diff --git a/src/http2.cc b/src/http2.cc index 38d74a3e..04dfb7ad 100644 --- a/src/http2.cc +++ b/src/http2.cc @@ -477,6 +477,11 @@ void dump_nv(FILE *out, const HeaderRefs &nva) { fflush(out); } +void erase_header(HeaderRef *hd) { + hd->name = StringRef{}; + hd->token = -1; +} + StringRef rewrite_location_uri(BlockAllocator &balloc, const StringRef &uri, const http_parser_url &u, const StringRef &match_host, diff --git a/src/http2.h b/src/http2.h index 5ebe11f1..9859930b 100644 --- a/src/http2.h +++ b/src/http2.h @@ -227,6 +227,9 @@ void dump_nv(FILE *out, const Headers &nva); void dump_nv(FILE *out, const HeaderRefs &nva); +// Ereases header in |hd|. +void erase_header(HeaderRef *hd); + // Rewrites redirection URI which usually appears in location header // field. The |uri| is the URI in the location header field. The |u| // stores the result of parsed |uri|. The |request_authority| is the diff --git a/src/shrpx_http_downstream_connection.cc b/src/shrpx_http_downstream_connection.cc index 2519d109..16435a84 100644 --- a/src/shrpx_http_downstream_connection.cc +++ b/src/shrpx_http_downstream_connection.cc @@ -720,15 +720,33 @@ int htp_hdrs_completecb(http_parser *htp) { // 204. Also server MUST NOT send Transfer-Encoding with a status // code 200 to a CONNECT request. Same holds true with // Content-Length. - if (resp.http_status == 204 || resp.http_status / 100 == 1 || - (resp.http_status == 200 && req.method == HTTP_CONNECT)) { + if (resp.http_status == 204) { + if (resp.fs.header(http2::HD_TRANSFER_ENCODING)) { + return -1; + } + // Some server send content-length: 0 for 204. Until they get + // fixed, we accept, but ignore it. + + // Calling parse_content_length() detects duplicated + // content-length header fields. + if (resp.fs.parse_content_length() != 0) { + return -1; + } + if (resp.fs.content_length != 0) { + return -1; + } + if (resp.fs.content_length == 0) { + auto cl = resp.fs.header(http2::HD_CONTENT_LENGTH); + assert(cl); + http2::erase_header(cl); + } + } else if (resp.http_status / 100 == 1 || + (resp.http_status == 200 && req.method == HTTP_CONNECT)) { if (resp.fs.header(http2::HD_CONTENT_LENGTH) || resp.fs.header(http2::HD_TRANSFER_ENCODING)) { return -1; } - } - - if (resp.fs.parse_content_length() != 0) { + } else if (resp.fs.parse_content_length() != 0) { downstream->set_response_state(Downstream::MSG_BAD_HEADER); return -1; } diff --git a/src/shrpx_mruby_module_response.cc b/src/shrpx_mruby_module_response.cc index 145def0e..7e263804 100644 --- a/src/shrpx_mruby_module_response.cc +++ b/src/shrpx_mruby_module_response.cc @@ -233,7 +233,7 @@ mrb_value response_return(mrb_state *mrb, mrb_value self) { (resp.http_status == 200 && req.method == HTTP_CONNECT)) { if (cl) { // Delete content-length here - cl->name = StringRef{}; + http2::erase_header(cl); } resp.fs.content_length = -1;