Wrap small inbound buffer by nghttp_buf

This commit is contained in:
Tatsuhiro Tsujikawa 2014-03-22 18:27:38 +09:00
parent 3c631b5625
commit 01586f473d
4 changed files with 274 additions and 74 deletions

View File

@ -52,6 +52,7 @@ typedef struct {
#define nghttp2_buf_len(BUF) ((BUF)->last - (BUF)->pos) #define nghttp2_buf_len(BUF) ((BUF)->last - (BUF)->pos)
#define nghttp2_buf_avail(BUF) ((BUF)->end - (BUF)->last) #define nghttp2_buf_avail(BUF) ((BUF)->end - (BUF)->last)
#define nghttp2_buf_mark_avail(BUF) ((BUF)->mark - (BUF)->last)
#define nghttp2_buf_cap(BUF) ((BUF)->end - (BUF)->begin) #define nghttp2_buf_cap(BUF) ((BUF)->end - (BUF)->begin)
#define nghttp2_buf_pos_offset(BUF) ((BUF)->pos - (BUF)->begin) #define nghttp2_buf_pos_offset(BUF) ((BUF)->pos - (BUF)->begin)

View File

@ -184,12 +184,19 @@ static void nghttp2_inbound_frame_reset(nghttp2_session *session)
break; break;
} }
memset(&iframe->frame, 0, sizeof(nghttp2_frame)); memset(&iframe->frame, 0, sizeof(nghttp2_frame));
iframe->state = NGHTTP2_IB_READ_HEAD; iframe->state = NGHTTP2_IB_READ_HEAD;
iframe->left = NGHTTP2_FRAME_HDLEN;
nghttp2_buf_wrap_init(&iframe->sbuf, iframe->raw_sbuf,
sizeof(iframe->raw_sbuf));
iframe->sbuf.mark += NGHTTP2_FRAME_HDLEN;
nghttp2_buf_free(&iframe->lbuf);
nghttp2_buf_wrap_init(&iframe->lbuf, NULL, 0);
iframe->niv = 0; iframe->niv = 0;
iframe->payloadleft = 0; iframe->payloadleft = 0;
iframe->padlen = 0; iframe->padlen = 0;
iframe->buflen = 0;
} }
static void init_settings(uint32_t *settings) static void init_settings(uint32_t *settings)
@ -2528,7 +2535,9 @@ static int session_process_headers_frame(nghttp2_session *session)
nghttp2_stream *stream; nghttp2_stream *stream;
rv = nghttp2_frame_unpack_headers_payload(&frame->headers, rv = nghttp2_frame_unpack_headers_payload(&frame->headers,
iframe->buf, iframe->buflen); iframe->sbuf.pos,
nghttp2_buf_len(&iframe->sbuf));
if(rv != 0) { if(rv != 0) {
return nghttp2_session_terminate_session(session, NGHTTP2_PROTOCOL_ERROR); return nghttp2_session_terminate_session(session, NGHTTP2_PROTOCOL_ERROR);
} }
@ -2595,7 +2604,9 @@ static int session_process_priority_frame(nghttp2_session *session)
nghttp2_frame *frame = &iframe->frame; nghttp2_frame *frame = &iframe->frame;
nghttp2_frame_unpack_priority_payload(&frame->priority, nghttp2_frame_unpack_priority_payload(&frame->priority,
iframe->buf, iframe->buflen); iframe->sbuf.pos,
nghttp2_buf_len(&iframe->sbuf));
return nghttp2_session_on_priority_received(session, frame); return nghttp2_session_on_priority_received(session, frame);
} }
@ -2634,7 +2645,9 @@ static int session_process_rst_stream_frame(nghttp2_session *session)
nghttp2_frame *frame = &iframe->frame; nghttp2_frame *frame = &iframe->frame;
nghttp2_frame_unpack_rst_stream_payload(&frame->rst_stream, nghttp2_frame_unpack_rst_stream_payload(&frame->rst_stream,
iframe->buf, iframe->buflen); iframe->sbuf.pos,
nghttp2_buf_len(&iframe->sbuf));
return nghttp2_session_on_rst_stream_received(session, frame); return nghttp2_session_on_rst_stream_received(session, frame);
} }
@ -3025,11 +3038,14 @@ static int session_process_push_promise_frame(nghttp2_session *session)
nghttp2_inbound_frame *iframe = &session->iframe; nghttp2_inbound_frame *iframe = &session->iframe;
nghttp2_frame *frame = &iframe->frame; nghttp2_frame *frame = &iframe->frame;
rv = nghttp2_frame_unpack_push_promise_payload(&frame->push_promise, rv = nghttp2_frame_unpack_push_promise_payload
iframe->buf, iframe->buflen); (&frame->push_promise,
iframe->sbuf.pos, nghttp2_buf_len(&iframe->sbuf));
if(rv != 0) { if(rv != 0) {
return nghttp2_session_terminate_session(session, NGHTTP2_PROTOCOL_ERROR); return nghttp2_session_terminate_session(session, NGHTTP2_PROTOCOL_ERROR);
} }
return nghttp2_session_on_push_promise_received(session, frame); return nghttp2_session_on_push_promise_received(session, frame);
} }
@ -3058,7 +3074,9 @@ static int session_process_ping_frame(nghttp2_session *session)
nghttp2_frame *frame = &iframe->frame; nghttp2_frame *frame = &iframe->frame;
nghttp2_frame_unpack_ping_payload(&frame->ping, nghttp2_frame_unpack_ping_payload(&frame->ping,
iframe->buf, iframe->buflen); iframe->sbuf.pos,
nghttp2_buf_len(&iframe->sbuf));
return nghttp2_session_on_ping_received(session, frame); return nghttp2_session_on_ping_received(session, frame);
} }
@ -3080,7 +3098,9 @@ static int session_process_goaway_frame(nghttp2_session *session)
nghttp2_frame *frame = &iframe->frame; nghttp2_frame *frame = &iframe->frame;
nghttp2_frame_unpack_goaway_payload(&frame->goaway, nghttp2_frame_unpack_goaway_payload(&frame->goaway,
iframe->buf, iframe->buflen); iframe->sbuf.pos,
nghttp2_buf_len(&iframe->sbuf));
return nghttp2_session_on_goaway_received(session, frame); return nghttp2_session_on_goaway_received(session, frame);
} }
@ -3197,7 +3217,9 @@ static int session_process_window_update_frame(nghttp2_session *session)
nghttp2_frame *frame = &iframe->frame; nghttp2_frame *frame = &iframe->frame;
nghttp2_frame_unpack_window_update_payload(&frame->window_update, nghttp2_frame_unpack_window_update_payload(&frame->window_update,
iframe->buf, iframe->buflen); iframe->sbuf.pos,
nghttp2_buf_len(&iframe->sbuf));
return nghttp2_session_on_window_update_received(session, frame); return nghttp2_session_on_window_update_received(session, frame);
} }
@ -3438,28 +3460,29 @@ static size_t inbound_frame_payload_readlen(nghttp2_inbound_frame *iframe,
} }
/* /*
* Resets iframe->left to |left| and iframe->buflen to 0 for the next * Resets iframe->sbuf and advance its mark pointer by |left| bytes.
* short buffering.
*/ */
static void inbound_frame_reset_left(nghttp2_inbound_frame *iframe, static void inbound_frame_set_mark(nghttp2_inbound_frame *iframe, size_t left)
size_t left)
{ {
iframe->left = left; nghttp2_buf_reset(&iframe->sbuf);
iframe->buflen = 0; iframe->sbuf.mark += left;
} }
static size_t inbound_frame_buf_read(nghttp2_inbound_frame *iframe, static size_t inbound_frame_buf_read(nghttp2_inbound_frame *iframe,
const uint8_t *in, const uint8_t *last) const uint8_t *in, const uint8_t *last)
{ {
size_t readlen = nghttp2_min((size_t)(last - in), iframe->left); size_t readlen;
memcpy(iframe->buf + iframe->buflen, in, readlen);
iframe->buflen += readlen; readlen = nghttp2_min(last - in,
iframe->left -= readlen; nghttp2_buf_mark_avail(&iframe->sbuf));
iframe->sbuf.last = nghttp2_cpymem(iframe->sbuf.last, in, readlen);
return readlen; return readlen;
} }
/* /*
* Unpacks SETTINGS entry in |iframe->buf|. * Unpacks SETTINGS entry in iframe->sbuf.
* *
* This function returns 0 if it succeeds, or -1. * This function returns 0 if it succeeds, or -1.
*/ */
@ -3468,7 +3491,8 @@ static int inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe)
nghttp2_settings_entry iv; nghttp2_settings_entry iv;
size_t i; size_t i;
nghttp2_frame_unpack_settings_entry(&iv, iframe->buf); nghttp2_frame_unpack_settings_entry(&iv, iframe->sbuf.pos);
switch(iv.settings_id) { switch(iv.settings_id) {
case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE:
case NGHTTP2_SETTINGS_ENABLE_PUSH: case NGHTTP2_SETTINGS_ENABLE_PUSH:
@ -3478,23 +3502,25 @@ static int inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe)
default: default:
return -1; return -1;
} }
for(i = 0; i < iframe->niv; ++i) { for(i = 0; i < iframe->niv; ++i) {
if(iframe->iv[i].settings_id == iv.settings_id) { if(iframe->iv[i].settings_id == iv.settings_id) {
iframe->iv[i] = iv; iframe->iv[i] = iv;
break; break;
} }
} }
if(i == iframe->niv) { if(i == iframe->niv) {
iframe->iv[iframe->niv++] = iv; iframe->iv[iframe->niv++] = iv;
} }
return 0; return 0;
} }
/* /*
* Checks PAD_HIGH and PAD_LOW flags and set iframe->left and * Checks PAD_HIGH and PAD_LOW flags and set iframe->sbuf to read them
* iframe->buflen accordingly. If padding is set, this function * accordingly. If padding is set, this function returns 1. If no
* returns 1. If no padding is set, this function returns 0. On error, * padding is set, this function returns 0. On error, returns -1.
* returns -1.
*/ */
static int inbound_frame_handle_pad(nghttp2_inbound_frame *iframe, static int inbound_frame_handle_pad(nghttp2_inbound_frame *iframe,
nghttp2_frame_hd *hd) nghttp2_frame_hd *hd)
@ -3506,14 +3532,14 @@ static int inbound_frame_handle_pad(nghttp2_inbound_frame *iframe,
if(hd->length < 2) { if(hd->length < 2) {
return -1; return -1;
} }
inbound_frame_reset_left(iframe, 2); inbound_frame_set_mark(iframe, 2);
return 1; return 1;
} }
if(hd->flags & NGHTTP2_FLAG_PAD_LOW) { if(hd->flags & NGHTTP2_FLAG_PAD_LOW) {
if(hd->length < 1) { if(hd->length < 1) {
return -1; return -1;
} }
inbound_frame_reset_left(iframe, 1); inbound_frame_set_mark(iframe, 1);
return 1; return 1;
} }
DEBUGF(fprintf(stderr, "recv: no padding in payload\n")); DEBUGF(fprintf(stderr, "recv: no padding in payload\n"));
@ -3527,19 +3553,26 @@ static int inbound_frame_handle_pad(nghttp2_inbound_frame *iframe,
static ssize_t inbound_frame_compute_pad(nghttp2_inbound_frame *iframe) static ssize_t inbound_frame_compute_pad(nghttp2_inbound_frame *iframe)
{ {
size_t padlen; size_t padlen;
padlen = iframe->buf[0];
padlen = iframe->sbuf.pos[0];
if(iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_HIGH) { if(iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_HIGH) {
padlen <<= 8; padlen <<= 8;
padlen |= iframe->buf[1]; padlen |= iframe->sbuf.pos[1];
++padlen; ++padlen;
} }
++padlen; ++padlen;
DEBUGF(fprintf(stderr, "recv: padlen=%zu\n", padlen)); DEBUGF(fprintf(stderr, "recv: padlen=%zu\n", padlen));
/* We cannot use iframe->frame.hd.length because of CONTINUATION */ /* We cannot use iframe->frame.hd.length because of CONTINUATION */
if(padlen - (padlen > 255) - 1 > iframe->payloadleft) { if(padlen - (padlen > 255) - 1 > iframe->payloadleft) {
return -1; return -1;
} }
iframe->padlen = padlen; iframe->padlen = padlen;
return padlen; return padlen;
} }
@ -3587,13 +3620,15 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
switch(iframe->state) { switch(iframe->state) {
case NGHTTP2_IB_READ_HEAD: case NGHTTP2_IB_READ_HEAD:
DEBUGF(fprintf(stderr, "recv: [IB_READ_HEAD]\n")); DEBUGF(fprintf(stderr, "recv: [IB_READ_HEAD]\n"));
readlen = inbound_frame_buf_read(iframe, in, last); readlen = inbound_frame_buf_read(iframe, in, last);
in += readlen; in += readlen;
if(iframe->left) {
if(nghttp2_buf_mark_avail(&iframe->sbuf)) {
return in - first; return in - first;
} }
nghttp2_frame_unpack_frame_hd(&iframe->frame.hd, iframe->buf); nghttp2_frame_unpack_frame_hd(&iframe->frame.hd, iframe->sbuf.pos);
iframe->payloadleft = iframe->frame.hd.length; iframe->payloadleft = iframe->frame.hd.length;
DEBUGF(fprintf(stderr, DEBUGF(fprintf(stderr,
@ -3607,6 +3642,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
switch(iframe->frame.hd.type) { switch(iframe->frame.hd.type) {
case NGHTTP2_DATA: { case NGHTTP2_DATA: {
DEBUGF(fprintf(stderr, "recv: DATA\n")); DEBUGF(fprintf(stderr, "recv: DATA\n"));
iframe->frame.hd.flags &= (NGHTTP2_FLAG_END_STREAM | iframe->frame.hd.flags &= (NGHTTP2_FLAG_END_STREAM |
NGHTTP2_FLAG_END_SEGMENT | NGHTTP2_FLAG_END_SEGMENT |
NGHTTP2_FLAG_PAD_LOW | NGHTTP2_FLAG_PAD_LOW |
@ -3614,6 +3650,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
/* Check stream is open. If it is not open or closing, /* Check stream is open. If it is not open or closing,
ignore payload. */ ignore payload. */
busy = 1; busy = 1;
rv = nghttp2_session_on_data_received_fail_fast(session); rv = nghttp2_session_on_data_received_fail_fast(session);
if(rv == NGHTTP2_ERR_IGN_PAYLOAD) { if(rv == NGHTTP2_ERR_IGN_PAYLOAD) {
DEBUGF(fprintf(stderr, "recv: DATA not allowed stream_id=%d\n", DEBUGF(fprintf(stderr, "recv: DATA not allowed stream_id=%d\n",
@ -3621,38 +3658,47 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
iframe->state = NGHTTP2_IB_IGN_DATA; iframe->state = NGHTTP2_IB_IGN_DATA;
break; break;
} }
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd);
if(rv < 0) { if(rv < 0) {
iframe->state = NGHTTP2_IB_IGN_DATA; iframe->state = NGHTTP2_IB_IGN_DATA;
rv = nghttp2_session_terminate_session(session, rv = nghttp2_session_terminate_session(session,
NGHTTP2_PROTOCOL_ERROR); NGHTTP2_PROTOCOL_ERROR);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
break; break;
} }
if(rv == 1) { if(rv == 1) {
iframe->state = NGHTTP2_IB_READ_PAD_DATA; iframe->state = NGHTTP2_IB_READ_PAD_DATA;
break; break;
} }
iframe->state = NGHTTP2_IB_READ_DATA; iframe->state = NGHTTP2_IB_READ_DATA;
break; break;
} }
case NGHTTP2_HEADERS: case NGHTTP2_HEADERS:
DEBUGF(fprintf(stderr, "recv: HEADERS\n"));
iframe->frame.hd.flags &= (NGHTTP2_FLAG_END_STREAM | iframe->frame.hd.flags &= (NGHTTP2_FLAG_END_STREAM |
NGHTTP2_FLAG_END_SEGMENT | NGHTTP2_FLAG_END_SEGMENT |
NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_END_HEADERS |
NGHTTP2_FLAG_PRIORITY | NGHTTP2_FLAG_PRIORITY |
NGHTTP2_FLAG_PAD_LOW | NGHTTP2_FLAG_PAD_LOW |
NGHTTP2_FLAG_PAD_HIGH); NGHTTP2_FLAG_PAD_HIGH);
DEBUGF(fprintf(stderr, "recv: HEADERS\n"));
rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd);
if(rv < 0) { if(rv < 0) {
busy = 1; busy = 1;
iframe->state = NGHTTP2_IB_IGN_PAYLOAD; iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
rv = nghttp2_session_terminate_session(session, rv = nghttp2_session_terminate_session(session,
NGHTTP2_PROTOCOL_ERROR); NGHTTP2_PROTOCOL_ERROR);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
@ -3660,30 +3706,40 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
} }
break; break;
} }
if(rv == 1) { if(rv == 1) {
iframe->state = NGHTTP2_IB_READ_NBYTE; iframe->state = NGHTTP2_IB_READ_NBYTE;
break; break;
} }
if(iframe->frame.hd.flags & NGHTTP2_FLAG_PRIORITY) { if(iframe->frame.hd.flags & NGHTTP2_FLAG_PRIORITY) {
if(iframe->payloadleft < 4) { if(iframe->payloadleft < 4) {
busy = 1; busy = 1;
iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR;
break; break;
} }
iframe->state = NGHTTP2_IB_READ_NBYTE; iframe->state = NGHTTP2_IB_READ_NBYTE;
inbound_frame_reset_left(iframe, 4);
inbound_frame_set_mark(iframe, 4);
break; break;
} }
rv = session_process_headers_frame(session); rv = session_process_headers_frame(session);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
busy = 1; busy = 1;
if(rv == NGHTTP2_ERR_IGN_HEADER_BLOCK) { if(rv == NGHTTP2_ERR_IGN_HEADER_BLOCK) {
iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK;
break; break;
} }
iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK;
break; break;
case NGHTTP2_PRIORITY: case NGHTTP2_PRIORITY:
case NGHTTP2_RST_STREAM: case NGHTTP2_RST_STREAM:
@ -3701,18 +3757,25 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
break; break;
} }
#endif /* DEBUGBUILD */ #endif /* DEBUGBUILD */
iframe->frame.hd.flags = NGHTTP2_FLAG_NONE; iframe->frame.hd.flags = NGHTTP2_FLAG_NONE;
if(iframe->payloadleft != 4) { if(iframe->payloadleft != 4) {
busy = 1; busy = 1;
iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR;
break; break;
} }
iframe->state = NGHTTP2_IB_READ_NBYTE; iframe->state = NGHTTP2_IB_READ_NBYTE;
inbound_frame_reset_left(iframe, 4);
inbound_frame_set_mark(iframe, 4);
break; break;
case NGHTTP2_SETTINGS: case NGHTTP2_SETTINGS:
DEBUGF(fprintf(stderr, "recv: SETTINGS\n")); DEBUGF(fprintf(stderr, "recv: SETTINGS\n"));
iframe->frame.hd.flags &= NGHTTP2_FLAG_ACK; iframe->frame.hd.flags &= NGHTTP2_FLAG_ACK;
if((iframe->frame.hd.length % NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) || if((iframe->frame.hd.length % NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) ||
((iframe->frame.hd.flags & NGHTTP2_FLAG_ACK) && ((iframe->frame.hd.flags & NGHTTP2_FLAG_ACK) &&
iframe->payloadleft > 0)) { iframe->payloadleft > 0)) {
@ -3720,20 +3783,26 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR;
break; break;
} }
iframe->state = NGHTTP2_IB_READ_SETTINGS; iframe->state = NGHTTP2_IB_READ_SETTINGS;
if(iframe->payloadleft) { if(iframe->payloadleft) {
inbound_frame_reset_left(iframe, inbound_frame_set_mark(iframe, NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH);
NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH);
break; break;
} }
busy = 1; busy = 1;
inbound_frame_reset_left(iframe, 0);
inbound_frame_set_mark(iframe, 0);
break; break;
case NGHTTP2_PUSH_PROMISE: case NGHTTP2_PUSH_PROMISE:
DEBUGF(fprintf(stderr, "recv: PUSH_PROMISE\n")); DEBUGF(fprintf(stderr, "recv: PUSH_PROMISE\n"));
iframe->frame.hd.flags &= (NGHTTP2_FLAG_END_HEADERS | iframe->frame.hd.flags &= (NGHTTP2_FLAG_END_HEADERS |
NGHTTP2_FLAG_PAD_LOW | NGHTTP2_FLAG_PAD_LOW |
NGHTTP2_FLAG_PAD_HIGH); NGHTTP2_FLAG_PAD_HIGH);
rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd);
if(rv < 0) { if(rv < 0) {
busy = 1; busy = 1;
@ -3745,42 +3814,56 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
} }
break; break;
} }
if(rv == 1) { if(rv == 1) {
iframe->state = NGHTTP2_IB_READ_NBYTE; iframe->state = NGHTTP2_IB_READ_NBYTE;
break; break;
} }
if(iframe->payloadleft < 4) { if(iframe->payloadleft < 4) {
busy = 1; busy = 1;
iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR;
break; break;
} }
iframe->state = NGHTTP2_IB_READ_NBYTE; iframe->state = NGHTTP2_IB_READ_NBYTE;
inbound_frame_reset_left(iframe, 4);
inbound_frame_set_mark(iframe, 4);
break; break;
case NGHTTP2_PING: case NGHTTP2_PING:
DEBUGF(fprintf(stderr, "recv: PING\n")); DEBUGF(fprintf(stderr, "recv: PING\n"));
iframe->frame.hd.flags &= NGHTTP2_FLAG_ACK; iframe->frame.hd.flags &= NGHTTP2_FLAG_ACK;
if(iframe->payloadleft != 8) { if(iframe->payloadleft != 8) {
busy = 1; busy = 1;
iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR;
break; break;
} }
iframe->state = NGHTTP2_IB_READ_NBYTE; iframe->state = NGHTTP2_IB_READ_NBYTE;
inbound_frame_reset_left(iframe, 8); inbound_frame_set_mark(iframe, 8);
break; break;
case NGHTTP2_GOAWAY: case NGHTTP2_GOAWAY:
DEBUGF(fprintf(stderr, "recv: GOAWAY\n")); DEBUGF(fprintf(stderr, "recv: GOAWAY\n"));
iframe->frame.hd.flags = NGHTTP2_FLAG_NONE; iframe->frame.hd.flags = NGHTTP2_FLAG_NONE;
if(iframe->payloadleft < 8) { if(iframe->payloadleft < 8) {
busy = 1; busy = 1;
iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR;
break; break;
} }
iframe->state = NGHTTP2_IB_READ_NBYTE; iframe->state = NGHTTP2_IB_READ_NBYTE;
inbound_frame_reset_left(iframe, 8); inbound_frame_set_mark(iframe, 8);
break; break;
default: default:
DEBUGF(fprintf(stderr, "recv: unknown frame\n")); DEBUGF(fprintf(stderr, "recv: unknown frame\n"));
/* Receiving unknown frame type and CONTINUATION in this state /* Receiving unknown frame type and CONTINUATION in this state
are subject to connection error of type PROTOCOL_ERROR */ are subject to connection error of type PROTOCOL_ERROR */
rv = nghttp2_session_terminate_session(session, rv = nghttp2_session_terminate_session(session,
@ -3788,21 +3871,29 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
busy = 1; busy = 1;
iframe->state = NGHTTP2_IB_IGN_PAYLOAD; iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
break; break;
} }
break; break;
case NGHTTP2_IB_READ_NBYTE: case NGHTTP2_IB_READ_NBYTE:
DEBUGF(fprintf(stderr, "recv: [IB_READ_NBYTE]\n")); DEBUGF(fprintf(stderr, "recv: [IB_READ_NBYTE]\n"));
readlen = inbound_frame_buf_read(iframe, in, last); readlen = inbound_frame_buf_read(iframe, in, last);
in += readlen; in += readlen;
iframe->payloadleft -= readlen; iframe->payloadleft -= readlen;
DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu, left=%zu\n",
readlen, iframe->payloadleft, iframe->left)); DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu, left=%zd\n",
if(iframe->left) { readlen, iframe->payloadleft,
nghttp2_buf_mark_avail(&iframe->sbuf)));
if(nghttp2_buf_mark_avail(&iframe->sbuf)) {
return in - first; return in - first;
} }
switch(iframe->frame.hd.type) { switch(iframe->frame.hd.type) {
case NGHTTP2_HEADERS: case NGHTTP2_HEADERS:
if(iframe->padlen == 0 && if(iframe->padlen == 0 &&
@ -3826,34 +3917,43 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
break; break;
} }
iframe->state = NGHTTP2_IB_READ_NBYTE; iframe->state = NGHTTP2_IB_READ_NBYTE;
inbound_frame_reset_left(iframe, 4); inbound_frame_set_mark(iframe, 4);
break; break;
} }
} }
rv = session_process_headers_frame(session); rv = session_process_headers_frame(session);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
busy = 1; busy = 1;
if(rv == NGHTTP2_ERR_IGN_HEADER_BLOCK) { if(rv == NGHTTP2_ERR_IGN_HEADER_BLOCK) {
iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK;
break; break;
} }
iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK;
break; break;
case NGHTTP2_PRIORITY: case NGHTTP2_PRIORITY:
rv = session_process_priority_frame(session); rv = session_process_priority_frame(session);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
nghttp2_inbound_frame_reset(session); nghttp2_inbound_frame_reset(session);
break; break;
case NGHTTP2_RST_STREAM: case NGHTTP2_RST_STREAM:
rv = session_process_rst_stream_frame(session); rv = session_process_rst_stream_frame(session);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
nghttp2_inbound_frame_reset(session); nghttp2_inbound_frame_reset(session);
break; break;
case NGHTTP2_PUSH_PROMISE: case NGHTTP2_PUSH_PROMISE:
if(iframe->padlen == 0 && if(iframe->padlen == 0 &&
@ -3869,48 +3969,65 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
iframe->state = NGHTTP2_IB_IGN_PAYLOAD; iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
break; break;
} }
iframe->frame.push_promise.padlen = rv; iframe->frame.push_promise.padlen = rv;
if(iframe->payloadleft < 4) { if(iframe->payloadleft < 4) {
busy = 1; busy = 1;
iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR;
break; break;
} }
iframe->state = NGHTTP2_IB_READ_NBYTE; iframe->state = NGHTTP2_IB_READ_NBYTE;
inbound_frame_reset_left(iframe, 4);
inbound_frame_set_mark(iframe, 4);
break; break;
} }
rv = session_process_push_promise_frame(session); rv = session_process_push_promise_frame(session);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
busy = 1; busy = 1;
if(rv == NGHTTP2_ERR_IGN_HEADER_BLOCK) { if(rv == NGHTTP2_ERR_IGN_HEADER_BLOCK) {
iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK;
break; break;
} }
iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK;
break; break;
case NGHTTP2_PING: case NGHTTP2_PING:
rv = session_process_ping_frame(session); rv = session_process_ping_frame(session);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
nghttp2_inbound_frame_reset(session); nghttp2_inbound_frame_reset(session);
break; break;
case NGHTTP2_GOAWAY: case NGHTTP2_GOAWAY:
busy = 1; busy = 1;
iframe->state = NGHTTP2_IB_READ_GOAWAY_DEBUG; iframe->state = NGHTTP2_IB_READ_GOAWAY_DEBUG;
break; break;
case NGHTTP2_WINDOW_UPDATE: case NGHTTP2_WINDOW_UPDATE:
rv = session_process_window_update_frame(session); rv = session_process_window_update_frame(session);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
nghttp2_inbound_frame_reset(session); nghttp2_inbound_frame_reset(session);
break; break;
default: default:
/* This is unknown frame */ /* This is unknown frame */
nghttp2_inbound_frame_reset(session); nghttp2_inbound_frame_reset(session);
break; break;
} }
break; break;
@ -3924,7 +4041,9 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
fprintf(stderr, "recv: [IB_IGN_HEADER_BLOCK]\n"); fprintf(stderr, "recv: [IB_IGN_HEADER_BLOCK]\n");
} }
#endif /* DEBUGBUILD */ #endif /* DEBUGBUILD */
readlen = inbound_frame_payload_readlen(iframe, in, last); readlen = inbound_frame_payload_readlen(iframe, in, last);
DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu\n", DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu\n",
readlen, iframe->payloadleft - readlen)); readlen, iframe->payloadleft - readlen));
@ -4001,8 +4120,11 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
~(NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW); ~(NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW);
if((iframe->frame.hd.flags & NGHTTP2_FLAG_END_HEADERS) == 0) { if((iframe->frame.hd.flags & NGHTTP2_FLAG_END_HEADERS) == 0) {
inbound_frame_reset_left(iframe, NGHTTP2_FRAME_HDLEN);
inbound_frame_set_mark(iframe, NGHTTP2_FRAME_HDLEN);
iframe->padlen = 0; iframe->padlen = 0;
if(iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) { if(iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) {
iframe->state = NGHTTP2_IB_EXPECT_CONTINUATION; iframe->state = NGHTTP2_IB_EXPECT_CONTINUATION;
} else { } else {
@ -4021,77 +4143,105 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
} }
case NGHTTP2_IB_IGN_PAYLOAD: case NGHTTP2_IB_IGN_PAYLOAD:
DEBUGF(fprintf(stderr, "recv: [IB_IGN_PAYLOAD]\n")); DEBUGF(fprintf(stderr, "recv: [IB_IGN_PAYLOAD]\n"));
readlen = inbound_frame_payload_readlen(iframe, in, last); readlen = inbound_frame_payload_readlen(iframe, in, last);
iframe->payloadleft -= readlen; iframe->payloadleft -= readlen;
in += readlen; in += readlen;
DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu\n", DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu\n",
readlen, iframe->payloadleft)); readlen, iframe->payloadleft));
if(iframe->payloadleft) { if(iframe->payloadleft) {
break; break;
} }
nghttp2_inbound_frame_reset(session); nghttp2_inbound_frame_reset(session);
break; break;
case NGHTTP2_IB_FRAME_SIZE_ERROR: case NGHTTP2_IB_FRAME_SIZE_ERROR:
DEBUGF(fprintf(stderr, "recv: [IB_FRAME_SIZE_ERROR]\n")); DEBUGF(fprintf(stderr, "recv: [IB_FRAME_SIZE_ERROR]\n"));
rv = session_handle_frame_size_error(session, &iframe->frame); rv = session_handle_frame_size_error(session, &iframe->frame);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
busy = 1; busy = 1;
iframe->state = NGHTTP2_IB_IGN_PAYLOAD; iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
break; break;
case NGHTTP2_IB_READ_SETTINGS: case NGHTTP2_IB_READ_SETTINGS:
DEBUGF(fprintf(stderr, "recv: [IB_READ_SETTINGS]\n")); DEBUGF(fprintf(stderr, "recv: [IB_READ_SETTINGS]\n"));
readlen = inbound_frame_buf_read(iframe, in, last); readlen = inbound_frame_buf_read(iframe, in, last);
iframe->payloadleft -= readlen; iframe->payloadleft -= readlen;
in += readlen; in += readlen;
DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu\n", DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu\n",
readlen, iframe->payloadleft)); readlen, iframe->payloadleft));
if(iframe->left) {
if(nghttp2_buf_mark_avail(&iframe->sbuf)) {
break; break;
} }
if(readlen > 0) { if(readlen > 0) {
rv = inbound_frame_set_settings_entry(iframe); rv = inbound_frame_set_settings_entry(iframe);
if(rv != 0) { if(rv != 0) {
DEBUGF(fprintf(stderr, "recv: bad settings received\n")); DEBUGF(fprintf(stderr, "recv: bad settings received\n"));
rv = nghttp2_session_terminate_session(session, rv = nghttp2_session_terminate_session(session,
NGHTTP2_PROTOCOL_ERROR); NGHTTP2_PROTOCOL_ERROR);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
if(iframe->payloadleft == 0) { if(iframe->payloadleft == 0) {
nghttp2_inbound_frame_reset(session); nghttp2_inbound_frame_reset(session);
break; break;
} }
iframe->state = NGHTTP2_IB_IGN_PAYLOAD; iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
break; break;
} }
} }
if(iframe->payloadleft) { if(iframe->payloadleft) {
inbound_frame_reset_left(iframe, NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH); inbound_frame_set_mark(iframe, NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH);
break; break;
} }
rv = session_process_settings_frame(session); rv = session_process_settings_frame(session);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
nghttp2_inbound_frame_reset(session); nghttp2_inbound_frame_reset(session);
break; break;
case NGHTTP2_IB_READ_GOAWAY_DEBUG: case NGHTTP2_IB_READ_GOAWAY_DEBUG:
DEBUGF(fprintf(stderr, "recv: [IB_READ_GOAWAY_DEBUG]\n")); DEBUGF(fprintf(stderr, "recv: [IB_READ_GOAWAY_DEBUG]\n"));
readlen = inbound_frame_payload_readlen(iframe, in, last); readlen = inbound_frame_payload_readlen(iframe, in, last);
iframe->payloadleft -= readlen; iframe->payloadleft -= readlen;
in += readlen; in += readlen;
DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu\n", DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu\n",
readlen, iframe->payloadleft)); readlen, iframe->payloadleft));
if(iframe->payloadleft) { if(iframe->payloadleft) {
break; break;
} }
rv = session_process_goaway_frame(session); rv = session_process_goaway_frame(session);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
nghttp2_inbound_frame_reset(session); nghttp2_inbound_frame_reset(session);
break; break;
case NGHTTP2_IB_EXPECT_CONTINUATION: case NGHTTP2_IB_EXPECT_CONTINUATION:
case NGHTTP2_IB_IGN_CONTINUATION: case NGHTTP2_IB_IGN_CONTINUATION:
@ -4102,12 +4252,15 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
fprintf(stderr, "recv: [IB_IGN_CONTINUATION]\n"); fprintf(stderr, "recv: [IB_IGN_CONTINUATION]\n");
} }
#endif /* DEBUGBUILD */ #endif /* DEBUGBUILD */
readlen = inbound_frame_buf_read(iframe, in, last); readlen = inbound_frame_buf_read(iframe, in, last);
in += readlen; in += readlen;
if(iframe->left) {
if(nghttp2_buf_mark_avail(&iframe->sbuf)) {
return in - first; return in - first;
} }
nghttp2_frame_unpack_frame_hd(&cont_hd, iframe->buf);
nghttp2_frame_unpack_frame_hd(&cont_hd, iframe->sbuf.pos);
iframe->payloadleft = cont_hd.length; iframe->payloadleft = cont_hd.length;
DEBUGF(fprintf(stderr, DEBUGF(fprintf(stderr,
@ -4128,12 +4281,17 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
/* Mark inflater bad so that we won't perform further decoding */ /* Mark inflater bad so that we won't perform further decoding */
session->hd_inflater.ctx.bad = 1; session->hd_inflater.ctx.bad = 1;
busy = 1; busy = 1;
iframe->state = NGHTTP2_IB_IGN_PAYLOAD; iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
break; break;
} }
iframe->frame.hd.flags |= cont_hd.flags & iframe->frame.hd.flags |= cont_hd.flags &
(NGHTTP2_FLAG_END_HEADERS | (NGHTTP2_FLAG_END_HEADERS |
NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW); NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW);
@ -4142,7 +4300,9 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
rv = inbound_frame_handle_pad(iframe, &cont_hd); rv = inbound_frame_handle_pad(iframe, &cont_hd);
if(rv < 0) { if(rv < 0) {
busy = 1; busy = 1;
iframe->state = NGHTTP2_IB_IGN_PAYLOAD; iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
rv = nghttp2_session_terminate_session(session, rv = nghttp2_session_terminate_session(session,
NGHTTP2_PROTOCOL_ERROR); NGHTTP2_PROTOCOL_ERROR);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
@ -4150,6 +4310,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
} }
break; break;
} }
if(rv == 1) { if(rv == 1) {
if(iframe->state == NGHTTP2_IB_EXPECT_CONTINUATION) { if(iframe->state == NGHTTP2_IB_EXPECT_CONTINUATION) {
iframe->state = NGHTTP2_IB_READ_PAD_CONTINUATION; iframe->state = NGHTTP2_IB_READ_PAD_CONTINUATION;
@ -4160,11 +4321,13 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
} }
busy = 1; busy = 1;
if(iframe->state == NGHTTP2_IB_EXPECT_CONTINUATION) { if(iframe->state == NGHTTP2_IB_EXPECT_CONTINUATION) {
iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK;
} else { } else {
iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK;
} }
break; break;
case NGHTTP2_IB_READ_PAD_CONTINUATION: case NGHTTP2_IB_READ_PAD_CONTINUATION:
case NGHTTP2_IB_IGN_PAD_CONTINUATION: case NGHTTP2_IB_IGN_PAD_CONTINUATION:
@ -4175,15 +4338,21 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
fprintf(stderr, "recv: [IB_IGN_PAD_CONTINUATION]\n"); fprintf(stderr, "recv: [IB_IGN_PAD_CONTINUATION]\n");
} }
#endif /* DEBUGBUILD */ #endif /* DEBUGBUILD */
readlen = inbound_frame_buf_read(iframe, in, last); readlen = inbound_frame_buf_read(iframe, in, last);
in += readlen; in += readlen;
iframe->payloadleft -= readlen; iframe->payloadleft -= readlen;
DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu, left=%zu\n", DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu, left=%zu\n",
readlen, iframe->payloadleft, iframe->left)); readlen, iframe->payloadleft,
if(iframe->left) { nghttp2_buf_mark_avail(&iframe->sbuf)));
if(nghttp2_buf_mark_avail(&iframe->sbuf)) {
return in - first; return in - first;
} }
busy = 1; busy = 1;
rv = inbound_frame_compute_pad(iframe); rv = inbound_frame_compute_pad(iframe);
if(rv < 0) { if(rv < 0) {
rv = nghttp2_session_terminate_session(session, rv = nghttp2_session_terminate_session(session,
@ -4191,28 +4360,37 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
iframe->state = NGHTTP2_IB_IGN_PAYLOAD; iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
break; break;
} }
iframe->padlen = rv; iframe->padlen = rv;
if(iframe->frame.hd.type == NGHTTP2_HEADERS) { if(iframe->frame.hd.type == NGHTTP2_HEADERS) {
iframe->frame.headers.padlen += rv; iframe->frame.headers.padlen += rv;
} else { } else {
iframe->frame.push_promise.padlen += rv; iframe->frame.push_promise.padlen += rv;
} }
if(iframe->state == NGHTTP2_IB_READ_PAD_CONTINUATION) { if(iframe->state == NGHTTP2_IB_READ_PAD_CONTINUATION) {
iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK;
} else { } else {
iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK;
} }
break; break;
case NGHTTP2_IB_READ_PAD_DATA: case NGHTTP2_IB_READ_PAD_DATA:
DEBUGF(fprintf(stderr, "recv: [IB_READ_PAD_DATA]\n")); DEBUGF(fprintf(stderr, "recv: [IB_READ_PAD_DATA]\n"));
readlen = inbound_frame_buf_read(iframe, in, last); readlen = inbound_frame_buf_read(iframe, in, last);
in += readlen; in += readlen;
iframe->payloadleft -= readlen; iframe->payloadleft -= readlen;
DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu, left=%zu\n", DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu, left=%zu\n",
readlen, iframe->payloadleft, iframe->left)); readlen, iframe->payloadleft,
nghttp2_buf_mark_avail(&iframe->sbuf)));
/* PAD_HIGH and PAD_LOW are subject to flow control */ /* PAD_HIGH and PAD_LOW are subject to flow control */
rv = nghttp2_session_update_recv_connection_window_size rv = nghttp2_session_update_recv_connection_window_size
@ -4220,6 +4398,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
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) {
@ -4232,11 +4411,12 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
} }
} }
if(iframe->left) { if(nghttp2_buf_mark_avail(&iframe->sbuf)) {
return in - first; return in - first;
} }
busy = 1; busy = 1;
rv = inbound_frame_compute_pad(iframe); rv = inbound_frame_compute_pad(iframe);
if(rv < 0) { if(rv < 0) {
rv = nghttp2_session_terminate_session(session, rv = nghttp2_session_terminate_session(session,
@ -4247,23 +4427,31 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
iframe->state = NGHTTP2_IB_IGN_DATA; iframe->state = NGHTTP2_IB_IGN_DATA;
break; break;
} }
iframe->frame.data.padlen = rv; iframe->frame.data.padlen = rv;
iframe->state = NGHTTP2_IB_READ_DATA; iframe->state = NGHTTP2_IB_READ_DATA;
break; break;
case NGHTTP2_IB_READ_DATA: case NGHTTP2_IB_READ_DATA:
DEBUGF(fprintf(stderr, "recv: [IB_READ_DATA]\n")); DEBUGF(fprintf(stderr, "recv: [IB_READ_DATA]\n"));
readlen = inbound_frame_payload_readlen(iframe, in, last); readlen = inbound_frame_payload_readlen(iframe, in, last);
iframe->payloadleft -= readlen; iframe->payloadleft -= readlen;
in += readlen; in += readlen;
DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu\n", DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu\n",
readlen, iframe->payloadleft)); readlen, iframe->payloadleft));
if(readlen > 0) { if(readlen > 0) {
ssize_t data_readlen; ssize_t data_readlen;
rv = nghttp2_session_update_recv_connection_window_size rv = nghttp2_session_update_recv_connection_window_size
(session, readlen); (session, readlen);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
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) {
@ -4275,9 +4463,12 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
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, "recv: data_readlen=%zu\n", data_readlen)); DEBUGF(fprintf(stderr, "recv: data_readlen=%zu\n", data_readlen));
if(data_readlen > 0 && if(data_readlen > 0 &&
session->callbacks.on_data_chunk_recv_callback) { session->callbacks.on_data_chunk_recv_callback) {
rv = session->callbacks.on_data_chunk_recv_callback rv = session->callbacks.on_data_chunk_recv_callback
@ -4290,11 +4481,13 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
if(rv == NGHTTP2_ERR_PAUSE) { if(rv == NGHTTP2_ERR_PAUSE) {
return in - first; return in - first;
} }
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return NGHTTP2_ERR_CALLBACK_FAILURE; return NGHTTP2_ERR_CALLBACK_FAILURE;
} }
} }
} }
if(iframe->payloadleft) { if(iframe->payloadleft) {
break; break;
} }
@ -4308,15 +4501,20 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
nghttp2_inbound_frame_reset(session); nghttp2_inbound_frame_reset(session);
break; break;
case NGHTTP2_IB_IGN_DATA: case NGHTTP2_IB_IGN_DATA:
DEBUGF(fprintf(stderr, "recv: [IB_IGN_DATA]\n")); DEBUGF(fprintf(stderr, "recv: [IB_IGN_DATA]\n"));
readlen = inbound_frame_payload_readlen(iframe, in, last); readlen = inbound_frame_payload_readlen(iframe, in, last);
iframe->payloadleft -= readlen; iframe->payloadleft -= readlen;
in += readlen; in += readlen;
DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu\n", DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu\n",
readlen, iframe->payloadleft)); readlen, iframe->payloadleft));
if(readlen > 0) { if(readlen > 0) {
/* Update connection-level flow control window for ignored /* Update connection-level flow control window for ignored
DATA frame too */ DATA frame too */
@ -4326,18 +4524,25 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
return rv; return rv;
} }
} }
if(iframe->payloadleft) { if(iframe->payloadleft) {
break; break;
} }
nghttp2_inbound_frame_reset(session); nghttp2_inbound_frame_reset(session);
break; break;
} }
if(!busy && in == last) { if(!busy && in == last) {
break; break;
} }
busy = 0; busy = 0;
} }
assert(in == last); assert(in == last);
return in - first; return in - first;
} }

View File

@ -88,18 +88,20 @@ typedef struct {
about the defined settings ID. If unknown ID is received, it is about the defined settings ID. If unknown ID is received, it is
subject to connection error */ subject to connection error */
nghttp2_settings_entry iv[5]; nghttp2_settings_entry iv[5];
/* buffer pointers to small buffer, raw_sbuf */
nghttp2_buf sbuf;
/* buffer pointers to large buffer, raw_lbuf */
nghttp2_buf lbuf;
/* Large buffer, malloced on demand */
uint8_t *raw_lbuf;
/* The number of entry filled in |iv| */ /* The number of entry filled in |iv| */
size_t niv; size_t niv;
/* How many bytes we still need to receive in the |buf| */
size_t left;
/* How many bytes we still need to receive for current frame */ /* How many bytes we still need to receive for current frame */
size_t payloadleft; size_t payloadleft;
/* padding length for the current frame */ /* padding length for the current frame */
size_t padlen; size_t padlen;
nghttp2_inbound_state state; nghttp2_inbound_state state;
uint8_t buf[8]; uint8_t raw_sbuf[8];
/* How many bytes have been written to |buf| */
uint8_t buflen;
} nghttp2_inbound_frame; } nghttp2_inbound_frame;
typedef enum { typedef enum {

View File

@ -1141,8 +1141,7 @@ void test_nghttp2_session_on_request_headers_received(void)
callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback; callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
nghttp2_session_server_new(&session, &callbacks, &user_data); nghttp2_session_server_new(&session, &callbacks, &user_data);
memset(session->iframe.buf, 0, 4);
session->iframe.buflen = 4;
nghttp2_frame_headers_init(&frame.headers, nghttp2_frame_headers_init(&frame.headers,
NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY, NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY,
stream_id, 1 << 20, NULL, 0); stream_id, 1 << 20, NULL, 0);
@ -1190,8 +1189,7 @@ void test_nghttp2_session_on_request_headers_received(void)
/* Check malformed headers. The library accept it. */ /* Check malformed headers. The library accept it. */
nghttp2_session_server_new(&session, &callbacks, &user_data); nghttp2_session_server_new(&session, &callbacks, &user_data);
memset(session->iframe.buf, 0, 4);
session->iframe.buflen = 4;
nvlen = nghttp2_nv_array_copy(&nva, malformed_nva, ARRLEN(malformed_nva)); nvlen = nghttp2_nv_array_copy(&nva, malformed_nva, ARRLEN(malformed_nva));
nghttp2_frame_headers_init(&frame.headers, nghttp2_frame_headers_init(&frame.headers,
NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY, NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY,
@ -1584,8 +1582,7 @@ void test_nghttp2_session_on_push_promise_received(void)
callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback; callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
nghttp2_session_client_new(&session, &callbacks, &user_data); nghttp2_session_client_new(&session, &callbacks, &user_data);
memset(session->iframe.buf, 0, 4);
session->iframe.buflen = 4;
stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
NGHTTP2_PRI_DEFAULT, NGHTTP2_PRI_DEFAULT,
NGHTTP2_STREAM_OPENING, NULL); NGHTTP2_STREAM_OPENING, NULL);
@ -1660,8 +1657,6 @@ void test_nghttp2_session_on_push_promise_received(void)
nghttp2_session_del(session); nghttp2_session_del(session);
nghttp2_session_client_new(&session, &callbacks, &user_data); nghttp2_session_client_new(&session, &callbacks, &user_data);
memset(session->iframe.buf, 0, 4);
session->iframe.buflen = 4;
stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
NGHTTP2_PRI_DEFAULT, NGHTTP2_PRI_DEFAULT,
@ -1698,8 +1693,7 @@ void test_nghttp2_session_on_push_promise_received(void)
nghttp2_session_del(session); nghttp2_session_del(session);
nghttp2_session_client_new(&session, &callbacks, &user_data); nghttp2_session_client_new(&session, &callbacks, &user_data);
memset(session->iframe.buf, 0, 4);
session->iframe.buflen = 4;
stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE, stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
NGHTTP2_PRI_DEFAULT, NGHTTP2_PRI_DEFAULT,
NGHTTP2_STREAM_RESERVED, NULL); NGHTTP2_STREAM_RESERVED, NULL);
@ -1721,8 +1715,7 @@ void test_nghttp2_session_on_push_promise_received(void)
/* Disable PUSH */ /* Disable PUSH */
nghttp2_session_client_new(&session, &callbacks, &user_data); nghttp2_session_client_new(&session, &callbacks, &user_data);
memset(session->iframe.buf, 0, 4);
session->iframe.buflen = 4;
stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
NGHTTP2_PRI_DEFAULT, NGHTTP2_PRI_DEFAULT,
NGHTTP2_STREAM_OPENING, NULL); NGHTTP2_STREAM_OPENING, NULL);
@ -1746,8 +1739,7 @@ void test_nghttp2_session_on_push_promise_received(void)
/* Check malformed headers. We accept malformed headers */ /* Check malformed headers. We accept malformed headers */
nghttp2_session_client_new(&session, &callbacks, &user_data); nghttp2_session_client_new(&session, &callbacks, &user_data);
memset(session->iframe.buf, 0, 4);
session->iframe.buflen = 4;
stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
NGHTTP2_PRI_DEFAULT, NGHTTP2_PRI_DEFAULT,
NGHTTP2_STREAM_OPENING, NULL); NGHTTP2_STREAM_OPENING, NULL);