From 0155c9115a43a85f376e5564b8736d1de3c244a8 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 4 Oct 2015 10:36:20 +0900 Subject: [PATCH] nghttpx: Fix so that --padding option works again --- src/shrpx.cc | 8 ++-- src/shrpx_http2_upstream.cc | 54 +++++++++++++++++++++---- src/shrpx_http2_upstream.h | 4 +- src/shrpx_http_downstream_connection.cc | 3 +- 4 files changed, 55 insertions(+), 14 deletions(-) diff --git a/src/shrpx.cc b/src/shrpx.cc index 68c2c493..a9cdfdd9 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -972,10 +972,6 @@ void fill_default_config() { mod_config()->padding = 0; mod_config()->worker_frontend_connections = 0; - mod_config()->http2_upstream_callbacks = create_http2_upstream_callbacks(); - mod_config()->http2_downstream_callbacks = - create_http2_downstream_callbacks(); - nghttp2_option_new(&mod_config()->http2_option); nghttp2_option_set_no_auto_window_update(get_config()->http2_option, 1); nghttp2_option_set_no_recv_client_magic(get_config()->http2_option, 1); @@ -2503,6 +2499,10 @@ int main(int argc, char **argv) { reset_timer(); } + mod_config()->http2_upstream_callbacks = create_http2_upstream_callbacks(); + mod_config()->http2_downstream_callbacks = + create_http2_downstream_callbacks(); + if (event_loop() != 0) { return -1; } diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index bb256946..529f4b81 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -648,11 +648,16 @@ int on_frame_not_send_callback(nghttp2_session *session, } // namespace void Http2Upstream::set_pending_data_downstream(Downstream *downstream, - size_t n) { + size_t n, size_t padlen) { pending_data_downstream_ = downstream; data_pendinglen_ = n; + padding_pendinglen_ = padlen; } +namespace { +constexpr auto PADDING = std::array{}; +} // namespace + namespace { int send_data_callback(nghttp2_session *session, nghttp2_frame *frame, const uint8_t *framehd, size_t length, @@ -663,12 +668,26 @@ int send_data_callback(nghttp2_session *session, nghttp2_frame *frame, auto wb = upstream->get_response_buf(); - if (wb->wleft() < 9) { - return NGHTTP2_ERR_WOULDBLOCK; + size_t padlen; + + if (frame->data.padlen == 0) { + if (wb->wleft() < 9) { + return NGHTTP2_ERR_WOULDBLOCK; + } + + wb->write(framehd, 9); + padlen = 0; + } else { + if (wb->wleft() < 10) { + return NGHTTP2_ERR_WOULDBLOCK; + } + + wb->write(framehd, 9); + padlen = frame->data.padlen - 1; + *wb->last++ = padlen; } - wb->write(framehd, 9); - + size_t npadwrite = 0; auto nwrite = std::min(length, wb->wleft()); body->remove(wb->last, nwrite); wb->write(nwrite); @@ -677,8 +696,16 @@ int send_data_callback(nghttp2_session *session, nghttp2_frame *frame, // libnghttp2 that we wrote everything, so downstream could be // deleted. We handle this situation in // Http2Upstream::remove_downstream(). - upstream->set_pending_data_downstream(downstream, length - nwrite); + upstream->set_pending_data_downstream(downstream, length - nwrite, padlen); + } else if (padlen > 0) { + npadwrite = std::min(padlen, wb->wleft()); + wb->write(PADDING.data(), npadwrite); + + if (npadwrite < padlen) { + upstream->set_pending_data_downstream(nullptr, 0, padlen - npadwrite); + } } + if (wb->rleft() == 0) { downstream->disable_upstream_wtimer(); } else { @@ -695,7 +722,7 @@ int send_data_callback(nghttp2_session *session, nghttp2_frame *frame, downstream->add_response_sent_bodylen(length); } - return nwrite < length ? NGHTTP2_ERR_PAUSE : 0; + return (nwrite < length || npadwrite < padlen) ? NGHTTP2_ERR_PAUSE : 0; } } // namespace @@ -821,7 +848,8 @@ Http2Upstream::Http2Upstream(ClientHandler *handler) !get_config()->http2_proxy), pending_response_buf_(handler->get_worker()->get_mcpool()), pending_data_downstream_(nullptr), handler_(handler), session_(nullptr), - data_pending_(nullptr), data_pendinglen_(0), shutdown_handled_(false) { + data_pending_(nullptr), data_pendinglen_(0), padding_pendinglen_(0), + shutdown_handled_(false) { int rv; @@ -971,6 +999,16 @@ int Http2Upstream::on_write() { } } + if (padding_pendinglen_ > 0) { + auto nwrite = std::min(wb_.wleft(), padding_pendinglen_); + wb_.write(PADDING.data(), nwrite); + padding_pendinglen_ -= nwrite; + + if (padding_pendinglen_ > 0) { + return 0; + } + } + for (;;) { const uint8_t *data; auto datalen = nghttp2_session_mem_send(session_, &data); diff --git a/src/shrpx_http2_upstream.h b/src/shrpx_http2_upstream.h index 6dac8c9a..d49455cc 100644 --- a/src/shrpx_http2_upstream.h +++ b/src/shrpx_http2_upstream.h @@ -114,7 +114,8 @@ public: WriteBuffer *get_response_buf(); - void set_pending_data_downstream(Downstream *downstream, size_t n); + void set_pending_data_downstream(Downstream *downstream, size_t n, + size_t padlen); private: WriteBuffer wb_; @@ -144,6 +145,7 @@ private: // if pending_data_downstream_ is not nullptr, or // pending_response_buf_ holds data to write. size_t data_pendinglen_; + size_t padding_pendinglen_; bool flow_control_; bool shutdown_handled_; }; diff --git a/src/shrpx_http_downstream_connection.cc b/src/shrpx_http_downstream_connection.cc index 31c444f1..b14c78a0 100644 --- a/src/shrpx_http_downstream_connection.cc +++ b/src/shrpx_http_downstream_connection.cc @@ -455,7 +455,8 @@ void HttpDownstreamConnection::pause_read(IOCtrlReason reason) { int HttpDownstreamConnection::resume_read(IOCtrlReason reason, size_t consumed) { - if (downstream_->get_response_buf()->rleft() == 0) { + if (downstream_->get_response_buf()->rleft() <= + get_config()->downstream_request_buffer_size / 2) { ioctrl_.resume_read(reason); }