diff options
author | Eric Avdey <eiri@eiri.ca> | 2021-08-25 09:10:35 -0300 |
---|---|---|
committer | Eric Avdey <eiri@eiri.ca> | 2021-08-26 12:12:51 -0300 |
commit | 42627140100d4dfd9a8170ee4c6660e605806244 (patch) | |
tree | 9d4e62537e1c797b2f12f57b8cd079035652975a | |
parent | 1b8d4b73bc9ea67bfe0df5a41e24ea864f4c846d (diff) | |
download | couchdb-42627140100d4dfd9a8170ee4c6660e605806244.tar.gz |
Discard a payload on a delete attachment request
While including a payload within a DELETE request is not forbidden by RFC7231
its presence on a delete attachment request leaves a mochiweb acceptor
in a semi-opened state since mochiweb's using lazy load for the request bodies.
This makes a next immediate request to the same acceptor to hung
until previous request's receive timeout.
This PR adds a step to explicitly "drain" and discard an entity body on a
delete attachment request to prevent that.
-rw-r--r-- | src/chttpd/src/chttpd_db.erl | 3 | ||||
-rw-r--r-- | test/elixir/test/attachments_test.exs | 15 |
2 files changed, 18 insertions, 0 deletions
diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl index ffdab2a29..e803454f4 100644 --- a/src/chttpd/src/chttpd_db.erl +++ b/src/chttpd/src/chttpd_db.erl @@ -857,6 +857,9 @@ db_req(#httpd{path_parts=[_DbName, <<"_local">> | _Rest]}, _Db) -> db_req(#httpd{path_parts=[_, DocId]}=Req, Db) -> db_doc_req(Req, Db, DocId); +db_req(#httpd{method='DELETE', path_parts=[_, DocId | FileNameParts]}=Req, Db) -> + chttpd:body(Req), + db_attachment_req(Req, Db, DocId, FileNameParts); db_req(#httpd{path_parts=[_, DocId | FileNameParts]}=Req, Db) -> db_attachment_req(Req, Db, DocId, FileNameParts). diff --git a/test/elixir/test/attachments_test.exs b/test/elixir/test/attachments_test.exs index c89486a8e..2bf38de95 100644 --- a/test/elixir/test/attachments_test.exs +++ b/test/elixir/test/attachments_test.exs @@ -124,6 +124,21 @@ defmodule AttachmentsTest do end @tag :with_db + test "delete attachment request with a payload should not block following requests", context do + db_name = context[:db_name] + + resp = Couch.put("/#{db_name}/bin_doc", body: @bin_att_doc, query: %{w: 3}) + assert resp.status_code in [201, 202] + rev = resp.body["rev"] + + resp = Couch.delete("/#{db_name}/bin_doc/foo.txt", body: 'some payload', query: %{w: 3, rev: rev}, ibrowse: [{:max_sessions, 1}, {:max_pipeline_size, 1}]) + assert resp.status_code == 200 + + resp = Couch.get("/", timeout: 1000, ibrowse: [{:max_sessions, 1}, {:max_pipeline_size, 1}]) + assert resp.status_code == 200 + end + + @tag :with_db test "saves binary", context do db_name = context[:db_name] |