riak / src / raw_http_resource.erl

Diff from to


 %%     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.
     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)
     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) ->
                                    RD, Links),
-            {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}
+     case dict:find(?MD_USERMETA, MD) of
+         {ok, M} -> 
+            lists:foldl(fun({Hdr,Val},Acc) ->
+                            [Acc|[Hdr,": ",Val,"\n"]]
+                        end,
+                        [], M);
+         error -> []
+     end,
               lists:delete(BucketLink, string:tokens(Heads, ",")))
+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).
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.