This is an automated email from the ASF dual-hosted git repository. garren pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/couchdb.git
The following commit(s) were added to refs/heads/master by this push: new 52da19b Add Prefer: return=minimal support (#605) 52da19b is described below commit 52da19b9c0f75e0afbb3267b8766343c270fdcf7 Author: garren smith <garren.sm...@gmail.com> AuthorDate: Wed Aug 9 15:23:32 2017 +0200 Add Prefer: return=minimal support (#605) Use the Prefer: return=minimal header options from [rfc7240](https://tools.ietf.org/html/rfc7240) to reduce the number of headers in the response. The header is configurable via the config --- rel/overlay/etc/default.ini | 3 + src/chttpd/src/chttpd.erl | 5 +- src/chttpd/src/chttpd_prefer_header.erl | 54 +++++++++++++ src/chttpd/test/chttpd_prefer_header_test.erl | 109 ++++++++++++++++++++++++++ src/couch/src/couch_httpd.erl | 6 +- 5 files changed, 173 insertions(+), 4 deletions(-) diff --git a/rel/overlay/etc/default.ini b/rel/overlay/etc/default.ini index d840ef8..30b2efa 100644 --- a/rel/overlay/etc/default.ini +++ b/rel/overlay/etc/default.ini @@ -57,6 +57,9 @@ backlog = 512 docroot = {{fauxton_root}} socket_options = [{recbuf, 262144}, {sndbuf, 262144}, {nodelay, true}] require_valid_user = false +; List of headers that will be kept when the header Prefer: return=minimal is included in a request. +; If Server header is left out, Mochiweb will add its own one in. +prefer_minimal = Cache-Control, Content-Length, Content-Range, Content-Type, ETag, Server, Transfer-Encoding, Vary [database_compaction] ; larger buffer sizes can originate smaller files diff --git a/src/chttpd/src/chttpd.erl b/src/chttpd/src/chttpd.erl index cfefb78..178209b 100644 --- a/src/chttpd/src/chttpd.erl +++ b/src/chttpd/src/chttpd.erl @@ -1115,8 +1115,9 @@ basic_headers(Req, Headers0) -> Headers = Headers0 ++ server_header() ++ couch_httpd_auth:cookie_auth_header(Req, Headers0), - Headers1 = chttpd_xframe_options:header(Req, Headers), - chttpd_cors:headers(Req, Headers1). + Headers1 = chttpd_cors:headers(Req, Headers), + Headers2 = chttpd_xframe_options:header(Req, Headers1), + chttpd_prefer_header:maybe_return_minimal(Req, Headers2). handle_response(Req0, Code0, Headers0, Args0, Type) -> {ok, {Req1, Code1, Headers1, Args1}} = diff --git a/src/chttpd/src/chttpd_prefer_header.erl b/src/chttpd/src/chttpd_prefer_header.erl new file mode 100644 index 0000000..f550e80 --- /dev/null +++ b/src/chttpd/src/chttpd_prefer_header.erl @@ -0,0 +1,54 @@ +% 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(chttpd_prefer_header). + + +-export([ + maybe_return_minimal/2 +]). + + +-include_lib("couch/include/couch_db.hrl"). + + +maybe_return_minimal(#httpd{mochi_req = MochiReq}, Headers) -> + case get_prefer_header(MochiReq) of + "return=minimal" -> + filter_headers(Headers, get_header_list()); + _ -> + Headers + end. + + +get_prefer_header(Req) -> + case Req:get_header_value("Prefer") of + Value when is_list(Value) -> + string:to_lower(Value); + undefined -> + undefined + end. + + +filter_headers(Headers, IncludeList) -> + lists:filter(fun({HeaderName, _}) -> + lists:member(HeaderName, IncludeList) + end, Headers). + + +get_header_list() -> + SectionStr = config:get("chttpd", "prefer_minimal", ""), + split_list(SectionStr). + + +split_list(S) -> + re:split(S, "\\s*,\\s*", [trim, {return, list}]). diff --git a/src/chttpd/test/chttpd_prefer_header_test.erl b/src/chttpd/test/chttpd_prefer_header_test.erl new file mode 100644 index 0000000..a8a5b3d --- /dev/null +++ b/src/chttpd/test/chttpd_prefer_header_test.erl @@ -0,0 +1,109 @@ +% 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(chttpd_prefer_header_test). +-include_lib("couch/include/couch_db.hrl"). +-include_lib("eunit/include/eunit.hrl"). + + +mock_request(ExcludeHeader) -> + Headers = mochiweb_headers:make(ExcludeHeader), + MochiReq = mochiweb_request:new(nil, 'GET', "/", {1, 1}, Headers), + MochiReq:cleanup(), + #httpd{mochi_req = MochiReq}. + + +default_headers() -> + [ + {"Cache-Control","must-revalidate"}, + {"Content-Type","application/json"}, + {"Content-Length", "100"}, + {"ETag","\"12343\""}, + {"X-Couch-Request-ID","7bd1adab86"}, + {"X-CouchDB-Body-Time","0"}, + {"Vary", "Accept-Encoding"}, + {"Server","CouchDB/2.1.0-f1a1d7f1c (Erlang OTP/19)"} + ]. + + +minimal_options_headers() -> + [ + {"Cache-Control","must-revalidate"}, + {"Content-Type","application/json"}, + {"Content-Length", "100"}, + {"ETag","\"12343\""}, + {"Vary", "Accept-Encoding"}, + {"Server","CouchDB/2.1.0-f1a1d7f1c (Erlang OTP/19)"} + ]. + + +default_no_exclude_header_test() -> + Headers = chttpd_prefer_header:maybe_return_minimal( + mock_request([]), + default_headers() + ), + ?assertEqual(default_headers(), Headers). + + +unsupported_exclude_header_test() -> + Req = mock_request([{"prefer", "Wrong"}]), + Headers = chttpd_prefer_header:maybe_return_minimal(Req, default_headers()), + ?assertEqual(default_headers(), Headers). + + +empty_header_test() -> + Req = mock_request([{"prefer", ""}]), + Headers = chttpd_prefer_header:maybe_return_minimal(Req, default_headers()), + ?assertEqual(default_headers(), Headers). + +setup() -> + ok = meck:new(config), + ok = meck:expect(config, get, fun("chttpd", "prefer_minimal", _) -> + "Cache-Control, Content-Length, Content-Type, ETag, Server, Vary" + end), + ok. + + +teardown(_) -> + meck:unload(config). + + +exclude_headers_test_() -> + { + "Test Prefer headers", + { + foreach, fun setup/0, fun teardown/1, + [ + fun minimal_options/1, + fun minimal_options_check_header_case/1, + fun minimal_options_check_header_value_case/1 + ] + } + }. + + +minimal_options(_) -> + Req = mock_request([{"Prefer", "return=minimal"}]), + Headers = chttpd_prefer_header:maybe_return_minimal(Req, default_headers()), + ?_assertEqual(minimal_options_headers(), Headers). + + +minimal_options_check_header_case(_) -> + Req = mock_request([{"prefer", "return=minimal"}]), + Headers = chttpd_prefer_header:maybe_return_minimal(Req, default_headers()), + ?_assertEqual(minimal_options_headers(), Headers). + + +minimal_options_check_header_value_case(_) -> + Req = mock_request([{"prefer", "RETURN=MINIMAL"}]), + Headers = chttpd_prefer_header:maybe_return_minimal(Req, default_headers()), + ?_assertEqual(minimal_options_headers(), Headers). \ No newline at end of file diff --git a/src/couch/src/couch_httpd.erl b/src/couch/src/couch_httpd.erl index 95b7074..faaf080 100644 --- a/src/couch/src/couch_httpd.erl +++ b/src/couch/src/couch_httpd.erl @@ -755,7 +755,8 @@ send_response_no_cors(#httpd{mochi_req=MochiReq}=Req, Code, Headers, Body) -> Headers1 = http_1_0_keep_alive(MochiReq, Headers), Headers2 = basic_headers_no_cors(Req, Headers1), Headers3 = chttpd_xframe_options:header(Req, Headers2), - Resp = handle_response(Req, Code, Headers3, Body, respond), + Headers4 = chttpd_prefer_header:maybe_return_minimal(Req, Headers3), + Resp = handle_response(Req, Code, Headers4, Body, respond), log_response(Code, Body), {ok, Resp}. @@ -1134,7 +1135,8 @@ validate_bind_address(Address) -> add_headers(Req, Headers0) -> Headers = basic_headers(Req, Headers0), - http_1_0_keep_alive(Req, Headers). + Headers1 = http_1_0_keep_alive(Req, Headers), + chttpd_prefer_header:maybe_return_minimal(Req, Headers1). basic_headers(Req, Headers0) -> Headers1 = basic_headers_no_cors(Req, Headers0), -- To stop receiving notification emails like this one, please contact ['"commits@couchdb.apache.org" <commits@couchdb.apache.org>'].