From 123752a032ab9560f613420c4d88e4c1701cb36c Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Fri, 17 Jun 2016 22:32:15 +0900 Subject: [PATCH] nghttpx: Handle error from push_upload_data and end_upload_data We have to gracefully handle the case where response ends before request body is fully received. --- src/shrpx_downstream.cc | 3 ++- src/shrpx_http2_upstream.cc | 12 +++++++++--- src/shrpx_https_upstream.cc | 6 ++++++ src/shrpx_spdy_upstream.cc | 12 +++++++++--- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/shrpx_downstream.cc b/src/shrpx_downstream.cc index 8afd7fc4..8b57a33f 100644 --- a/src/shrpx_downstream.cc +++ b/src/shrpx_downstream.cc @@ -530,13 +530,14 @@ int Downstream::push_request_headers() { } int Downstream::push_upload_data_chunk(const uint8_t *data, size_t datalen) { + req_.recv_body_length += datalen; + // Assumes that request headers have already been pushed to output // buffer using push_request_headers(). if (!dconn_) { DLOG(INFO, this) << "dconn_ is NULL"; return -1; } - req_.recv_body_length += datalen; if (dconn_->push_upload_data_chunk(data, datalen) != 0) { return -1; } diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index 08872fb5..1c1686df 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -447,7 +447,9 @@ int on_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame, downstream->disable_upstream_rtimer(); if (downstream->end_upload_data() != 0) { - upstream->rst_stream(downstream, NGHTTP2_INTERNAL_ERROR); + if (downstream->get_response_state() != Downstream::MSG_COMPLETE) { + upstream->rst_stream(downstream, NGHTTP2_INTERNAL_ERROR); + } } downstream->set_request_state(Downstream::MSG_COMPLETE); @@ -472,7 +474,9 @@ int on_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame, downstream->disable_upstream_rtimer(); if (downstream->end_upload_data() != 0) { - upstream->rst_stream(downstream, NGHTTP2_INTERNAL_ERROR); + if (downstream->get_response_state() != Downstream::MSG_COMPLETE) { + upstream->rst_stream(downstream, NGHTTP2_INTERNAL_ERROR); + } } downstream->set_request_state(Downstream::MSG_COMPLETE); @@ -522,7 +526,9 @@ int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags, downstream->reset_upstream_rtimer(); if (downstream->push_upload_data_chunk(data, len) != 0) { - upstream->rst_stream(downstream, NGHTTP2_INTERNAL_ERROR); + if (downstream->get_response_state() != Downstream::MSG_COMPLETE) { + upstream->rst_stream(downstream, NGHTTP2_INTERNAL_ERROR); + } if (upstream->consume(stream_id, len) != 0) { return NGHTTP2_ERR_CALLBACK_FAILURE; diff --git a/src/shrpx_https_upstream.cc b/src/shrpx_https_upstream.cc index 1f5e4640..ae48f822 100644 --- a/src/shrpx_https_upstream.cc +++ b/src/shrpx_https_upstream.cc @@ -444,6 +444,12 @@ int htp_bodycb(http_parser *htp, const char *data, size_t len) { rv = downstream->push_upload_data_chunk( reinterpret_cast(data), len); if (rv != 0) { + // Ignore error if response has been completed. We will end up in + // htp_msg_completecb, and request will end gracefully. + if (downstream->get_response_state() == Downstream::MSG_COMPLETE) { + return 0; + } + return -1; } return 0; diff --git a/src/shrpx_spdy_upstream.cc b/src/shrpx_spdy_upstream.cc index 2d97100e..7991a77c 100644 --- a/src/shrpx_spdy_upstream.cc +++ b/src/shrpx_spdy_upstream.cc @@ -363,7 +363,9 @@ void SpdyUpstream::initiate_downstream(Downstream *downstream) { auto &req = downstream->request(); if (!req.http2_expect_body) { if (downstream->end_upload_data() != 0) { - rst_stream(downstream, SPDYLAY_INTERNAL_ERROR); + if (downstream->get_response_state() != Downstream::MSG_COMPLETE) { + rst_stream(downstream, SPDYLAY_INTERNAL_ERROR); + } } } } @@ -385,7 +387,9 @@ void on_data_chunk_recv_callback(spdylay_session *session, uint8_t flags, downstream->reset_upstream_rtimer(); if (downstream->push_upload_data_chunk(data, len) != 0) { - upstream->rst_stream(downstream, SPDYLAY_INTERNAL_ERROR); + if (downstream->get_response_state() != Downstream::MSG_COMPLETE) { + upstream->rst_stream(downstream, SPDYLAY_INTERNAL_ERROR); + } upstream->consume(stream_id, len); @@ -448,7 +452,9 @@ void on_data_recv_callback(spdylay_session *session, uint8_t flags, downstream->disable_upstream_rtimer(); if (downstream->end_upload_data() != 0) { - upstream->rst_stream(downstream, SPDYLAY_INTERNAL_ERROR); + if (downstream->get_response_state() != Downstream::MSG_COMPLETE) { + upstream->rst_stream(downstream, SPDYLAY_INTERNAL_ERROR); + } } downstream->set_request_state(Downstream::MSG_COMPLETE); }