diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index 2d7e2876..50e5a81e 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -372,6 +372,10 @@ int Http2Upstream::on_request_headers(Downstream *downstream, if (!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) { req.http2_expect_body = true; + } else if (req.fs.content_length == -1) { + // If END_STREAM flag is set to HEADERS frame, we are sure that + // content-length is 0. + req.fs.content_length = 0; } downstream->inspect_http2_request(); @@ -643,6 +647,9 @@ int on_frame_send_callback(nghttp2_session *session, const nghttp2_frame *frame, req.http_major = 2; req.http_minor = 0; + req.fs.content_length = 0; + req.http2_expect_body = false; + auto &promised_balloc = promised_downstream->get_block_allocator(); for (size_t i = 0; i < frame->push_promise.nvlen; ++i) { @@ -2072,6 +2079,9 @@ Http2Upstream::on_downstream_push_promise(Downstream *downstream, promised_req.http_major = 2; promised_req.http_minor = 0; + promised_req.fs.content_length = 0; + promised_req.http2_expect_body = false; + auto ptr = promised_downstream.get(); add_pending_downstream(std::move(promised_downstream)); downstream_queue_.mark_active(ptr); diff --git a/src/shrpx_http_downstream_connection.cc b/src/shrpx_http_downstream_connection.cc index 9a454a21..b743526b 100644 --- a/src/shrpx_http_downstream_connection.cc +++ b/src/shrpx_http_downstream_connection.cc @@ -525,7 +525,13 @@ int HttpDownstreamConnection::push_request_headers() { << downstream_->get_stream_id() << "\n" << nhdrs; } - signal_write(); + // Don't call signal_write() if we anticipate request body. We call + // signal_write() when we received request body chunk, and it + // enables us to send headers and data in one writev system call. + if (connect_method || + (!req.http2_expect_body && req.fs.content_length == 0)) { + signal_write(); + } return 0; } diff --git a/src/shrpx_https_upstream.cc b/src/shrpx_https_upstream.cc index 0be62b62..863f8d62 100644 --- a/src/shrpx_https_upstream.cc +++ b/src/shrpx_https_upstream.cc @@ -312,10 +312,19 @@ int htp_hdrs_completecb(http_parser *htp) { ULOG(INFO, upstream) << "HTTP request headers\n" << ss.str(); } - // set content-length if no transfer-encoding is given. If - // transfer-encoding is given, leave req.fs.content_length to -1. - if (!req.fs.header(http2::HD_TRANSFER_ENCODING)) { - req.fs.content_length = htp->content_length; + // set content-length if method is not CONNECT, and no + // transfer-encoding is given. If transfer-encoding is given, leave + // req.fs.content_length to -1. + if (method != HTTP_CONNECT && !req.fs.header(http2::HD_TRANSFER_ENCODING)) { + // http-parser returns (uint64_t)-1 if there is no content-length + // header field. If we don't have both transfer-encoding, and + // content-length header field, we assume that there is no request + // body. + if (htp->content_length == std::numeric_limits::max()) { + req.fs.content_length = 0; + } else { + req.fs.content_length = htp->content_length; + } } auto host = req.fs.header(http2::HD_HOST); diff --git a/src/shrpx_spdy_upstream.cc b/src/shrpx_spdy_upstream.cc index 8077d426..fa0ffc94 100644 --- a/src/shrpx_spdy_upstream.cc +++ b/src/shrpx_spdy_upstream.cc @@ -305,6 +305,8 @@ void on_ctrl_recv_callback(spdylay_session *session, spdylay_frame_type type, if (!(frame->syn_stream.hd.flags & SPDYLAY_CTRL_FLAG_FIN)) { req.http2_expect_body = true; + } else if (req.fs.content_length == -1) { + req.fs.content_length = 0; } downstream->inspect_http2_request();