From bf9cd2b1c36909b41fc3db40f4a2c351e2e43182 Mon Sep 17 00:00:00 2001 From: Garren Smith Date: Thu, 7 Apr 2016 16:06:31 +0200 Subject: [PATCH] Create md5 etag for _local docs This makes a unique ETAG for _local docs, so that they are cached correctly, and fetched again when the document changes. fixes COUCHDB-2978 --- src/couch_httpd.erl | 15 ++++++++++++--- test/couch_etag_tests.erl | 30 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 test/couch_etag_tests.erl diff --git a/src/couch_httpd.erl b/src/couch_httpd.erl index 7370594e..c4f5a9c2 100644 --- a/src/couch_httpd.erl +++ b/src/couch_httpd.erl @@ -21,7 +21,7 @@ -export([make_fun_spec_strs/1]). -export([make_arity_1_fun/1, make_arity_2_fun/1, make_arity_3_fun/1]). -export([parse_form/1,json_body/1,json_body_obj/1,body/1]). --export([doc_etag/1, make_etag/1, etag_match/2, etag_respond/3, etag_maybe/2]). +-export([doc_etag/1, doc_etag/3, make_etag/1, etag_match/2, etag_respond/3, etag_maybe/2]). -export([primary_header_value/2,partition/1,serve_file/3,serve_file/4, server_header/0]). -export([start_chunked_response/3,send_chunk/2,log_request/2]). -export([start_response_length/4, start_response/3, send/2]). @@ -594,8 +594,17 @@ maybe_decompress(Httpd, Body) -> throw({bad_ctype, [Else, " is not a supported content encoding."]}) end. -doc_etag(#doc{revs={Start, [DiskRev|_]}}) -> - "\"" ++ ?b2l(couch_doc:rev_to_str({Start, DiskRev})) ++ "\"". +doc_etag(#doc{id=Id, body=Body, revs={Start, [DiskRev|_]}}) -> + doc_etag(Id, Body, {Start, DiskRev}). + +doc_etag(<<"_local/", _/binary>>, Body, {Start, DiskRev}) -> + make_etag({Start, DiskRev, Body}); +doc_etag(_Id, _Body, {Start, DiskRev}) -> + rev_etag({Start, DiskRev}). + +rev_etag({Start, DiskRev}) -> + Rev = couch_doc:rev_to_str({Start, DiskRev}), + <<$", Rev/binary, $">>. make_etag(Term) -> <> = couch_crypto:hash(md5, term_to_binary(Term)), diff --git a/test/couch_etag_tests.erl b/test/couch_etag_tests.erl new file mode 100644 index 00000000..9d15e483 --- /dev/null +++ b/test/couch_etag_tests.erl @@ -0,0 +1,30 @@ +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "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. + +-module(couch_etag_tests). + +-include_lib("eunit/include/eunit.hrl"). + +local_with_empty_body_test() -> + Etag = couch_httpd:doc_etag(<<"_local/local-and-empty">>, {[]}, {0, <<"1">>}), + ?assertEqual(Etag, <<"\"5ZVXQYO7VLEOU0TL9VXDNP5PV\"">>). + + +local_with_body_test() -> + DocBody = {[{<<"hello">>,<<"world">>},{<<"relax">>,true}]}, + Etag = couch_httpd:doc_etag(<<"_local/local-with-body">>, DocBody, {0, <<"1">>}), + ?assertEqual(Etag, <<"\"CEFXP6WH8OKYIWO1GLGBHKCCA\"">>). + +normal_doc_uses_rev_test() -> + DocBody = {[{<<"hello">>,<<"world">>},{<<"relax">>,true}]}, + Etag = couch_httpd:doc_etag(<<"nomal-doc">>, DocBody, {1, <<"efda11e34e88ebe31a2f83e84a0435b6">>}), + ?assertEqual(Etag, <<"\"1-efda11e34e88ebe31a2f83e84a0435b6\"">>).