You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by va...@apache.org on 2020/10/12 17:06:39 UTC

[couchdb] 01/01: Properly combine base and extra headers when making replicator requests

This is an automated email from the ASF dual-hosted git repository.

vatamane pushed a commit to branch fix-replicator-header-merging
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 68f16c2ce9f07d9f94937200ad18896419220efb
Author: Nick Vatamaniuc <va...@apache.org>
AuthorDate: Fri Oct 9 18:10:44 2020 -0400

    Properly combine base and extra headers when making replicator requests
    
    Previously we subtly relied on one set of headers being sorted, then sorted the
    other set of headers, and ran `lists:ukeymerge/3`. That function, however,
    needs both arguments to be sorted in order for it to work as expected. If one
    argument wasn't sorted we could get duplicate headers easily, which is what was
    observed in testing.
    
    A better fix than just sorting both sets of keys, is to use an actual header
    processing library to combine them so we can account for case insensitivity as
    well.
---
 .../src/couch_replicator_httpc.erl                 | 28 ++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/src/couch_replicator/src/couch_replicator_httpc.erl b/src/couch_replicator/src/couch_replicator_httpc.erl
index 4dce319..466bc57 100644
--- a/src/couch_replicator/src/couch_replicator_httpc.erl
+++ b/src/couch_replicator/src/couch_replicator_httpc.erl
@@ -97,8 +97,8 @@ send_req(HttpDb, Params1, Callback) ->
 
 send_ibrowse_req(#httpdb{headers = BaseHeaders} = HttpDb0, Params) ->
     Method = get_value(method, Params, get),
-    UserHeaders = lists:keysort(1, get_value(headers, Params, [])),
-    Headers1 = lists:ukeymerge(1, UserHeaders, BaseHeaders),
+    UserHeaders = get_value(headers, Params, []),
+    Headers1 = merge_headers(BaseHeaders, UserHeaders),
     {Headers2, HttpDb} = couch_replicator_auth:update_headers(HttpDb0, Headers1),
     Url = full_url(HttpDb, Params),
     Body = get_value(body, Params, []),
@@ -493,3 +493,27 @@ backoff_before_request(Worker, HttpDb, Params) ->
         Sleep when Sleep == 0 ->
             ok
     end.
+
+
+merge_headers(Headers1, Headers2) when is_list(Headers1), is_list(Headers2) ->
+    Empty = mochiweb_headers:empty(),
+    Merged = mochiweb_headers:enter_from_list(Headers1 ++ Headers2, Empty),
+    mochiweb_headers:to_list(Merged).
+
+
+-ifdef(TEST).
+
+-include_lib("couch/include/couch_eunit.hrl").
+
+
+merge_headers_test() ->
+    ?assertEqual([], merge_headers([], [])),
+    ?assertEqual([{"a", "x"}], merge_headers([], [{"a", "x"}])),
+    ?assertEqual([{"a", "x"}], merge_headers([{"a", "x"}], [])),
+    ?assertEqual([{"a", "y"}], merge_headers([{"A", "x"}], [{"a", "y"}])),
+    ?assertEqual([{"a", "y"}, {"B", "x"}], merge_headers([{"B", "x"}],
+        [{"a", "y"}])),
+    ?assertEqual([{"a", "y"}], merge_headers([{"A", "z"}, {"a", "y"}], [])),
+    ?assertEqual([{"a", "y"}], merge_headers([], [{"A", "z"}, {"a", "y"}])).
+
+-endif.