summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Newson <rnewson@apache.org>2019-03-06 14:58:23 +0000
committerRobert Newson <rnewson@apache.org>2019-03-06 15:08:08 +0000
commitc151a321da0df18fb563b9cd09ba64e56e540e38 (patch)
tree2d77128c497a6079ddec33b6cc4d7c50f665ebbf
parentaee2fd9859c14aed1cb28f458a846064c58cf782 (diff)
downloadcouchdb-c151a321da0df18fb563b9cd09ba64e56e540e38.tar.gz
Ignore weak ETag part
Some load balancer configurations (HAproxy with compression enabled is the motivating example) will add W/ to our response ETags if they modify the response before sending it to the client. as per rfc7232 section 3.2; "A recipient MUST use the weak comparison function when comparing entity-tags for If-None-Match (Section 2.3.2), since weak entity-tags can be used for cache validation even if there have been changes to the representation data." This change improves our ETag checking toward RFC compliance.
-rw-r--r--src/chttpd/src/chttpd.erl8
-rw-r--r--test/javascript/tests/etags_head.js4
2 files changed, 11 insertions, 1 deletions
diff --git a/src/chttpd/src/chttpd.erl b/src/chttpd/src/chttpd.erl
index ac371a2e5..1e1d638be 100644
--- a/src/chttpd/src/chttpd.erl
+++ b/src/chttpd/src/chttpd.erl
@@ -693,10 +693,16 @@ etag_match(Req, CurrentEtag) when is_binary(CurrentEtag) ->
etag_match(Req, binary_to_list(CurrentEtag));
etag_match(Req, CurrentEtag) ->
- EtagsToMatch = string:tokens(
+ EtagsToMatch0 = string:tokens(
chttpd:header_value(Req, "If-None-Match", ""), ", "),
+ EtagsToMatch = lists:map(fun strip_weak_prefix/1, EtagsToMatch0),
lists:member(CurrentEtag, EtagsToMatch).
+strip_weak_prefix([$W, $/ | Etag]) ->
+ Etag;
+strip_weak_prefix(Etag) ->
+ Etag.
+
etag_respond(Req, CurrentEtag, RespFun) ->
case etag_match(Req, CurrentEtag) of
true ->
diff --git a/test/javascript/tests/etags_head.js b/test/javascript/tests/etags_head.js
index ab5476921..9faca4af6 100644
--- a/test/javascript/tests/etags_head.js
+++ b/test/javascript/tests/etags_head.js
@@ -63,6 +63,10 @@ couchTests.etags_head = function(debug) {
headers: {"if-none-match": etag}
});
T(xhr.status == 304);
+ xhr = CouchDB.request("GET", "/" + db_name + "/1", {
+ headers: {"if-none-match": "W/" + etag}
+ });
+ T(xhr.status == 304);
// fail to delete a doc
xhr = CouchDB.request("DELETE", "/" + db_name + "/1", {