Anonymous avatar Anonymous committed bfd8553 Merge

merge from hg tip (r445)

Comments (0)

Files changed (7)

 Martin Scholl
 Jayson Baird
 Kirill A. Korinskiy
-
-
+Kevin Smith
+Jonathan Lee

client_lib/jiak.php

     function delete($bucket, $key, $dw=2) {
         $resp = $this->_do_req("DELETE", $this->JKP .
                     urlencode($bucket) . "/" . urlencode($key) .
-                    "&dw=" . $dw);
+                    "?dw=" . $dw);
         $http_code = $resp['http_code'];
         if ($http_code == 404) return false;
         else if ($http_code == 204) return true;

src/jiak_resource.erl

 %% @doc Determine whether an object write violates the write mask of
 %%      the bucket.
 object_forbidden(ReqData, Context=#ctx{jiak_context=JC,module=Mod}) ->
-    {Diffs, NewContext0} = diff_objects(ReqData, Context),
-    NewContext = NewContext0#ctx{jiak_context=JC:set_diff(Diffs)},
-    Permitted = check_write_mask(Mod, Diffs),    
-    case Permitted of
-        false ->
-            {true,
-             wrq:append_to_response_body(
-               io_lib:format(
-                 "Write disallowed, some of ~p not writable.~n", 
-                 [[K || {K,_,_} <- element(1, Diffs)]]),
-               ReqData),
-             NewContext};
-        true ->
-            {false, ReqData, NewContext}
+    case diff_objects(ReqData, Context) of
+        {ok, {Diffs, NewContext0}} ->
+            NewContext = NewContext0#ctx{jiak_context=JC:set_diff(Diffs)},
+            Permitted = check_write_mask(Mod, Diffs),    
+            case Permitted of
+                false ->
+                    {true,
+                     wrq:append_to_response_body(
+                       io_lib:format(
+                         "Write disallowed, some of ~p not writable.~n", 
+                         [[K || {K,_,_} <- element(1, Diffs)]]),
+                       ReqData),
+                     NewContext};
+                true ->
+                    {false, ReqData, NewContext}
+            end;
+        {error, {timeout, NewContext}} ->
+            {{halt, 503},
+             wrq:set_resp_body("Timeout during object_forbidden read.",
+                               ReqData),
+             NewContext}
     end.
 
 %% @spec encodings_provided(webmachine:wrq(), context()) ->
 diff_objects(_ReqData, Context=#ctx{incoming=NewObj, key=container}) ->
     %% same as notfound
     Diffs = jiak_object:diff(undefined, NewObj),
-    {Diffs, Context#ctx{diffs=Diffs}};
+    {ok, {Diffs, Context#ctx{diffs=Diffs}}};
 diff_objects(ReqData, Context=#ctx{incoming=NewObj0, module=Mod}) ->
     case retrieve_object(ReqData, Context) of
 	{notfound, NewContext} ->
 	    Diffs = jiak_object:diff(undefined, NewObj0),
-	    {Diffs, NewContext#ctx{diffs=Diffs}};
+	    {ok, {Diffs, NewContext#ctx{diffs=Diffs}}};
 	{ok, {JiakObject, NewContext}} ->
 	    NewObj = copy_unreadable_props(Mod,JiakObject, NewObj0),
 	    Diffs = jiak_object:diff(JiakObject, NewObj),
-	    {Diffs, NewContext#ctx{diffs=Diffs, storedobj=NewObj, 
-				   incoming=NewObj}}
+	    {ok, {Diffs, NewContext#ctx{diffs=Diffs, storedobj=NewObj, 
+                                        incoming=NewObj}}};
+        Error -> Error
     end.
 
 %% @spec apply_read_mask(jiak_object()) -> jiak_object()
 -define(MD_VTAG,     <<"X-Riak-VTag">>).
 -define(MD_LINKS,    <<"Links">>).
 -define(MD_LASTMOD,  <<"X-Riak-Last-Modified">>).
+-define(MD_USERMETA, <<"X-Riak-Meta">>).
 
 %% Names of HTTP header fields
--define(HEAD_CTYPE,    "Content-Type").
--define(HEAD_VCLOCK,   "X-Riak-Vclock").
--define(HEAD_LINK,     "Link").
--define(HEAD_ENCODING, "Content-Encoding").
--define(HEAD_CLIENT,   "X-Riak-ClientId").
+-define(HEAD_CTYPE,           "Content-Type").
+-define(HEAD_VCLOCK,          "X-Riak-Vclock").
+-define(HEAD_LINK,            "Link").
+-define(HEAD_ENCODING,        "Content-Encoding").
+-define(HEAD_CLIENT,          "X-Riak-ClientId").
+-define(HEAD_USERMETA_PREFIX, "X-Riak-Meta-").
 
 %% Names of JSON fields in bucket properties
 -define(JSON_PROPS,   <<"props">>).

src/raw_http_resource.erl

 %%     Last-Modified: The last-modified time of the object
 %%     Encoding: The value of the incoming Encoding header from
 %%       the request that stored the data.
+%%     X-Riak-Meta-: Any headers prefixed by X-Riak-Meta- supplied
+%%       on PUT are returned verbatim
 %%   Specifying the query param "r=R", where R is an integer will
 %%   cause Riak to use R as the r-value for the read request. A
 %%   default r-value of 2 will be used if none is specified.
 %%   Include a Link header to set the links of the object.
 %%   Include an Encoding header if you would like an Encoding header
 %%   to be included in the response to subsequent GET requests.
+%%   Include custom metadata using headers prefixed with X-Riak-Meta-.
+%%   They will be returned verbatim on subsequent GET requests.
 %%   Specifying the query param "w=W", where W is an integer will
 %%   cause Riak to use W as the w-value for the write request. A
 %%   default w-value of 2 will be used if none is specified.
            end,
     VclockDoc = riak_object:set_vclock(Doc0, decode_vclock_header(RD)),
     {CType, Charset} = extract_content_type(RD),
+    UserMeta = extract_user_meta(RD),
     CTypeMD = dict:store(?MD_CTYPE, CType, dict:new()),
     CharsetMD = if Charset /= undefined ->
                         dict:store(?MD_CHARSET, Charset, CTypeMD);
                 E -> dict:store(?MD_ENCODING, E, CharsetMD)
             end,
     LinkMD = dict:store(?MD_LINKS, L, EncMD),
-    MDDoc = riak_object:update_metadata(VclockDoc, LinkMD),
+    UserMetaMD = dict:store(?MD_USERMETA, UserMeta, LinkMD),
+    MDDoc = riak_object:update_metadata(VclockDoc, UserMetaMD),
     Doc = riak_object:update_value(MDDoc, wrq:req_body(RD)),
     ok = C:put(Doc, Ctx#ctx.w, Ctx#ctx.dw),
     {true, RD, Ctx#ctx{doc={ok, Doc}}}.
     Params = [ list_to_tuple(string:tokens(P, "=")) || P <- RawParams],
     {CType, proplists:get_value("charset", Params)}.
 
+%% @spec extract_user_meta(reqdata()) -> proplist()
+%% @doc Extract headers prefixed by X-Riak-Meta- in the client's PUT request
+%%      to be returned by subsequent GET requests.
+extract_user_meta(RD) ->
+    lists:filter(fun({K,_V}) ->
+                    lists:prefix(
+                        ?HEAD_USERMETA_PREFIX,
+                        any_to_list(K))
+                end,
+                mochiweb_headers:to_list(wrq:req_headers(RD))).
+
 %% @spec multiple_choices(reqdata(), context()) ->
 %%          {boolean(), reqdata(), context()}
 %% @doc Determine whether a document has siblings.  If the user has
 
 %% @spec produce_doc_body(reqdata(), context()) -> {binary(), reqdata(), context()}
 %% @doc Extract the value of the document, and place it in the response
-%%      body of the request.  This function also adds the Link header
-%%      to the response.  One link will point to the bucket, with the
+%%      body of the request.  This function also adds the Link and X-Riak-Meta-
+%%      headers to the response.  One link will point to the bucket, with the
 %%      property "rel=container".  The rest of the links will be constructed
 %%      from the links of the document.
 produce_doc_body(RD, Ctx) ->
                                    end,
                                    RD, Links),
                        Ctx),
-            {Doc, encode_vclock_header(LinkRD, Ctx), Ctx};
+            UserMetaRD = case dict:find(?MD_USERMETA, MD) of
+                        {ok, UserMeta} -> 
+                            lists:foldl(fun({K,V},Acc) ->
+                                            wrq:merge_resp_headers([{K,V}],Acc)
+                                        end,
+                                        LinkRD, UserMeta);
+                        error -> LinkRD
+                    end,
+            {Doc, encode_vclock_header(UserMetaRD, Ctx), Ctx};
         multiple_choices ->
             {<<"">>, RD, Ctx}
     end.
              Rfc1123
      end,
      "\n",
+     case dict:find(?MD_USERMETA, MD) of
+         {ok, M} -> 
+            lists:foldl(fun({Hdr,Val},Acc) ->
+                            [Acc|[Hdr,": ",Val,"\n"]]
+                        end,
+                        [], M);
+         error -> []
+     end,
      "\n",V].
     
 
               end,
               lists:delete(BucketLink, string:tokens(Heads, ",")))
     end.
+
+any_to_list(V) when is_list(V) ->
+    V;
+any_to_list(V) when is_atom(V) ->
+    atom_to_list(V);
+any_to_list(V) when is_binary(V) ->
+    binary_to_list(V).

src/riak_fs_backend.erl

 %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 %% KIND, either express or implied.  See the License for the
 %% specific language governing permissions and limitations
-%% under the License.    
+%% under the License.
 
 % @doc riak_fs_backend is a simple filesystem storage system.
 
 %% @spec put(state(), BKey :: riak_object:bkey(), Val :: binary()) ->
 %%         ok | {error, Reason :: term()}
 %% @doc Store Val under Bkey
-put(State,BKey,Val) ->       
+put(State,BKey,Val) ->
     File = location(State,BKey),
     case filelib:ensure_dir(File) of
         ok -> atomic_write(State, File, Val);

src/riak_vnode.erl

                StateData=#state{mod=Mod,modstate=ModState}) ->
     % send each obj (BKey) in difflist to targetnode
     % return a state with waiting_diffobjs populated
-    [send_diff_obj(TargetNode,BKey,Mod,ModState) || BKey <- DiffList],
-    StateData#state{waiting_diffobjs=DiffList}.
+    Sent = [K || K <- [send_diff_obj(TargetNode,BKey,Mod,ModState) 
+                       || BKey <- DiffList], K /= nop],
+    StateData#state{waiting_diffobjs=Sent}.
 send_diff_obj(TargetNode,BKey,Mod,ModState) ->
-    {ok,BinObj} = Mod:get(ModState,BKey),
-    gen_fsm:send_event(TargetNode, {diffobj,{BKey,BinObj,self()}}).
+    case Mod:get(ModState,BKey) of
+        {ok,BinObj} ->
+            gen_fsm:send_event(TargetNode, {diffobj,{BKey,BinObj,self()}}),
+            BKey;
+        _ ->
+            nop
+    end.
 
 %%%%%%%%%% in merk_waiting state, we have sent a merkle tree to the
 %%%%%%%%%% home vnode, and are waiting for a list of different objects
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.