Fix PAD_HIGH and PAD_LOW are not counted in flow control

This commit is contained in:
Tatsuhiro Tsujikawa 2014-02-11 21:30:44 +09:00
parent cd3eae3dd2
commit 7822bbd7e8
4 changed files with 76 additions and 13 deletions

View File

@ -3204,7 +3204,8 @@ static int adjust_recv_window_size(int32_t *recv_window_size_ptr,
static int nghttp2_session_update_recv_stream_window_size static int nghttp2_session_update_recv_stream_window_size
(nghttp2_session *session, (nghttp2_session *session,
nghttp2_stream *stream, nghttp2_stream *stream,
int32_t delta_size) int32_t delta_size,
int send_window_update)
{ {
int rv; int rv;
rv = adjust_recv_window_size(&stream->recv_window_size, delta_size, rv = adjust_recv_window_size(&stream->recv_window_size, delta_size,
@ -3213,7 +3214,10 @@ static int nghttp2_session_update_recv_stream_window_size
return nghttp2_session_add_rst_stream(session, stream->stream_id, return nghttp2_session_add_rst_stream(session, stream->stream_id,
NGHTTP2_FLOW_CONTROL_ERROR); NGHTTP2_FLOW_CONTROL_ERROR);
} }
if(!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE)) { /* We don't have to send WINDOW_UPDATE if the data received is the
last chunk in the incoming stream. */
if(send_window_update &&
!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE)) {
/* We have to use local_settings here because it is the constraint /* We have to use local_settings here because it is the constraint
the remote endpoint should honor. */ the remote endpoint should honor. */
if(nghttp2_should_send_window_update(stream->local_window_size, if(nghttp2_should_send_window_update(stream->local_window_size,
@ -3478,6 +3482,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
int rv; int rv;
int busy = 0; int busy = 0;
nghttp2_frame_hd cont_hd; nghttp2_frame_hd cont_hd;
nghttp2_stream *stream;
for(;;) { for(;;) {
switch(iframe->state) { switch(iframe->state) {
@ -3657,6 +3662,23 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
} }
iframe->frame.data.padlen = rv; iframe->frame.data.padlen = rv;
iframe->state = NGHTTP2_IB_READ_DATA; iframe->state = NGHTTP2_IB_READ_DATA;
/* PAD_HIGH and PAD_LOW are subject to flow control */
rv = nghttp2_session_update_recv_connection_window_size
(session, iframe->buflen);
if(nghttp2_is_fatal(rv)) {
return rv;
}
stream = nghttp2_session_get_stream(session,
iframe->frame.hd.stream_id);
if(stream) {
rv = nghttp2_session_update_recv_stream_window_size
(session, stream, iframe->buflen,
iframe->payloadleft ||
(iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0);
if(nghttp2_is_fatal(rv)) {
return rv;
}
}
break; break;
case NGHTTP2_HEADERS: case NGHTTP2_HEADERS:
if(iframe->padlen == 0 && if(iframe->padlen == 0 &&
@ -4037,19 +4059,17 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
if(iframe->payloadleft ||
(iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
nghttp2_stream *stream;
stream = nghttp2_session_get_stream(session, stream = nghttp2_session_get_stream(session,
iframe->frame.hd.stream_id); iframe->frame.hd.stream_id);
if(stream) { if(stream) {
rv = nghttp2_session_update_recv_stream_window_size rv = nghttp2_session_update_recv_stream_window_size
(session, stream, readlen); (session, stream, readlen,
iframe->payloadleft ||
(iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
} }
}
data_readlen = inbound_frame_effective_readlen data_readlen = inbound_frame_effective_readlen
(iframe, iframe->payloadleft, readlen); (iframe, iframe->payloadleft, readlen);
DEBUGF(fprintf(stderr, "data_readlen=%zu\n", data_readlen)); DEBUGF(fprintf(stderr, "data_readlen=%zu\n", data_readlen));

View File

@ -181,6 +181,8 @@ int main(int argc, char* argv[])
test_nghttp2_session_flow_control) || test_nghttp2_session_flow_control) ||
!CU_add_test(pSuite, "session_flow_control_data_recv", !CU_add_test(pSuite, "session_flow_control_data_recv",
test_nghttp2_session_flow_control_data_recv) || test_nghttp2_session_flow_control_data_recv) ||
!CU_add_test(pSuite, "session_flow_control_data_with_padding_recv",
test_nghttp2_session_flow_control_data_with_padding_recv) ||
!CU_add_test(pSuite, "session_data_read_temporal_failure", !CU_add_test(pSuite, "session_data_read_temporal_failure",
test_nghttp2_session_data_read_temporal_failure) || test_nghttp2_session_data_read_temporal_failure) ||
!CU_add_test(pSuite, "session_on_stream_close", !CU_add_test(pSuite, "session_on_stream_close",

View File

@ -3542,6 +3542,46 @@ void test_nghttp2_session_flow_control_data_recv(void)
nghttp2_session_del(session); nghttp2_session_del(session);
} }
void test_nghttp2_session_flow_control_data_with_padding_recv(void)
{
nghttp2_session *session;
nghttp2_session_callbacks callbacks;
uint8_t data[1024];
nghttp2_frame_hd hd;
nghttp2_stream *stream;
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.send_callback = null_send_callback;
/* Initial window size to 64KiB - 1*/
nghttp2_session_client_new(&session, &callbacks, NULL);
stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
NGHTTP2_PRI_DEFAULT,
NGHTTP2_STREAM_OPENED, NULL);
/* Create DATA frame */
memset(data, 0, sizeof(data));
hd.length = 357;
hd.type = NGHTTP2_DATA;
hd.flags = NGHTTP2_FLAG_END_STREAM |
NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW;;
hd.stream_id = 1;
nghttp2_frame_pack_frame_hd(data, &hd);
/* Add 2 byte padding (PAD_LOW itself is padding) */
data[NGHTTP2_FRAME_HEAD_LENGTH] = 1;
data[NGHTTP2_FRAME_HEAD_LENGTH + 1] = 1;
CU_ASSERT(NGHTTP2_FRAME_HEAD_LENGTH + hd.length ==
nghttp2_session_mem_recv(session, data,
NGHTTP2_FRAME_HEAD_LENGTH + hd.length));
CU_ASSERT(hd.length == session->recv_window_size);
CU_ASSERT(hd.length == stream->recv_window_size);
nghttp2_session_del(session);
}
void test_nghttp2_session_data_read_temporal_failure(void) void test_nghttp2_session_data_read_temporal_failure(void)
{ {
nghttp2_session *session; nghttp2_session *session;

View File

@ -81,6 +81,7 @@ void test_nghttp2_session_stop_data_with_rst_stream(void);
void test_nghttp2_session_defer_data(void); void test_nghttp2_session_defer_data(void);
void test_nghttp2_session_flow_control(void); void test_nghttp2_session_flow_control(void);
void test_nghttp2_session_flow_control_data_recv(void); void test_nghttp2_session_flow_control_data_recv(void);
void test_nghttp2_session_flow_control_data_with_padding_recv(void);
void test_nghttp2_session_data_read_temporal_failure(void); void test_nghttp2_session_data_read_temporal_failure(void);
void test_nghttp2_session_on_stream_close(void); void test_nghttp2_session_on_stream_close(void);
void test_nghttp2_session_on_ctrl_not_send(void); void test_nghttp2_session_on_ctrl_not_send(void);