Fix DATA is not consumed if nghttp2_http_on_data_chunk failed

This commit fixes the bug that DATA is not consumed if
nghttp2_http_on_data_chunk is failed.  It also simplify the handling
of missing stream in NGHTTP2_IB_READ_DATA state.
This commit is contained in:
Tatsuhiro Tsujikawa 2015-07-08 22:27:04 +09:00
parent 693fba3b64
commit c70cfe64c4
1 changed files with 51 additions and 46 deletions

View File

@ -5739,6 +5739,14 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
break;
case NGHTTP2_IB_READ_DATA:
stream = nghttp2_session_get_stream(session, iframe->frame.hd.stream_id);
if (!stream) {
busy = 1;
iframe->state = NGHTTP2_IB_IGN_DATA;
break;
}
DEBUGF(fprintf(stderr, "recv: [IB_READ_DATA]\n"));
readlen = inbound_frame_payload_readlen(iframe, in, last);
@ -5756,68 +5764,65 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return rv;
}
stream =
nghttp2_session_get_stream(session, iframe->frame.hd.stream_id);
if (stream) {
rv = session_update_recv_stream_window_size(
session, stream, readlen,
iframe->payloadleft ||
(iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0);
rv = session_update_recv_stream_window_size(
session, stream, readlen,
iframe->payloadleft ||
(iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0);
if (nghttp2_is_fatal(rv)) {
return rv;
}
data_readlen = inbound_frame_effective_readlen(
iframe, iframe->payloadleft, readlen);
padlen = readlen - data_readlen;
if (padlen > 0) {
/* Padding is considered as "consumed" immediately */
rv = nghttp2_session_consume(session, iframe->frame.hd.stream_id,
padlen);
if (nghttp2_is_fatal(rv)) {
return rv;
}
}
data_readlen = inbound_frame_effective_readlen(
iframe, iframe->payloadleft, readlen);
DEBUGF(fprintf(stderr, "recv: data_readlen=%zd\n", data_readlen));
padlen = readlen - data_readlen;
if (data_readlen > 0) {
if (session_enforce_http_messaging(session)) {
if (nghttp2_http_on_data_chunk(stream, data_readlen) != 0) {
if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
/* Consume all data for connection immediately here */
rv = session_update_connection_consumed_size(session,
data_readlen);
if (padlen > 0) {
/* Padding is considered as "consumed" immediately */
rv = nghttp2_session_consume(session, iframe->frame.hd.stream_id,
padlen);
if (nghttp2_is_fatal(rv)) {
return rv;
}
}
DEBUGF(fprintf(stderr, "recv: data_readlen=%zd\n", data_readlen));
if (data_readlen > 0) {
if (session_enforce_http_messaging(session)) {
if (nghttp2_http_on_data_chunk(stream, data_readlen) != 0) {
rv = nghttp2_session_add_rst_stream(session,
iframe->frame.hd.stream_id,
NGHTTP2_PROTOCOL_ERROR);
if (nghttp2_is_fatal(rv)) {
return rv;
}
busy = 1;
iframe->state = NGHTTP2_IB_IGN_DATA;
break;
}
}
if (session->callbacks.on_data_chunk_recv_callback) {
rv = session->callbacks.on_data_chunk_recv_callback(
session, iframe->frame.hd.flags, iframe->frame.hd.stream_id,
in - readlen, data_readlen, session->user_data);
if (rv == NGHTTP2_ERR_PAUSE) {
return in - first;
}
rv = nghttp2_session_add_rst_stream(
session, iframe->frame.hd.stream_id, NGHTTP2_PROTOCOL_ERROR);
if (nghttp2_is_fatal(rv)) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
return rv;
}
busy = 1;
iframe->state = NGHTTP2_IB_IGN_DATA;
break;
}
}
} else if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
/* stream was closed or does not exist. Consume all data
for connection immediately here */
rv = session_update_connection_consumed_size(session, readlen);
if (session->callbacks.on_data_chunk_recv_callback) {
rv = session->callbacks.on_data_chunk_recv_callback(
session, iframe->frame.hd.flags, iframe->frame.hd.stream_id,
in - readlen, data_readlen, session->user_data);
if (rv == NGHTTP2_ERR_PAUSE) {
return in - first;
}
if (nghttp2_is_fatal(rv)) {
return rv;
if (nghttp2_is_fatal(rv)) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
}
}
}