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.
This commit is contained in:
Tatsuhiro Tsujikawa 2016-06-17 22:32:15 +09:00
parent ec5e438a7c
commit 123752a032
4 changed files with 26 additions and 7 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -444,6 +444,12 @@ int htp_bodycb(http_parser *htp, const char *data, size_t len) {
rv = downstream->push_upload_data_chunk(
reinterpret_cast<const uint8_t *>(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;

View File

@ -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);
}