Introduce nghttp2_buf to ease buffer management

This commit is contained in:
Tatsuhiro Tsujikawa 2014-03-11 01:47:38 +09:00
parent d074cb611f
commit 358b4386d3
21 changed files with 1604 additions and 894 deletions

View File

@ -33,6 +33,7 @@ lib_LTLIBRARIES = libnghttp2.la
OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \
nghttp2_buffer.c nghttp2_frame.c \ nghttp2_buffer.c nghttp2_frame.c \
nghttp2_buf.c \
nghttp2_stream.c nghttp2_outbound_item.c \ nghttp2_stream.c nghttp2_outbound_item.c \
nghttp2_session.c nghttp2_submit.c \ nghttp2_session.c nghttp2_submit.c \
nghttp2_helper.c \ nghttp2_helper.c \
@ -42,6 +43,7 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \
HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \ HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
nghttp2_buffer.h nghttp2_frame.h \ nghttp2_buffer.h nghttp2_frame.h \
nghttp2_buf.h \
nghttp2_session.h nghttp2_helper.h nghttp2_stream.h nghttp2_int.h \ nghttp2_session.h nghttp2_helper.h nghttp2_stream.h nghttp2_int.h \
nghttp2_npn.h nghttp2_gzip.h \ nghttp2_npn.h nghttp2_gzip.h \
nghttp2_submit.h nghttp2_outbound_item.h \ nghttp2_submit.h nghttp2_outbound_item.h \

95
lib/nghttp2_buf.c Normal file
View File

@ -0,0 +1,95 @@
/*
* nghttp2 - HTTP/2.0 C Library
*
* Copyright (c) 2014 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "nghttp2_buf.h"
#include "nghttp2_helper.h"
void nghttp2_buf_init(nghttp2_buf *buf)
{
buf->begin = NULL;
buf->end = NULL;
buf->pos = NULL;
buf->last = NULL;
buf->mark = NULL;
}
int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial)
{
nghttp2_buf_init(buf);
return nghttp2_buf_reserve(buf, initial);
}
void nghttp2_buf_free(nghttp2_buf *buf)
{
free(buf->begin);
}
int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap)
{
uint8_t *ptr;
size_t cap;
cap = nghttp2_buf_cap(buf);
if(cap >= new_cap) {
return 0;
}
new_cap = nghttp2_max(new_cap, cap * 2);
ptr = realloc(buf->begin, new_cap);
if(ptr == NULL) {
return NGHTTP2_ERR_NOMEM;
}
buf->pos = ptr + (buf->pos - buf->begin);
buf->last = ptr + (buf->last - buf->begin);
buf->mark = ptr + (buf->mark - buf->begin);
buf->begin = ptr;
buf->end = ptr + new_cap;
return 0;
}
int nghttp2_buf_pos_reserve(nghttp2_buf *buf, size_t new_rel_cap)
{
return nghttp2_buf_reserve(buf, nghttp2_buf_pos_offset(buf) + new_rel_cap);
}
int nghttp2_buf_last_reserve(nghttp2_buf *buf, size_t new_rel_cap)
{
return nghttp2_buf_reserve(buf, nghttp2_buf_last_offset(buf) + new_rel_cap);
}
void nghttp2_buf_reset(nghttp2_buf *buf)
{
buf->pos = buf->last = buf->mark = buf->begin;
}
void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len)
{
buf->begin = buf->pos = buf->last = buf->mark = begin;
buf->end = begin + len;
}

137
lib/nghttp2_buf.h Normal file
View File

@ -0,0 +1,137 @@
/*
* nghttp2 - HTTP/2.0 C Library
*
* Copyright (c) 2014 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_BUF_H
#define NGHTTP2_BUF_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
#include "nghttp2_int.h"
typedef struct {
/* This points to the beginning of the buffer. The effective range
of buffer is [begin, end). */
uint8_t *begin;
/* This points to the memory one byte beyond the end of the
buffer. */
uint8_t *end;
/* The position indicator for effective start of the buffer. pos <=
last must be hold. */
uint8_t *pos;
/* The position indicator for effective one beyond of the end of the
buffer. last <= end must be hold. */
uint8_t *last;
/* Mark arbitrary position in buffer [begin, end) */
uint8_t *mark;
} nghttp2_buf;
#define nghttp2_buf_len(BUF) ((BUF)->last - (BUF)->pos)
#define nghttp2_buf_avail(BUF) ((BUF)->end - (BUF)->last)
#define nghttp2_buf_cap(BUF) ((BUF)->end - (BUF)->begin)
#define nghttp2_buf_pos_offset(BUF) ((BUF)->pos - (BUF)->begin)
#define nghttp2_buf_last_offset(BUF) ((BUF)->last - (BUF)->begin)
#define nghttp2_buf_shift_right(BUF, AMT) \
do { \
(BUF)->pos += AMT; \
(BUF)->last += AMT; \
} while(0)
#define nghttp2_buf_shift_left(BUF, AMT) \
do { \
(BUF)->pos -= AMT; \
(BUF)->last -= AMT; \
} while(0)
/*
* Initializes the |buf|. No memory is allocated in this function. Use
* nghttp2_buf_reserve() or nghttp2_buf_reserve2() to allocate memory.
*/
void nghttp2_buf_init(nghttp2_buf *buf);
/*
* Initializes the |buf| and allocates at least |initial| bytes of
* memory.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial);
/*
* Frees buffer in |buf|.
*/
void nghttp2_buf_free(nghttp2_buf *buf);
/*
* Extends buffer so that nghttp2_buf_cap() returns at least
* |new_cap|. If extensions took place, buffer pointers in |buf| will
* change.
*
* This function returns 0 if it succeeds, or one of the followings
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap);
/*
* This function behaves like nghttp2_buf_reserve(), but new capacity
* is calculated as nghttp2_buf_pos_offset(buf) + new_rel_cap. In
* other words, this function reserves memory at least |new_rel_cap|
* bytes from buf->pos.
*/
int nghttp2_buf_pos_reserve(nghttp2_buf *buf, size_t new_rel_cap);
/*
* This function behaves like nghttp2_buf_reserve(), but new capacity
* is calculated as nghttp2_buf_last_offset(buf) + new_rel_cap. In
* other words, this function reserves memory at least |new_rel_cap|
* bytes from buf->last.
*/
int nghttp2_buf_last_reserve(nghttp2_buf *buf, size_t new_rel_cap);
/*
* Resets pos, last, mark member of |buf| to buf->begin.
*/
void nghttp2_buf_reset(nghttp2_buf *buf);
/*
* Initializes |buf| using supplied buffer |begin| of length
* |len|. Semantically, the application should not call *_reserve() or
* nghttp2_free() functions for |buf|.
*/
void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len);
#endif /* NGHTTP2_BUF_H */

View File

@ -224,50 +224,64 @@ size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame)
} }
} }
ssize_t nghttp2_frame_pack_headers(uint8_t **buf_ptr, ssize_t nghttp2_frame_pack_headers(nghttp2_buf *buf,
size_t *buflen_ptr,
size_t *bufoff_ptr,
nghttp2_headers *frame, nghttp2_headers *frame,
nghttp2_hd_deflater *deflater) nghttp2_hd_deflater *deflater)
{ {
size_t payloadoff = NGHTTP2_FRAME_HEAD_LENGTH + 2; size_t nv_offset;
size_t nv_offset =
payloadoff + nghttp2_frame_headers_payload_nv_offset(frame);
ssize_t rv; ssize_t rv;
size_t payloadlen;
rv = nghttp2_hd_deflate_hd(deflater, buf_ptr, buflen_ptr, nv_offset, assert(nghttp2_buf_len(buf) == 0);
frame->nva, frame->nvlen);
if(rv < 0) {
return rv;
}
payloadlen = nghttp2_frame_headers_payload_nv_offset(frame) + rv; /* Account for possible PAD_HIGH and PAD_LOW */
buf->pos += 2;
*bufoff_ptr = 2; nv_offset =
frame->padlen = 0; NGHTTP2_FRAME_HDLEN + nghttp2_frame_headers_payload_nv_offset(frame);
frame->hd.length = payloadlen;
/* If frame->nvlen == 0, *buflen_ptr may be smaller than /* If frame->nvlen == 0, nghttp2_buf_len(buf) may be smaller than
nv_offset */ nv_offset */
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, nv_offset); rv = nghttp2_buf_pos_reserve(buf, nv_offset);
if(rv < 0) { if(rv < 0) {
return rv; return rv;
} }
memset(*buf_ptr + *bufoff_ptr, 0, NGHTTP2_FRAME_HEAD_LENGTH);
buf->pos += nv_offset;
buf->last = buf->pos;
/* This call will adjust buf->last to the correct position */
rv = nghttp2_hd_deflate_hd(deflater, buf, frame->nva, frame->nvlen);
buf->pos -= nv_offset;
if(rv < 0) {
return rv;
}
frame->hd.length = nghttp2_frame_headers_payload_nv_offset(frame) + rv;
frame->padlen = 0;
/* Don't use buf->last, since it already points to the end of the
frame */
memset(buf->pos, 0, NGHTTP2_FRAME_HEAD_LENGTH);
/* pack ctrl header after length is determined */ /* pack ctrl header after length is determined */
if(NGHTTP2_MAX_FRAME_LENGTH < payloadlen) { if(NGHTTP2_MAX_FRAME_LENGTH < frame->hd.length) {
/* Needs CONTINUATION */ /* Needs CONTINUATION */
nghttp2_frame_hd hd = frame->hd; nghttp2_frame_hd hd = frame->hd;
hd.flags &= ~NGHTTP2_FLAG_END_HEADERS; hd.flags &= ~NGHTTP2_FLAG_END_HEADERS;
hd.length = NGHTTP2_MAX_FRAME_LENGTH; hd.length = NGHTTP2_MAX_FRAME_LENGTH;
nghttp2_frame_pack_frame_hd(*buf_ptr + *bufoff_ptr, &hd);
nghttp2_frame_pack_frame_hd(buf->pos, &hd);
} else { } else {
nghttp2_frame_pack_frame_hd(*buf_ptr + *bufoff_ptr, &frame->hd); nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
} }
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
nghttp2_put_uint32be(&(*buf_ptr)[payloadoff], frame->pri); nghttp2_put_uint32be(buf->pos + NGHTTP2_FRAME_HDLEN, frame->pri);
} }
return *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH + frame->hd.length;
return nghttp2_buf_len(buf);
} }
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame, int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
@ -284,19 +298,28 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
return 0; return 0;
} }
ssize_t nghttp2_frame_pack_priority(uint8_t **buf_ptr, size_t *buflen_ptr, ssize_t nghttp2_frame_pack_priority(nghttp2_buf *buf,
nghttp2_priority *frame) nghttp2_priority *frame)
{ {
ssize_t framelen= NGHTTP2_FRAME_HEAD_LENGTH + 4; ssize_t framelen= NGHTTP2_FRAME_HEAD_LENGTH + 4;
int rv; int rv;
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, framelen);
assert(nghttp2_buf_len(buf) == 0);
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
memset(*buf_ptr, 0, framelen);
nghttp2_frame_pack_frame_hd(*buf_ptr, &frame->hd); memset(buf->last, 0, framelen);
nghttp2_put_uint32be(&(*buf_ptr)[8], frame->pri);
return framelen; nghttp2_frame_pack_frame_hd(buf->last, &frame->hd);
buf->last += NGHTTP2_FRAME_HDLEN;
nghttp2_put_uint32be(buf->last, frame->pri);
buf->last += 4;
return nghttp2_buf_len(buf);
} }
void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame, void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
@ -306,19 +329,28 @@ void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
frame->pri = nghttp2_get_uint32(payload) & NGHTTP2_PRIORITY_MASK; frame->pri = nghttp2_get_uint32(payload) & NGHTTP2_PRIORITY_MASK;
} }
ssize_t nghttp2_frame_pack_rst_stream(uint8_t **buf_ptr, size_t *buflen_ptr, ssize_t nghttp2_frame_pack_rst_stream(nghttp2_buf *buf,
nghttp2_rst_stream *frame) nghttp2_rst_stream *frame)
{ {
ssize_t framelen = NGHTTP2_FRAME_HEAD_LENGTH + 4; ssize_t framelen = NGHTTP2_FRAME_HEAD_LENGTH + 4;
int rv; int rv;
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, framelen);
assert(nghttp2_buf_len(buf) == 0);
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
memset(*buf_ptr, 0, framelen);
nghttp2_frame_pack_frame_hd(*buf_ptr, &frame->hd); memset(buf->last, 0, framelen);
nghttp2_put_uint32be(&(*buf_ptr)[8], frame->error_code);
return framelen; nghttp2_frame_pack_frame_hd(buf->last, &frame->hd);
buf->last += NGHTTP2_FRAME_HDLEN;
nghttp2_put_uint32be(buf->last, frame->error_code);
buf->last += 4;
return nghttp2_buf_len(buf);
} }
void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame, void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
@ -328,19 +360,28 @@ void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
frame->error_code = nghttp2_get_uint32(payload); frame->error_code = nghttp2_get_uint32(payload);
} }
ssize_t nghttp2_frame_pack_settings(uint8_t **buf_ptr, size_t *buflen_ptr, ssize_t nghttp2_frame_pack_settings(nghttp2_buf *buf,
nghttp2_settings *frame) nghttp2_settings *frame)
{ {
ssize_t framelen = NGHTTP2_FRAME_HEAD_LENGTH + frame->hd.length; ssize_t framelen = NGHTTP2_FRAME_HEAD_LENGTH + frame->hd.length;
int rv; int rv;
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, framelen);
assert(nghttp2_buf_len(buf) == 0);
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
memset(*buf_ptr, 0, framelen);
nghttp2_frame_pack_frame_hd(*buf_ptr, &frame->hd); memset(buf->last, 0, framelen);
nghttp2_frame_pack_settings_payload(*buf_ptr + 8, frame->iv, frame->niv);
return framelen; nghttp2_frame_pack_frame_hd(buf->last, &frame->hd);
buf->last += NGHTTP2_FRAME_HDLEN;
buf->last += nghttp2_frame_pack_settings_payload(buf->last,
frame->iv, frame->niv);
return nghttp2_buf_len(buf);
} }
size_t nghttp2_frame_pack_settings_payload(uint8_t *buf, size_t nghttp2_frame_pack_settings_payload(uint8_t *buf,
@ -395,47 +436,60 @@ int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
return 0; return 0;
} }
ssize_t nghttp2_frame_pack_push_promise(uint8_t **buf_ptr, ssize_t nghttp2_frame_pack_push_promise(nghttp2_buf *buf,
size_t *buflen_ptr,
size_t *bufoff_ptr,
nghttp2_push_promise *frame, nghttp2_push_promise *frame,
nghttp2_hd_deflater *deflater) nghttp2_hd_deflater *deflater)
{ {
size_t payloadoff = NGHTTP2_FRAME_HEAD_LENGTH + 2; size_t nv_offset = NGHTTP2_FRAME_HDLEN + 4;
size_t nv_offset = payloadoff + 4;
ssize_t rv; ssize_t rv;
size_t payloadlen;
rv = nghttp2_hd_deflate_hd(deflater, buf_ptr, buflen_ptr, nv_offset, assert(nghttp2_buf_len(buf) == 0);
frame->nva, frame->nvlen);
if(rv < 0) {
return rv;
}
payloadlen = 4 + rv; /* Account for possible PAD_HIGH and PAD_LOW */
buf->pos += 2;
*bufoff_ptr = 2; /* If frame->nvlen == 0, nghttp2_buf_len(buf) may be smaller than
frame->padlen = 0;
frame->hd.length = payloadlen;
/* If frame->nvlen == 0, *buflen_ptr may be smaller than
nv_offset */ nv_offset */
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, nv_offset); rv = nghttp2_buf_pos_reserve(buf, nv_offset);
if(rv < 0) { if(rv < 0) {
return rv; return rv;
} }
memset(*buf_ptr + *bufoff_ptr, 0, NGHTTP2_FRAME_HEAD_LENGTH);
buf->pos += nv_offset;
buf->last = buf->pos;
/* This call will adjust buf->last to the correct position */
rv = nghttp2_hd_deflate_hd(deflater, buf, frame->nva, frame->nvlen);
buf->pos -= nv_offset;
if(rv < 0) {
return rv;
}
frame->hd.length = 4 + rv;
frame->padlen = 0;
/* Don't use buf->last, since it already points to the end of the
frame */
memset(buf->pos, 0, NGHTTP2_FRAME_HEAD_LENGTH);
/* pack ctrl header after length is determined */ /* pack ctrl header after length is determined */
if(NGHTTP2_MAX_FRAME_LENGTH < payloadlen) { if(NGHTTP2_MAX_FRAME_LENGTH < frame->hd.length) {
/* Needs CONTINUATION */ /* Needs CONTINUATION */
nghttp2_frame_hd hd = frame->hd; nghttp2_frame_hd hd = frame->hd;
hd.flags &= ~NGHTTP2_FLAG_END_HEADERS; hd.flags &= ~NGHTTP2_FLAG_END_HEADERS;
hd.length = NGHTTP2_MAX_FRAME_LENGTH; hd.length = NGHTTP2_MAX_FRAME_LENGTH;
nghttp2_frame_pack_frame_hd(*buf_ptr + *bufoff_ptr, &hd);
nghttp2_frame_pack_frame_hd(buf->pos, &hd);
} else { } else {
nghttp2_frame_pack_frame_hd(*buf_ptr + *bufoff_ptr, &frame->hd); nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
} }
nghttp2_put_uint32be(&(*buf_ptr)[payloadoff], frame->promised_stream_id);
return *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH + frame->hd.length; nghttp2_put_uint32be(buf->pos + NGHTTP2_FRAME_HDLEN,
frame->promised_stream_id);
return nghttp2_buf_len(buf);
} }
int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame, int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
@ -449,19 +503,27 @@ int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
return 0; return 0;
} }
ssize_t nghttp2_frame_pack_ping(uint8_t **buf_ptr, size_t *buflen_ptr, ssize_t nghttp2_frame_pack_ping(nghttp2_buf *buf, nghttp2_ping *frame)
nghttp2_ping *frame)
{ {
ssize_t framelen = NGHTTP2_FRAME_HEAD_LENGTH + 8; ssize_t framelen = NGHTTP2_FRAME_HEAD_LENGTH + 8;
int rv; int rv;
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, framelen);
assert(nghttp2_buf_len(buf) == 0);
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
memset(*buf_ptr, 0, framelen);
nghttp2_frame_pack_frame_hd(*buf_ptr, &frame->hd); memset(buf->last, 0, framelen);
memcpy(&(*buf_ptr)[8], frame->opaque_data, sizeof(frame->opaque_data));
return framelen; nghttp2_frame_pack_frame_hd(buf->last, &frame->hd);
buf->last += NGHTTP2_FRAME_HDLEN;
memcpy(buf->last, frame->opaque_data, sizeof(frame->opaque_data));
buf->last += sizeof(frame->opaque_data);
return nghttp2_buf_len(buf);
} }
void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame, void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
@ -471,21 +533,33 @@ void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
memcpy(frame->opaque_data, payload, sizeof(frame->opaque_data)); memcpy(frame->opaque_data, payload, sizeof(frame->opaque_data));
} }
ssize_t nghttp2_frame_pack_goaway(uint8_t **buf_ptr, size_t *buflen_ptr, ssize_t nghttp2_frame_pack_goaway(nghttp2_buf *buf, nghttp2_goaway *frame)
nghttp2_goaway *frame)
{ {
ssize_t framelen = NGHTTP2_FRAME_HEAD_LENGTH + frame->hd.length; ssize_t framelen = NGHTTP2_FRAME_HEAD_LENGTH + frame->hd.length;
int rv; int rv;
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, framelen);
assert(nghttp2_buf_len(buf) == 0);
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
memset(*buf_ptr, 0, framelen);
nghttp2_frame_pack_frame_hd(*buf_ptr, &frame->hd); memset(buf->last, 0, framelen);
nghttp2_put_uint32be(&(*buf_ptr)[8], frame->last_stream_id);
nghttp2_put_uint32be(&(*buf_ptr)[12], frame->error_code); nghttp2_frame_pack_frame_hd(buf->last, &frame->hd);
memcpy(&(*buf_ptr)[16], frame->opaque_data, frame->opaque_data_len); buf->last += NGHTTP2_FRAME_HDLEN;
return framelen;
nghttp2_put_uint32be(buf->last, frame->last_stream_id);
buf->last += 4;
nghttp2_put_uint32be(buf->last, frame->error_code);
buf->last += 4;
memcpy(buf->last, frame->opaque_data, frame->opaque_data_len);
buf->last += frame->opaque_data_len;
return nghttp2_buf_len(buf);
} }
void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame, void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
@ -499,19 +573,28 @@ void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
frame->opaque_data_len = 0; frame->opaque_data_len = 0;
} }
ssize_t nghttp2_frame_pack_window_update(uint8_t **buf_ptr, size_t *buflen_ptr, ssize_t nghttp2_frame_pack_window_update(nghttp2_buf *buf,
nghttp2_window_update *frame) nghttp2_window_update *frame)
{ {
ssize_t framelen = NGHTTP2_FRAME_HEAD_LENGTH + 4; ssize_t framelen = NGHTTP2_FRAME_HEAD_LENGTH + 4;
int rv; int rv;
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, framelen);
assert(nghttp2_buf_len(buf) == 0);
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
memset(*buf_ptr, 0, framelen);
nghttp2_frame_pack_frame_hd(*buf_ptr, &frame->hd); memset(buf->last, 0, framelen);
nghttp2_put_uint32be(&(*buf_ptr)[8], frame->window_size_increment);
return framelen; nghttp2_frame_pack_frame_hd(buf->last, &frame->hd);
buf->last += NGHTTP2_FRAME_HDLEN;
nghttp2_put_uint32be(buf->last, frame->window_size_increment);
buf->last += 4;
return nghttp2_buf_len(buf);
} }
void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame, void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
@ -654,42 +737,34 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv)
return 1; return 1;
} }
int nghttp2_frame_add_pad(uint8_t **buf_ptr, size_t *buflen_ptr, void nghttp2_frame_set_pad(nghttp2_buf *buf, uint8_t *flags_ptr, size_t padlen)
size_t *bufoff_ptr,
uint8_t *flags_ptr,
size_t payloadlen,
size_t padlen)
{ {
int rv;
size_t trail_padlen = 0; size_t trail_padlen = 0;
/* extra 2 bytes for PAD_HIGH and PAD_LOW. */
size_t trail_padoff = *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH + payloadlen;
if(padlen > 257) { if(padlen > 256) {
uint8_t *p; uint8_t *p;
*bufoff_ptr -= 2;
trail_padlen = padlen - 2; trail_padlen = padlen - 2;
*flags_ptr |= NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW; *flags_ptr |= NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW;
p = *buf_ptr + *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH;
assert(nghttp2_buf_pos_offset(buf) >= 2);
/* Consume previous 2 bytes, shifting 2 bytes to the left */
nghttp2_buf_shift_left(buf, 2);
p = buf->pos + NGHTTP2_FRAME_HEAD_LENGTH;
*p++ = trail_padlen >> 8; *p++ = trail_padlen >> 8;
*p = trail_padlen & 0xff; *p = trail_padlen & 0xff;
} else if(padlen > 0) { } else if(padlen > 0) {
--*bufoff_ptr; assert(nghttp2_buf_pos_offset(buf) >= 1);
/* Consume previous 1 byte, shifting 1 bytes to the left */
nghttp2_buf_shift_left(buf, 1);
trail_padlen = padlen - 1; trail_padlen = padlen - 1;
*flags_ptr |= NGHTTP2_FLAG_PAD_LOW; *flags_ptr |= NGHTTP2_FLAG_PAD_LOW;
(*buf_ptr)[*bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH] = trail_padlen;
} else {
return 0;
}
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, *(buf->pos + NGHTTP2_FRAME_HEAD_LENGTH) = trail_padlen;
trail_padoff + trail_padlen);
if(rv != 0) {
return rv;
} }
/* We have to zero out padding bytes so that we won't reveal the
possible internal data to the remote peer */
memset((*buf_ptr) + trail_padoff, 0, trail_padlen);
return 0;
} }

View File

@ -32,6 +32,7 @@
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
#include "nghttp2_hd.h" #include "nghttp2_hd.h"
#include "nghttp2_buffer.h" #include "nghttp2_buffer.h"
#include "nghttp2_buf.h"
#define NGHTTP2_FRAME_LENGTH_MASK ((1 << 14) - 1) #define NGHTTP2_FRAME_LENGTH_MASK ((1 << 14) - 1)
#define NGHTTP2_STREAM_ID_MASK ((1u << 31) - 1) #define NGHTTP2_STREAM_ID_MASK ((1u << 31) - 1)
@ -39,7 +40,8 @@
#define NGHTTP2_WINDOW_SIZE_INCREMENT_MASK ((1u << 31) - 1) #define NGHTTP2_WINDOW_SIZE_INCREMENT_MASK ((1u << 31) - 1)
#define NGHTTP2_SETTINGS_ID_MASK ((1 << 24) - 1) #define NGHTTP2_SETTINGS_ID_MASK ((1 << 24) - 1)
/* The maximum payload length of a frame */ /* The maximum payload length of a frame TODO: Must be renamed as
NGHTTP2_MAX_PAYLOAD_LENGTH */
#define NGHTTP2_MAX_FRAME_LENGTH ((1 << 14) - 1) #define NGHTTP2_MAX_FRAME_LENGTH ((1 << 14) - 1)
/* The maximum length of DATA frame payload. To fit entire DATA frame /* The maximum length of DATA frame payload. To fit entire DATA frame
@ -48,7 +50,8 @@
#define NGHTTP2_DATA_PAYLOAD_LENGTH 4086 #define NGHTTP2_DATA_PAYLOAD_LENGTH 4086
/* The number of bytes of frame header. */ /* The number of bytes of frame header. */
#define NGHTTP2_FRAME_HEAD_LENGTH 8 #define NGHTTP2_FRAME_HDLEN 8
#define NGHTTP2_FRAME_HEAD_LENGTH NGHTTP2_FRAME_HDLEN
/* The number of bytes for each SETTINGS entry */ /* The number of bytes for each SETTINGS entry */
#define NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH 5 #define NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH 5
@ -100,15 +103,12 @@ void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t* buf);
size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame); size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame);
/* /*
* Packs HEADERS frame |frame| in wire format and store it in * Packs HEADERS frame |frame| in wire format and store it in |buf|.
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| bytes. * This function expands |buf| as necessary to store frame. The caller
* This function expands |*buf_ptr| as necessary to store frame. When * must make sure that nghttp2_buf_len(buf) == 0 holds when calling
* expansion occurred, memory previously pointed by |*buf_ptr| may * this function.
* change. |*buf_ptr| and |*buflen_ptr| are updated accordingly.
* *
* The first byte the frame is serialized is returned in the * The first byte the frame is serialized is returned in the |buf|.
* |*bufoff_ptr|. Currently, it is always 2 to account for possible
* PAD_HIGH and PAD_LOW.
* *
* frame->hd.length is assigned after length is determined during * frame->hd.length is assigned after length is determined during
* packing process. If payload length is strictly larger than * packing process. If payload length is strictly larger than
@ -116,8 +116,8 @@ size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame);
* but frame->hd.length is set to NGHTTP2_MAX_FRAME_LENGTH and * but frame->hd.length is set to NGHTTP2_MAX_FRAME_LENGTH and
* NGHTTP2_FLAG_END_HEADERS flag is cleared from frame->hd.flags. * NGHTTP2_FLAG_END_HEADERS flag is cleared from frame->hd.flags.
* *
* This function returns the size of packed frame (which includes * This function returns the size of packed frame (which equals to
* |*bufoff_ptr| bytes) if it succeeds, or returns one of the * nghttp2_buf_len(buf)) if it succeeds, or returns one of the
* following negative error codes: * following negative error codes:
* *
* NGHTTP2_ERR_HEADER_COMP * NGHTTP2_ERR_HEADER_COMP
@ -127,9 +127,7 @@ size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame);
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory. * Out of memory.
*/ */
ssize_t nghttp2_frame_pack_headers(uint8_t **buf_ptr, ssize_t nghttp2_frame_pack_headers(nghttp2_buf *buf,
size_t *buflen_ptr,
size_t *bufoff_ptr,
nghttp2_headers *frame, nghttp2_headers *frame,
nghttp2_hd_deflater *deflater); nghttp2_hd_deflater *deflater);
@ -149,9 +147,8 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
/* /*
* Packs PRIORITY frame |frame| in wire format and store it in * Packs PRIORITY frame |frame| in wire format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| * |buf|. This function expands |buf| as necessary to store given
* length. This function expands |*buf_ptr| as necessary to store * |frame|.
* given |frame|.
* *
* This function returns 0 if it succeeds or one of the following * This function returns 0 if it succeeds or one of the following
* negative error codes: * negative error codes:
@ -159,7 +156,7 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory. * Out of memory.
*/ */
ssize_t nghttp2_frame_pack_priority(uint8_t **buf_ptr, size_t *buflen_ptr, ssize_t nghttp2_frame_pack_priority(nghttp2_buf *buf,
nghttp2_priority *frame); nghttp2_priority *frame);
/* /*
@ -171,10 +168,8 @@ void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
/* /*
* Packs RST_STREAM frame |frame| in wire frame format and store it in * Packs RST_STREAM frame |frame| in wire frame format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| * |buf|. This function expands |buf| as necessary to store given
* length. This function expands |*buf_ptr| as necessary to store * |frame|.
* given |frame|. In spdy/2 spec, RST_STREAM wire format is always 16
* bytes long.
* *
* This function returns the size of packed frame if it succeeds, or * This function returns the size of packed frame if it succeeds, or
* returns one of the following negative error codes: * returns one of the following negative error codes:
@ -182,7 +177,7 @@ void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory. * Out of memory.
*/ */
ssize_t nghttp2_frame_pack_rst_stream(uint8_t **buf_ptr, size_t *buflen_ptr, ssize_t nghttp2_frame_pack_rst_stream(nghttp2_buf *buf,
nghttp2_rst_stream *frame); nghttp2_rst_stream *frame);
/* /*
@ -194,9 +189,8 @@ void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
/* /*
* Packs SETTINGS frame |frame| in wire format and store it in * Packs SETTINGS frame |frame| in wire format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| * |buf|. This function expands |buf| as necessary to store given
* length. This function expands |*buf_ptr| as necessary to store * |frame|.
* given |frame|.
* *
* This function returns the size of packed frame if it succeeds, or * This function returns the size of packed frame if it succeeds, or
* returns one of the following negative error codes: * returns one of the following negative error codes:
@ -204,7 +198,7 @@ void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory. * Out of memory.
*/ */
ssize_t nghttp2_frame_pack_settings(uint8_t **buf_ptr, size_t *buflen_ptr, ssize_t nghttp2_frame_pack_settings(nghttp2_buf *buf,
nghttp2_settings *frame); nghttp2_settings *frame);
/* /*
@ -253,14 +247,11 @@ int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
/* /*
* Packs PUSH_PROMISE frame |frame| in wire format and store it in * Packs PUSH_PROMISE frame |frame| in wire format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| bytes. * |buf|. This function expands |buf| as necessary to store
* This function expands |*buf_ptr| as necessary to store frame. When * frame. The caller must make sure that nghttp2_buf_len(buf) == 0
* expansion occurred, memory previously pointed by |*buf_ptr| may * holds when calling this function.
* change. |*buf_ptr| and |*buflen_ptr| are updated accordingly.
* *
* The first byte the frame is serialized is returned in the * The first byte the frame is serialized is returned in the |buf|.
* |*bufoff_ptr|. Currently, it is always 2 to account for possible
* PAD_HIGH and PAD_LOW.
* *
* frame->hd.length is assigned after length is determined during * frame->hd.length is assigned after length is determined during
* packing process. If payload length is strictly larger than * packing process. If payload length is strictly larger than
@ -268,13 +259,10 @@ int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
* but frame->hd.length is set to NGHTTP2_MAX_FRAME_LENGTH and * but frame->hd.length is set to NGHTTP2_MAX_FRAME_LENGTH and
* NGHTTP2_FLAG_END_HEADERS flag is cleared from frame->hd.flags. * NGHTTP2_FLAG_END_HEADERS flag is cleared from frame->hd.flags.
* *
* This function returns the size of packed frame (which includes * This function returns the size of packed frame (which equals to
* |*bufoff_ptr| bytes) if it succeeds, or returns one of the * nghttp2_buf_len(buf)) if it succeeds, or returns one of the
* following negative error codes: * following negative error codes:
* *
* This function returns the size of packed frame if it succeeds, or
* returns one of the following negative error codes:
*
* NGHTTP2_ERR_HEADER_COMP * NGHTTP2_ERR_HEADER_COMP
* The deflate operation failed. * The deflate operation failed.
* NGHTTP2_ERR_FRAME_TOO_LARGE * NGHTTP2_ERR_FRAME_TOO_LARGE
@ -282,9 +270,7 @@ int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory. * Out of memory.
*/ */
ssize_t nghttp2_frame_pack_push_promise(uint8_t **buf_ptr, ssize_t nghttp2_frame_pack_push_promise(nghttp2_buf *buf,
size_t *buflen_ptr,
size_t *bufoff_ptr,
nghttp2_push_promise *frame, nghttp2_push_promise *frame,
nghttp2_hd_deflater *deflater); nghttp2_hd_deflater *deflater);
@ -303,10 +289,8 @@ int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
size_t payloadlen); size_t payloadlen);
/* /*
* Packs PING frame |frame| in wire format and store it in * Packs PING frame |frame| in wire format and store it in |buf|. This
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| * function expands |buf| as necessary to store given |frame|.
* length. This function expands |*buf_ptr| as necessary to store
* given |frame|.
* *
* This function returns 0 if it succeeds or one of the following * This function returns 0 if it succeeds or one of the following
* negative error codes: * negative error codes:
@ -314,8 +298,7 @@ int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory. * Out of memory.
*/ */
ssize_t nghttp2_frame_pack_ping(uint8_t **buf_ptr, size_t *buflen_ptr, ssize_t nghttp2_frame_pack_ping(nghttp2_buf *buf, nghttp2_ping *frame);
nghttp2_ping *frame);
/* /*
* Unpacks PING wire format into |frame|. * Unpacks PING wire format into |frame|.
@ -326,9 +309,8 @@ void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
/* /*
* Packs GOAWAY frame |frame | in wire format and store it in * Packs GOAWAY frame |frame | in wire format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| * |buf|. This function expands |buf| as necessary to store given
* length. This function expands |*buf_ptr| as necessary to store * |frame|.
* given |frame|.
* *
* This function returns 0 if it succeeds or one of the following * This function returns 0 if it succeeds or one of the following
* negative error codes: * negative error codes:
@ -336,8 +318,7 @@ void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory. * Out of memory.
*/ */
ssize_t nghttp2_frame_pack_goaway(uint8_t **buf_ptr, size_t *buflen_ptr, ssize_t nghttp2_frame_pack_goaway(nghttp2_buf *buf, nghttp2_goaway *frame);
nghttp2_goaway *frame);
/* /*
* Unpacks GOAWAY wire format into |frame|. * Unpacks GOAWAY wire format into |frame|.
@ -348,9 +329,8 @@ void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
/* /*
* Packs WINDOW_UPDATE frame |frame| in wire frame format and store it * Packs WINDOW_UPDATE frame |frame| in wire frame format and store it
* in |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| * in |buf|. This function expands |buf| as necessary to store given
* length. This function expands |*buf_ptr| as necessary to store * |frame|.
* given |frame|.
* *
* This function returns the size of packed frame if it succeeds, or * This function returns the size of packed frame if it succeeds, or
* returns one of the following negative error codes: * returns one of the following negative error codes:
@ -358,7 +338,7 @@ void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory. * Out of memory.
*/ */
ssize_t nghttp2_frame_pack_window_update(uint8_t **buf_ptr, size_t *buflen_ptr, ssize_t nghttp2_frame_pack_window_update(nghttp2_buf *buf,
nghttp2_window_update *frame); nghttp2_window_update *frame);
/* /*
@ -508,29 +488,22 @@ void nghttp2_nv_array_del(nghttp2_nv *nva);
int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv); int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
/* /*
* Add padding to the payload in the |*buf_ptr| of length * Sets PAD_HIGH and PAD_LOW fields, flags and adjust buf->pos and
* |*buflen_ptr|. The payload length is given in |payloadlen|. The * buf->last accordingly based on given padding length. The padding is
* frame header starts at offset |*bufoff_ptr|. Therefore, the payload
* must start at offset *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH from
* |*buf_ptr| to account for PAD_HIGH and PAD_LOW. The padding is
* given in the |padlen|. * given in the |padlen|.
* *
* The |*flags_ptr| is updated to include NGHTTP2_FLAG_PAD_LOW and * The |*flags_ptr| is updated to include NGHTTP2_FLAG_PAD_LOW and
* NGHTTP2_FLAG_PAD_HIGH based on the padding length. The * NGHTTP2_FLAG_PAD_HIGH based on the padding length.
* |*bufoff_ptr| will have the offset starting the frame header in
* |*buf_ptr|.
* *
* The |*buf_ptr| and |*buflen_ptr| may be extended to include padding * This function does not allocate memory at all.
* bytes.
* *
* The padding specifier PAD_HIGH and PAD_LOW are located right after * The padding specifier PAD_HIGH and PAD_LOW are located right after
* the frame header. But they may not be there depending of the length * the frame header. But they may not be there depending of the length
* of the padding. To save the additional buffer copy, we allocate * of the padding. To save the additional buffer copy, we shift
* buffer size as if these 2 bytes always exist. Depending of the * buf->pos to 2 bytes right before this call. Depending of the length
* length of the padding, we move the location of frame header and * of the padding, we shift left buf->pos and buf->last. If more than
* adjust |*bufoff_ptr|. If more than or equal to 256 padding is made, * or equal to 256 padding is made, 2 left shift is done |buf| looks
* the |*bufoff_ptr| is 0 and the content of the |*buf_ptr| looks like * like this:
* this:
* *
* 0 1 2 3 * 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
@ -543,8 +516,8 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
* +---------------+---------------+-------------------------------+ * +---------------+---------------+-------------------------------+
* *
* *
* If padding is less than 256 but strictly more than 0, the * If padding is less than 256 but strictly more than 0, the |buf| is
* |*bufoff_ptr| is 1 and the |*buf_ptr| looks like this: * 1 left shift and the |buf| looks like this:
* *
* 0 1 2 3 * 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
@ -556,8 +529,8 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
* . Frame Header | Pad low | Payload ... * . Frame Header | Pad low | Payload ...
* +---------------+---------------+-------------------------------+ * +---------------+---------------+-------------------------------+
* *
* If no padding is added, the |*bufoff_ptr| is 2 and the |*buf_ptr| * If no padding is added, no shift is done and the |buf| looks like
* looks like this: * this:
* *
* 0 1 2 3 * 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
@ -571,17 +544,10 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
* *
* Notice that the position of payload does not change. This way, we * Notice that the position of payload does not change. This way, we
* can set PAD_HIGH and PAD_LOW after payload was serialized and no * can set PAD_HIGH and PAD_LOW after payload was serialized and no
* additional copy operation is required (if the |*buf_ptr| is large * additional copy operation is required (if the |buf| is large enough
* enough to account the additional padding, of course). * to account the additional padding, of course).
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/ */
int nghttp2_frame_add_pad(uint8_t **buf_ptr, size_t *buflen_ptr, void nghttp2_frame_set_pad(nghttp2_buf *buf, uint8_t *flags_ptr,
size_t *bufoff_ptr, uint8_t *flags_ptr, size_t padlen);
size_t payloadlen, size_t padlen);
#endif /* NGHTTP2_FRAME_H */ #endif /* NGHTTP2_FRAME_H */

View File

@ -436,17 +436,21 @@ static int emit_indname_header(nghttp2_nv *nv_out, nghttp2_hd_entry *ent,
return 0; return 0;
} }
static int ensure_write_buffer(uint8_t **buf_ptr, size_t *buflen_ptr, static int ensure_write_buffer(nghttp2_buf *buf, size_t need)
size_t offset, size_t need)
{ {
int rv; int rv;
if(need + offset > NGHTTP2_HD_MAX_BUFFER_LENGTH) {
need += nghttp2_buf_last_offset(buf);
if(need > NGHTTP2_HD_MAX_BUFFER_LENGTH) {
return NGHTTP2_ERR_HEADER_COMP; return NGHTTP2_ERR_HEADER_COMP;
} }
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, offset + need);
rv = nghttp2_buf_reserve(buf, need);
if(rv != 0) { if(rv != 0) {
return NGHTTP2_ERR_NOMEM; return NGHTTP2_ERR_NOMEM;
} }
return 0; return 0;
} }
@ -556,55 +560,68 @@ static uint8_t* decode_length(ssize_t *res, int *final, ssize_t initial,
return in + 1; return in + 1;
} }
static int emit_clear_refset(uint8_t **buf_ptr, size_t *buflen_ptr, static int emit_clear_refset(nghttp2_buf *buf)
size_t *offset_ptr)
{ {
int rv; int rv;
uint8_t *bufp; uint8_t *bufp;
rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, 2);
rv = ensure_write_buffer(buf, 2);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
bufp = *buf_ptr + *offset_ptr;
bufp = buf->last;
*bufp++ = 0x80u; *bufp++ = 0x80u;
*bufp = 0x80u; *bufp++ = 0x80u;
*offset_ptr += 2;
buf->last = bufp;
return 0; return 0;
} }
static int emit_table_size(uint8_t **buf_ptr, size_t *buflen_ptr, static int emit_table_size(nghttp2_buf *buf, size_t table_size)
size_t *offset_ptr, size_t table_size)
{ {
int rv; int rv;
uint8_t *bufp; uint8_t *bufp;
size_t blocklen = 1 + count_encoded_length(table_size, 7); size_t blocklen;
rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, blocklen);
blocklen = 1 + count_encoded_length(table_size, 7);
rv = ensure_write_buffer(buf, blocklen);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
DEBUGF(fprintf(stderr, "emit table_size=%zu\n", table_size)); DEBUGF(fprintf(stderr, "emit table_size=%zu\n", table_size));
bufp = *buf_ptr + *offset_ptr;
bufp = buf->last;
*bufp++ = 0x80u; *bufp++ = 0x80u;
*bufp = 0; *bufp = 0;
encode_length(bufp, table_size, 7); encode_length(bufp, table_size, 7);
*offset_ptr += blocklen;
buf->last += blocklen;
return 0; return 0;
} }
static int emit_indexed_block(uint8_t **buf_ptr, size_t *buflen_ptr, static int emit_indexed_block(nghttp2_buf *buf, size_t index)
size_t *offset_ptr, size_t index)
{ {
int rv; int rv;
uint8_t *bufp; size_t blocklen;
size_t blocklen = count_encoded_length(index + 1, 7);
rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, blocklen); blocklen = count_encoded_length(index + 1, 7);
rv = ensure_write_buffer(buf, blocklen);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
bufp = *buf_ptr + *offset_ptr;
*bufp = 0x80u; *buf->last = 0x80u;
encode_length(bufp, index + 1, 7); encode_length(buf->last, index + 1, 7);
*offset_ptr += blocklen;
buf->last += blocklen;
return 0; return 0;
} }
@ -613,6 +630,7 @@ static size_t emit_string(uint8_t *buf, size_t buflen,
const uint8_t *str, size_t len) const uint8_t *str, size_t len)
{ {
size_t rv; size_t rv;
*buf = huffman ? 1 << 7 : 0; *buf = huffman ? 1 << 7 : 0;
rv = encode_length(buf, enclen, 7); rv = encode_length(buf, enclen, 7);
buf += rv; buf += rv;
@ -625,66 +643,89 @@ static size_t emit_string(uint8_t *buf, size_t buflen,
return rv + enclen; return rv + enclen;
} }
static int emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr, static int emit_indname_block(nghttp2_buf *buf, size_t index,
size_t *offset_ptr, size_t index,
const uint8_t *value, size_t valuelen, const uint8_t *value, size_t valuelen,
int inc_indexing) int inc_indexing)
{ {
int rv; int rv;
uint8_t *bufp; uint8_t *bufp;
size_t encvallen = nghttp2_hd_huff_encode_count(value, valuelen); size_t encvallen;
size_t blocklen = count_encoded_length(index + 1, 6); size_t blocklen;
int huffman = encvallen < valuelen; int huffman;
encvallen = nghttp2_hd_huff_encode_count(value, valuelen);
blocklen = count_encoded_length(index + 1, 6);
huffman = encvallen < valuelen;
if(!huffman) { if(!huffman) {
encvallen = valuelen; encvallen = valuelen;
} }
blocklen += count_encoded_length(encvallen, 7) + encvallen; blocklen += count_encoded_length(encvallen, 7) + encvallen;
rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, blocklen);
rv = ensure_write_buffer(buf, blocklen);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
bufp = *buf_ptr + *offset_ptr;
bufp = buf->last;
*bufp = inc_indexing ? 0 : 0x40u; *bufp = inc_indexing ? 0 : 0x40u;
bufp += encode_length(bufp, index + 1, 6); bufp += encode_length(bufp, index + 1, 6);
bufp += emit_string(bufp, *buflen_ptr - (bufp - *buf_ptr), bufp += emit_string(bufp, buf->end - bufp,
encvallen, huffman, value, valuelen); encvallen, huffman, value, valuelen);
assert(bufp - (*buf_ptr + *offset_ptr) == (ssize_t)blocklen);
*offset_ptr += blocklen; assert(bufp - buf->last == (ssize_t)blocklen);
buf->last = bufp;
return 0; return 0;
} }
static int emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr, static int emit_newname_block(nghttp2_buf *buf, nghttp2_nv *nv,
size_t *offset_ptr, nghttp2_nv *nv,
int inc_indexing) int inc_indexing)
{ {
int rv; int rv;
uint8_t *bufp; uint8_t *bufp;
size_t encnamelen = size_t encnamelen;
nghttp2_hd_huff_encode_count(nv->name, nv->namelen); size_t encvallen;
size_t encvallen = size_t blocklen;
nghttp2_hd_huff_encode_count(nv->value, nv->valuelen); int name_huffman;
size_t blocklen = 1; int value_huffman;
int name_huffman = encnamelen < nv->namelen;
int value_huffman = encvallen < nv->valuelen; encnamelen = nghttp2_hd_huff_encode_count(nv->name, nv->namelen);
encvallen = nghttp2_hd_huff_encode_count(nv->value, nv->valuelen);
blocklen = 1;
name_huffman = encnamelen < nv->namelen;
value_huffman = encvallen < nv->valuelen;
if(!name_huffman) { if(!name_huffman) {
encnamelen = nv->namelen; encnamelen = nv->namelen;
} }
if(!value_huffman) { if(!value_huffman) {
encvallen = nv->valuelen; encvallen = nv->valuelen;
} }
blocklen += count_encoded_length(encnamelen, 7) + encnamelen + blocklen += count_encoded_length(encnamelen, 7) + encnamelen +
count_encoded_length(encvallen, 7) + encvallen; count_encoded_length(encvallen, 7) + encvallen;
rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, blocklen);
rv = ensure_write_buffer(buf, blocklen);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
bufp = *buf_ptr + *offset_ptr;
bufp = buf->last;
*bufp++ = inc_indexing ? 0 : 0x40u; *bufp++ = inc_indexing ? 0 : 0x40u;
bufp += emit_string(bufp, *buflen_ptr - (bufp - *buf_ptr), bufp += emit_string(bufp, buf->end - bufp,
encnamelen, name_huffman, nv->name, nv->namelen); encnamelen, name_huffman, nv->name, nv->namelen);
bufp += emit_string(bufp, *buflen_ptr - (bufp - *buf_ptr), bufp += emit_string(bufp, buf->end - bufp,
encvallen, value_huffman, nv->value, nv->valuelen); encvallen, value_huffman, nv->value, nv->valuelen);
*offset_ptr += blocklen;
assert(bufp - buf->last == (ssize_t)blocklen);
buf->last = bufp;
return 0; return 0;
} }
@ -692,15 +733,12 @@ static int emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
* Emit common header with |index| by toggle off and on (thus 2 * Emit common header with |index| by toggle off and on (thus 2
* indexed representation emissions). * indexed representation emissions).
*/ */
static int emit_implicit(uint8_t **buf_ptr, static int emit_implicit(nghttp2_buf *buf, size_t index)
size_t *buflen_ptr,
size_t *offset_ptr,
size_t index)
{ {
int i; int i, rv;
int rv;
for(i = 0; i < 2; ++i) { for(i = 0; i < 2; ++i) {
rv = emit_indexed_block(buf_ptr, buflen_ptr, offset_ptr, index); rv = emit_indexed_block(buf, index);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
@ -709,26 +747,29 @@ static int emit_implicit(uint8_t **buf_ptr,
} }
static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context, static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context,
uint8_t **buf_ptr, nghttp2_buf *buf,
size_t *buflen_ptr,
size_t *offset_ptr,
nghttp2_nv *nv, nghttp2_nv *nv,
uint8_t entry_flags) uint8_t entry_flags)
{ {
int rv; int rv;
nghttp2_hd_entry *new_ent; nghttp2_hd_entry *new_ent;
size_t room = entry_room(nv->namelen, nv->valuelen); size_t room;
room = entry_room(nv->namelen, nv->valuelen);
while(context->hd_table_bufsize + room > context->hd_table_bufsize_max && while(context->hd_table_bufsize + room > context->hd_table_bufsize_max &&
context->hd_table.len > 0) { context->hd_table.len > 0) {
size_t index = context->hd_table.len - 1; size_t index = context->hd_table.len - 1;
nghttp2_hd_entry* ent = nghttp2_hd_ringbuf_get(&context->hd_table, index); nghttp2_hd_entry* ent = nghttp2_hd_ringbuf_get(&context->hd_table, index);
context->hd_table_bufsize -= entry_room(ent->nv.namelen, ent->nv.valuelen); context->hd_table_bufsize -= entry_room(ent->nv.namelen, ent->nv.valuelen);
if(context->role == NGHTTP2_HD_ROLE_DEFLATE) { if(context->role == NGHTTP2_HD_ROLE_DEFLATE) {
if(ent->flags & NGHTTP2_HD_FLAG_IMPLICIT_EMIT) { if(ent->flags & NGHTTP2_HD_FLAG_IMPLICIT_EMIT) {
/* Emit common header just before it slips away from the /* Emit common header just before it slips away from the
table. If we don't do this, we have to emit it in literal table. If we don't do this, we have to emit it in literal
representation which hurts compression. */ representation which hurts compression. */
rv = emit_implicit(buf_ptr, buflen_ptr, offset_ptr, index); rv = emit_implicit(buf, index);
if(rv != 0) { if(rv != 0) {
return NULL; return NULL;
} }
@ -948,24 +989,25 @@ static int hd_deflate_should_indexing(nghttp2_hd_deflater *deflater,
} }
static int deflate_nv(nghttp2_hd_deflater *deflater, static int deflate_nv(nghttp2_hd_deflater *deflater,
uint8_t **buf_ptr, size_t *buflen_ptr, nghttp2_buf *buf, nghttp2_nv *nv)
size_t *offset_ptr,
nghttp2_nv *nv)
{ {
int rv; int rv;
nghttp2_hd_entry *ent; nghttp2_hd_entry *ent;
search_result res; search_result res;
res = search_hd_table(&deflater->ctx, nv); res = search_hd_table(&deflater->ctx, nv);
if(res.index != -1 && res.name_value_match) { if(res.index != -1 && res.name_value_match) {
size_t index = res.index; size_t index = res.index;
ent = nghttp2_hd_table_get(&deflater->ctx, index); ent = nghttp2_hd_table_get(&deflater->ctx, index);
if(index >= deflater->ctx.hd_table.len) { if(index >= deflater->ctx.hd_table.len) {
nghttp2_hd_entry *new_ent; nghttp2_hd_entry *new_ent;
/* It is important to first add entry to the header table and /* It is important to first add entry to the header table and
let eviction go. If NGHTTP2_HD_FLAG_IMPLICIT_EMIT entry is let eviction go. If NGHTTP2_HD_FLAG_IMPLICIT_EMIT entry is
evicted, it must be emitted before the |nv|. */ evicted, it must be emitted before the |nv|. */
new_ent = add_hd_table_incremental(&deflater->ctx, buf_ptr, buflen_ptr, new_ent = add_hd_table_incremental(&deflater->ctx, buf, &ent->nv,
offset_ptr, &ent->nv,
NGHTTP2_HD_FLAG_NONE); NGHTTP2_HD_FLAG_NONE);
if(!new_ent) { if(!new_ent) {
return NGHTTP2_ERR_HEADER_COMP; return NGHTTP2_ERR_HEADER_COMP;
@ -979,13 +1021,13 @@ static int deflate_nv(nghttp2_hd_deflater *deflater,
set */ set */
new_ent->flags |= NGHTTP2_HD_FLAG_EMIT; new_ent->flags |= NGHTTP2_HD_FLAG_EMIT;
} }
rv = emit_indexed_block(buf_ptr, buflen_ptr, offset_ptr, index); rv = emit_indexed_block(buf, index);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
} else if((ent->flags & NGHTTP2_HD_FLAG_REFSET) == 0) { } else if((ent->flags & NGHTTP2_HD_FLAG_REFSET) == 0) {
ent->flags |= NGHTTP2_HD_FLAG_REFSET | NGHTTP2_HD_FLAG_EMIT; ent->flags |= NGHTTP2_HD_FLAG_REFSET | NGHTTP2_HD_FLAG_EMIT;
rv = emit_indexed_block(buf_ptr, buflen_ptr, offset_ptr, index); rv = emit_indexed_block(buf, index);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
@ -1015,7 +1057,7 @@ static int deflate_nv(nghttp2_hd_deflater *deflater,
ent->flags |= NGHTTP2_HD_FLAG_IMPLICIT_EMIT; ent->flags |= NGHTTP2_HD_FLAG_IMPLICIT_EMIT;
} }
for(; num_emits > 0; --num_emits) { for(; num_emits > 0; --num_emits) {
rv = emit_indexed_block(buf_ptr, buflen_ptr, offset_ptr, index); rv = emit_indexed_block(buf, index);
if(rv != 0) { if(rv != 0) {
break; break;
} }
@ -1033,12 +1075,10 @@ static int deflate_nv(nghttp2_hd_deflater *deflater,
nghttp2_nv nv_indname; nghttp2_nv nv_indname;
nv_indname = *nv; nv_indname = *nv;
nv_indname.name = nghttp2_hd_table_get(&deflater->ctx, index)->nv.name; nv_indname.name = nghttp2_hd_table_get(&deflater->ctx, index)->nv.name;
new_ent = add_hd_table_incremental(&deflater->ctx, buf_ptr, buflen_ptr, new_ent = add_hd_table_incremental(&deflater->ctx, buf, &nv_indname,
offset_ptr, &nv_indname,
NGHTTP2_HD_FLAG_VALUE_ALLOC); NGHTTP2_HD_FLAG_VALUE_ALLOC);
} else { } else {
new_ent = add_hd_table_incremental(&deflater->ctx, buf_ptr, buflen_ptr, new_ent = add_hd_table_incremental(&deflater->ctx, buf, nv,
offset_ptr, nv,
NGHTTP2_HD_FLAG_NAME_ALLOC | NGHTTP2_HD_FLAG_NAME_ALLOC |
NGHTTP2_HD_FLAG_VALUE_ALLOC); NGHTTP2_HD_FLAG_VALUE_ALLOC);
} }
@ -1056,10 +1096,9 @@ static int deflate_nv(nghttp2_hd_deflater *deflater,
incidx = 1; incidx = 1;
} }
if(index == -1) { if(index == -1) {
rv = emit_newname_block(buf_ptr, buflen_ptr, offset_ptr, nv, incidx); rv = emit_newname_block(buf, nv, incidx);
} else { } else {
rv = emit_indname_block(buf_ptr, buflen_ptr, offset_ptr, index, rv = emit_indname_block(buf, index, nv->value, nv->valuelen, incidx);
nv->value, nv->valuelen, incidx);
} }
if(rv != 0) { if(rv != 0) {
return rv; return rv;
@ -1070,42 +1109,44 @@ static int deflate_nv(nghttp2_hd_deflater *deflater,
static int deflate_post_process_hd_entry(nghttp2_hd_entry *ent, static int deflate_post_process_hd_entry(nghttp2_hd_entry *ent,
size_t index, size_t index,
uint8_t **buf_ptr, nghttp2_buf *buf)
size_t *buflen_ptr,
size_t *offset_ptr)
{ {
int rv; int rv;
if((ent->flags & NGHTTP2_HD_FLAG_REFSET) && if((ent->flags & NGHTTP2_HD_FLAG_REFSET) &&
(ent->flags & NGHTTP2_HD_FLAG_IMPLICIT_EMIT) == 0 && (ent->flags & NGHTTP2_HD_FLAG_IMPLICIT_EMIT) == 0 &&
(ent->flags & NGHTTP2_HD_FLAG_EMIT) == 0) { (ent->flags & NGHTTP2_HD_FLAG_EMIT) == 0) {
/* This entry is not present in the current header set and must /* This entry is not present in the current header set and must
be removed. */ be removed. */
ent->flags ^= NGHTTP2_HD_FLAG_REFSET; ent->flags ^= NGHTTP2_HD_FLAG_REFSET;
rv = emit_indexed_block(buf_ptr, buflen_ptr, offset_ptr, index);
rv = emit_indexed_block(buf, index);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
} }
ent->flags &= ~(NGHTTP2_HD_FLAG_EMIT | NGHTTP2_HD_FLAG_IMPLICIT_EMIT); ent->flags &= ~(NGHTTP2_HD_FLAG_EMIT | NGHTTP2_HD_FLAG_IMPLICIT_EMIT);
return 0; return 0;
} }
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
uint8_t **buf_ptr, size_t *buflen_ptr, nghttp2_buf *buf,
size_t nv_offset,
nghttp2_nv *nv, size_t nvlen) nghttp2_nv *nv, size_t nvlen)
{ {
size_t i, offset; size_t i;
int rv = 0; int rv = 0;
assert(nghttp2_buf_len(buf) == 0);
if(deflater->ctx.bad) { if(deflater->ctx.bad) {
return NGHTTP2_ERR_HEADER_COMP; return NGHTTP2_ERR_HEADER_COMP;
} }
offset = nv_offset;
if(deflater->ctx.hd_table_bufsize_max > if(deflater->ctx.hd_table_bufsize_max >
deflater->deflate_hd_table_bufsize_max) { deflater->deflate_hd_table_bufsize_max) {
rv = emit_table_size(buf_ptr, buflen_ptr, &offset, rv = emit_table_size(buf, deflater->deflate_hd_table_bufsize_max);
deflater->deflate_hd_table_bufsize_max);
if(rv != 0) { if(rv != 0) {
goto fail; goto fail;
} }
@ -1114,26 +1155,28 @@ ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
} }
if(deflater->no_refset) { if(deflater->no_refset) {
rv = emit_clear_refset(buf_ptr, buflen_ptr, &offset); rv = emit_clear_refset(buf);
if(rv != 0) { if(rv != 0) {
goto fail; goto fail;
} }
clear_refset(&deflater->ctx); clear_refset(&deflater->ctx);
} }
for(i = 0; i < nvlen; ++i) { for(i = 0; i < nvlen; ++i) {
rv = deflate_nv(deflater, buf_ptr, buflen_ptr, &offset, &nv[i]); rv = deflate_nv(deflater, buf, &nv[i]);
if(rv != 0) { if(rv != 0) {
goto fail; goto fail;
} }
} }
for(i = 0; i < deflater->ctx.hd_table.len; ++i) { for(i = 0; i < deflater->ctx.hd_table.len; ++i) {
nghttp2_hd_entry *ent = nghttp2_hd_ringbuf_get(&deflater->ctx.hd_table, i); nghttp2_hd_entry *ent = nghttp2_hd_ringbuf_get(&deflater->ctx.hd_table, i);
rv = deflate_post_process_hd_entry(ent, i, buf_ptr, buflen_ptr, &offset);
rv = deflate_post_process_hd_entry(ent, i, buf);
if(rv != 0) { if(rv != 0) {
goto fail; goto fail;
} }
} }
return offset - nv_offset;
return nghttp2_buf_len(buf);
fail: fail:
deflater->ctx.bad = 1; deflater->ctx.bad = 1;
return rv; return rv;
@ -1259,8 +1302,8 @@ static int hd_inflate_commit_indexed(nghttp2_hd_inflater *inflater,
nghttp2_hd_entry *ent = nghttp2_hd_table_get(&inflater->ctx, inflater->index); nghttp2_hd_entry *ent = nghttp2_hd_table_get(&inflater->ctx, inflater->index);
if(inflater->index >= inflater->ctx.hd_table.len) { if(inflater->index >= inflater->ctx.hd_table.len) {
nghttp2_hd_entry *new_ent; nghttp2_hd_entry *new_ent;
new_ent = add_hd_table_incremental(&inflater->ctx, NULL, NULL, NULL, new_ent = add_hd_table_incremental(&inflater->ctx, NULL, &ent->nv,
&ent->nv, NGHTTP2_HD_FLAG_NONE); NGHTTP2_HD_FLAG_NONE);
if(!new_ent) { if(!new_ent) {
return NGHTTP2_ERR_NOMEM; return NGHTTP2_ERR_NOMEM;
} }
@ -1307,8 +1350,7 @@ static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater,
uint8_t ent_flags = uint8_t ent_flags =
NGHTTP2_HD_FLAG_NAME_ALLOC | NGHTTP2_HD_FLAG_VALUE_ALLOC | NGHTTP2_HD_FLAG_NAME_ALLOC | NGHTTP2_HD_FLAG_VALUE_ALLOC |
NGHTTP2_HD_FLAG_NAME_GIFT | NGHTTP2_HD_FLAG_VALUE_GIFT; NGHTTP2_HD_FLAG_NAME_GIFT | NGHTTP2_HD_FLAG_VALUE_GIFT;
new_ent = add_hd_table_incremental(&inflater->ctx, NULL, NULL, NULL, &nv, new_ent = add_hd_table_incremental(&inflater->ctx, NULL, &nv, ent_flags);
ent_flags);
if(new_ent) { if(new_ent) {
nghttp2_buffer_release(&inflater->namebuf); nghttp2_buffer_release(&inflater->namebuf);
nghttp2_buffer_release(&inflater->valuebuf); nghttp2_buffer_release(&inflater->valuebuf);
@ -1357,10 +1399,8 @@ static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater,
nv.namelen = inflater->ent_name->nv.namelen; nv.namelen = inflater->ent_name->nv.namelen;
nv.value = inflater->valuebuf.buf; nv.value = inflater->valuebuf.buf;
nv.valuelen = inflater->valuebuf.len; nv.valuelen = inflater->valuebuf.len;
new_ent = add_hd_table_incremental(&inflater->ctx, NULL, NULL, NULL, &nv, new_ent = add_hd_table_incremental(&inflater->ctx, NULL, &nv, ent_flags);
ent_flags);
if(!static_name && --inflater->ent_name->ref == 0) { if(!static_name && --inflater->ent_name->ref == 0) {
fprintf(stderr, "index=%zu, len=%zu\n", inflater->index, inflater->ctx.hd_table.len);
nghttp2_hd_entry_free(inflater->ent_name); nghttp2_hd_entry_free(inflater->ent_name);
free(inflater->ent_name); free(inflater->ent_name);
} }
@ -1693,24 +1733,20 @@ int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater)
return 0; return 0;
} }
int nghttp2_hd_emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr, int nghttp2_hd_emit_indname_block(nghttp2_buf *buf, size_t index,
size_t *offset_ptr, size_t index,
const uint8_t *value, size_t valuelen, const uint8_t *value, size_t valuelen,
int inc_indexing) int inc_indexing)
{ {
return emit_indname_block(buf_ptr, buflen_ptr, offset_ptr, return emit_indname_block(buf, index, value, valuelen, inc_indexing);
index, value, valuelen, inc_indexing);
} }
int nghttp2_hd_emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr, int nghttp2_hd_emit_newname_block(nghttp2_buf *buf, nghttp2_nv *nv,
size_t *offset_ptr, nghttp2_nv *nv,
int inc_indexing) int inc_indexing)
{ {
return emit_newname_block(buf_ptr, buflen_ptr, offset_ptr, nv, inc_indexing); return emit_newname_block(buf, nv, inc_indexing);
} }
int nghttp2_hd_emit_table_size(uint8_t **buf_ptr, size_t *buflen_ptr, int nghttp2_hd_emit_table_size(nghttp2_buf *buf, size_t table_size)
size_t *offset_ptr, size_t table_size)
{ {
return emit_table_size(buf_ptr, buflen_ptr, offset_ptr, table_size); return emit_table_size(buf, table_size);
} }

View File

@ -33,6 +33,7 @@
#include "nghttp2_hd_huffman.h" #include "nghttp2_hd_huffman.h"
#include "nghttp2_buffer.h" #include "nghttp2_buffer.h"
#include "nghttp2_buf.h"
#define NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE (1 << 12) #define NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE (1 << 12)
#define NGHTTP2_HD_ENTRY_OVERHEAD 32 #define NGHTTP2_HD_ENTRY_OVERHEAD 32
@ -295,16 +296,13 @@ int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater,
/* /*
* Deflates the |nva|, which has the |nvlen| name/value pairs, into * Deflates the |nva|, which has the |nvlen| name/value pairs, into
* the buffer pointed by the |*buf_ptr| with the length |*buflen_ptr|. * the buffer pointed by the |buf|. The caller must ensure that
* The output starts after |nv_offset| bytes from |*buf_ptr|. * nghttp2_buf_len(buf) == 0 holds. Write starts at buf->last.
* *
* This function expands |*buf_ptr| as necessary to store the * This function expands |buf| as necessary to store the result.
* result. When expansion occurred, memory previously pointed by
* |*buf_ptr| may change. |*buf_ptr| and |*buflen_ptr| are updated
* accordingly.
* *
* This function copies necessary data into |*buf_ptr|. After this * This function copies necessary data into |buf|. After this function
* function returns, it is safe to delete the |nva|. * returns, it is safe to delete the |nva|.
* *
* TODO: The rest of the code call nghttp2_hd_end_headers() after this * TODO: The rest of the code call nghttp2_hd_end_headers() after this
* call, but it is just a regacy of the first implementation. Now it * call, but it is just a regacy of the first implementation. Now it
@ -319,8 +317,7 @@ int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater,
* Deflation process has failed. * Deflation process has failed.
*/ */
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
uint8_t **buf_ptr, size_t *buflen_ptr, nghttp2_buf *buf,
size_t nv_offset,
nghttp2_nv *nva, size_t nvlen); nghttp2_nv *nva, size_t nvlen);
typedef enum { typedef enum {
@ -373,19 +370,16 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater); int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater);
/* For unittesting purpose */ /* For unittesting purpose */
int nghttp2_hd_emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr, int nghttp2_hd_emit_indname_block(nghttp2_buf *buf, size_t index,
size_t *offset_ptr, size_t index,
const uint8_t *value, size_t valuelen, const uint8_t *value, size_t valuelen,
int inc_indexing); int inc_indexing);
/* For unittesting purpose */ /* For unittesting purpose */
int nghttp2_hd_emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr, int nghttp2_hd_emit_newname_block(nghttp2_buf *buf, nghttp2_nv *nv,
size_t *offset_ptr, nghttp2_nv *nv,
int inc_indexing); int inc_indexing);
/* For unittesting purpose */ /* For unittesting purpose */
int nghttp2_hd_emit_table_size(uint8_t **buf_ptr, size_t *buflen_ptr, int nghttp2_hd_emit_table_size(nghttp2_buf *buf, size_t table_size);
size_t *offset_ptr, size_t table_size);
/* For unittesting purpose */ /* For unittesting purpose */
nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context, nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context,

View File

@ -382,3 +382,10 @@ int nghttp2_check_header_value(const uint8_t *value, size_t len)
} }
return 1; return 1;
} }
uint8_t* nghttp2_cpymem(uint8_t *dest, uint8_t *src, size_t len)
{
memcpy(dest, src, len);
return dest + len;
}

View File

@ -126,4 +126,11 @@ int nghttp2_should_send_window_update(int32_t local_window_size,
*/ */
void nghttp2_free(void *ptr); void nghttp2_free(void *ptr);
/*
* Copies the buffer |src| of length |len| to the destination pointed
* by the |dest|, assuming that the |dest| is at lest |len| bytes long
* . Returns dest + len.
*/
uint8_t* nghttp2_cpymem(uint8_t *dest, uint8_t *src, size_t len);
#endif /* NGHTTP2_HELPER_H */ #endif /* NGHTTP2_HELPER_H */

View File

@ -211,7 +211,7 @@ static void nghttp2_active_outbound_item_reset
nghttp2_outbound_item_free(aob->item); nghttp2_outbound_item_free(aob->item);
free(aob->item); free(aob->item);
aob->item = NULL; aob->item = NULL;
aob->framebuflen = aob->framebufoff = aob->framebufmark = 0; nghttp2_buf_reset(&aob->framebuf);
aob->state = NGHTTP2_OB_POP_ITEM; aob->state = NGHTTP2_OB_POP_ITEM;
} }
@ -290,13 +290,12 @@ static int nghttp2_session_new(nghttp2_session **session_ptr,
(*session_ptr)->server = 1; (*session_ptr)->server = 1;
} }
(*session_ptr)->aob.framebuf = malloc rv = nghttp2_buf_init2(&(*session_ptr)->aob.framebuf,
(NGHTTP2_INITIAL_OUTBOUND_FRAMEBUF_LENGTH); NGHTTP2_INITIAL_OUTBOUND_FRAMEBUF_LENGTH);
if((*session_ptr)->aob.framebuf == NULL) { if(rv != 0) {
rv = NGHTTP2_ERR_NOMEM;
goto fail_aob_framebuf; goto fail_aob_framebuf;
} }
(*session_ptr)->aob.framebufmax = NGHTTP2_INITIAL_OUTBOUND_FRAMEBUF_LENGTH;
nghttp2_active_outbound_item_reset(&(*session_ptr)->aob); nghttp2_active_outbound_item_reset(&(*session_ptr)->aob);
memset((*session_ptr)->remote_settings, 0, memset((*session_ptr)->remote_settings, 0,
@ -419,7 +418,7 @@ void nghttp2_session_del(nghttp2_session *session)
nghttp2_hd_deflate_free(&session->hd_deflater); nghttp2_hd_deflate_free(&session->hd_deflater);
nghttp2_hd_inflate_free(&session->hd_inflater); nghttp2_hd_inflate_free(&session->hd_inflater);
nghttp2_active_outbound_item_reset(&session->aob); nghttp2_active_outbound_item_reset(&session->aob);
free(session->aob.framebuf); nghttp2_buf_free(&session->aob.framebuf);
free(session); free(session);
} }
@ -1125,6 +1124,36 @@ static ssize_t session_call_select_padding(nghttp2_session *session,
return frame->hd.length; return frame->hd.length;
} }
static int session_reserve_pad_trail(nghttp2_session *session, size_t padlen)
{
int rv;
nghttp2_active_outbound_item *aob;
if(padlen == 0) {
return 0;
}
aob = &session->aob;
DEBUGF(fprintf(stderr,
"reserving extra %zu padding bytes, including garbage, "
"but adjusted later\n",
padlen));
rv = nghttp2_buf_last_reserve(&aob->framebuf, padlen);
if(nghttp2_is_fatal(rv)) {
return rv;
}
/* We have to zero out padding bytes so that we won't reveal the
possible internal data to the remote peer */
memset(aob->framebuf.last, 0, padlen);
aob->framebuf.last += padlen;
return 0;
}
/* Add padding to HEADERS or PUSH_PROMISE. We use /* Add padding to HEADERS or PUSH_PROMISE. We use
frame->headers.padlen in this function to use the fact that frame->headers.padlen in this function to use the fact that
frame->push_promise has also padlen in the same position. */ frame->push_promise has also padlen in the same position. */
@ -1133,6 +1162,9 @@ static ssize_t session_headers_add_pad(nghttp2_session *session,
{ {
int rv; int rv;
ssize_t padded_payloadlen; ssize_t padded_payloadlen;
nghttp2_active_outbound_item *aob;
aob = &session->aob;
padded_payloadlen = session_call_select_padding(session, frame, padded_payloadlen = session_call_select_padding(session, frame,
frame->hd.length + 1024); frame->hd.length + 1024);
@ -1143,7 +1175,7 @@ static ssize_t session_headers_add_pad(nghttp2_session *session,
frame->headers.padlen = padded_payloadlen - frame->hd.length; frame->headers.padlen = padded_payloadlen - frame->hd.length;
frame->hd.length = padded_payloadlen; frame->hd.length = padded_payloadlen;
DEBUGF(fprintf(stderr, "payloadlen=%zu, padlen=%zu\n", DEBUGF(fprintf(stderr, "padding selected: payloadlen=%zu, padlen=%zu\n",
frame->hd.length, frame->headers.padlen)); frame->hd.length, frame->headers.padlen));
if(frame->hd.length > NGHTTP2_MAX_FRAME_LENGTH) { if(frame->hd.length > NGHTTP2_MAX_FRAME_LENGTH) {
@ -1151,49 +1183,59 @@ static ssize_t session_headers_add_pad(nghttp2_session *session,
hd.flags &= ~NGHTTP2_FLAG_END_HEADERS; hd.flags &= ~NGHTTP2_FLAG_END_HEADERS;
hd.length = NGHTTP2_MAX_FRAME_LENGTH; hd.length = NGHTTP2_MAX_FRAME_LENGTH;
if(NGHTTP2_MAX_FRAME_LENGTH > if(NGHTTP2_MAX_FRAME_LENGTH > frame->hd.length - frame->headers.padlen) {
frame->hd.length - frame->headers.padlen) { size_t padlen;
size_t padlen = NGHTTP2_MAX_FRAME_LENGTH -
padlen = NGHTTP2_MAX_FRAME_LENGTH -
(frame->hd.length - frame->headers.padlen); (frame->hd.length - frame->headers.padlen);
DEBUGF(fprintf(stderr, "padding across 2 frames\n")); DEBUGF(fprintf(stderr, "padding across 2 frames\n"));
DEBUGF(fprintf(stderr, "first HEADERS/PUSH_PROMISE " DEBUGF(fprintf(stderr, "first HEADERS/PUSH_PROMISE "
"payloadlen=%zu, padlen=%zu\n", hd.length, padlen)); "payloadlen=%zu, padlen=%zu\n", hd.length, padlen));
rv = nghttp2_frame_add_pad(&session->aob.framebuf, rv = session_reserve_pad_trail(session, frame->headers.padlen);
&session->aob.framebufmax,
&session->aob.framebufoff,
&hd.flags,
hd.length - padlen,
padlen);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
nghttp2_frame_set_pad(&aob->framebuf, &hd.flags, padlen);
} else { } else {
/* PAD_HIGH and PAD_LOW will be added in /* PAD_HIGH and PAD_LOW will be added in
nghttp2_session_after_frame_sent(). */ nghttp2_session_after_frame_sent(). */
DEBUGF(fprintf(stderr,
"first HEADERS/PUSH_PROMISE does not have "
"padding payloadlen=%zu", hd.length));
/* Ensure that we have allocated buffer */
rv = session_reserve_pad_trail(session, frame->headers.padlen);
if(nghttp2_is_fatal(rv)) {
return rv;
}
} }
nghttp2_frame_pack_frame_hd nghttp2_frame_pack_frame_hd(aob->framebuf.pos, &hd);
(session->aob.framebuf + session->aob.framebufoff, &hd);
/* At this point, framebuflen > session->aob.framebufmax. But
before we access the missing part, we will allocate it in
nghttp2_session_after_frame_sent(). */
} else if(frame->headers.padlen > 0) { } else if(frame->headers.padlen > 0) {
nghttp2_frame_hd hd = frame->hd; nghttp2_frame_hd hd = frame->hd;
rv = nghttp2_frame_add_pad(&session->aob.framebuf,
&session->aob.framebufmax, rv = session_reserve_pad_trail(session, frame->headers.padlen);
&session->aob.framebufoff,
&hd.flags,
frame->hd.length - frame->headers.padlen,
frame->headers.padlen);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
nghttp2_frame_pack_frame_hd
(session->aob.framebuf + session->aob.framebufoff, &hd); DEBUGF(fprintf(stderr,
"first HEADERS/PUSH_PROMISE payloadlen=%zu, padlen=%zu\n",
frame->hd.length, frame->headers.padlen));
nghttp2_frame_set_pad(&aob->framebuf, &hd.flags, frame->headers.padlen);
if(nghttp2_is_fatal(rv)) {
return rv;
}
nghttp2_frame_pack_frame_hd(aob->framebuf.pos, &hd);
} }
return session->aob.framebufoff + NGHTTP2_FRAME_HEAD_LENGTH
+ frame->hd.length; return nghttp2_buf_len(&session->aob.framebuf);
} }
static ssize_t nghttp2_session_prep_frame(nghttp2_session *session, static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
@ -1233,13 +1275,16 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
} }
} }
framebuflen = nghttp2_frame_pack_headers(&session->aob.framebuf, framebuflen = nghttp2_frame_pack_headers(&session->aob.framebuf,
&session->aob.framebufmax,
&session->aob.framebufoff,
&frame->headers, &frame->headers,
&session->hd_deflater); &session->hd_deflater);
if(framebuflen < 0) { if(framebuflen < 0) {
return framebuflen; return framebuflen;
} }
DEBUGF(fprintf(stderr,
"before padding, HEADERS serialized in %zd bytes\n",
nghttp2_buf_len(&session->aob.framebuf)));
framebuflen = session_headers_add_pad(session, frame); framebuflen = session_headers_add_pad(session, frame);
if(framebuflen < 0) { if(framebuflen < 0) {
return framebuflen; return framebuflen;
@ -1266,6 +1311,10 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
default: default:
break; break;
} }
DEBUGF(fprintf(stderr, "HEADERS serialized in %zd bytes\n",
nghttp2_buf_len(&session->aob.framebuf)));
break; break;
} }
case NGHTTP2_PRIORITY: { case NGHTTP2_PRIORITY: {
@ -1275,7 +1324,6 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
return rv; return rv;
} }
framebuflen = nghttp2_frame_pack_priority(&session->aob.framebuf, framebuflen = nghttp2_frame_pack_priority(&session->aob.framebuf,
&session->aob.framebufmax,
&frame->priority); &frame->priority);
if(framebuflen < 0) { if(framebuflen < 0) {
return framebuflen; return framebuflen;
@ -1284,7 +1332,6 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
} }
case NGHTTP2_RST_STREAM: case NGHTTP2_RST_STREAM:
framebuflen = nghttp2_frame_pack_rst_stream(&session->aob.framebuf, framebuflen = nghttp2_frame_pack_rst_stream(&session->aob.framebuf,
&session->aob.framebufmax,
&frame->rst_stream); &frame->rst_stream);
if(framebuflen < 0) { if(framebuflen < 0) {
return framebuflen; return framebuflen;
@ -1296,7 +1343,6 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
return rv; return rv;
} }
framebuflen = nghttp2_frame_pack_settings(&session->aob.framebuf, framebuflen = nghttp2_frame_pack_settings(&session->aob.framebuf,
&session->aob.framebufmax,
&frame->settings); &frame->settings);
if(framebuflen < 0) { if(framebuflen < 0) {
return framebuflen; return framebuflen;
@ -1316,8 +1362,6 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
frame->push_promise.promised_stream_id = session->next_stream_id; frame->push_promise.promised_stream_id = session->next_stream_id;
session->next_stream_id += 2; session->next_stream_id += 2;
framebuflen = nghttp2_frame_pack_push_promise(&session->aob.framebuf, framebuflen = nghttp2_frame_pack_push_promise(&session->aob.framebuf,
&session->aob.framebufmax,
&session->aob.framebufoff,
&frame->push_promise, &frame->push_promise,
&session->hd_deflater); &session->hd_deflater);
if(framebuflen < 0) { if(framebuflen < 0) {
@ -1343,7 +1387,6 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
} }
case NGHTTP2_PING: case NGHTTP2_PING:
framebuflen = nghttp2_frame_pack_ping(&session->aob.framebuf, framebuflen = nghttp2_frame_pack_ping(&session->aob.framebuf,
&session->aob.framebufmax,
&frame->ping); &frame->ping);
if(framebuflen < 0) { if(framebuflen < 0) {
return framebuflen; return framebuflen;
@ -1356,7 +1399,6 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
return rv; return rv;
} }
framebuflen = nghttp2_frame_pack_window_update(&session->aob.framebuf, framebuflen = nghttp2_frame_pack_window_update(&session->aob.framebuf,
&session->aob.framebufmax,
&frame->window_update); &frame->window_update);
if(framebuflen < 0) { if(framebuflen < 0) {
return framebuflen; return framebuflen;
@ -1372,7 +1414,6 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
return NGHTTP2_ERR_GOAWAY_ALREADY_SENT; return NGHTTP2_ERR_GOAWAY_ALREADY_SENT;
} }
framebuflen = nghttp2_frame_pack_goaway(&session->aob.framebuf, framebuflen = nghttp2_frame_pack_goaway(&session->aob.framebuf,
&session->aob.framebufmax,
&frame->goaway); &frame->goaway);
if(framebuflen < 0) { if(framebuflen < 0) {
return framebuflen; return framebuflen;
@ -1403,8 +1444,6 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
} }
framebuflen = nghttp2_session_pack_data(session, framebuflen = nghttp2_session_pack_data(session,
&session->aob.framebuf, &session->aob.framebuf,
&session->aob.framebufmax,
&session->aob.framebufoff,
next_readmax, next_readmax,
data_frame); data_frame);
if(framebuflen == NGHTTP2_ERR_DEFERRED) { if(framebuflen == NGHTTP2_ERR_DEFERRED) {
@ -1516,13 +1555,8 @@ static int session_call_before_frame_send(nghttp2_session *session,
{ {
int rv; int rv;
if(session->callbacks.before_frame_send_callback) { if(session->callbacks.before_frame_send_callback) {
/* Adjust frame length to deal with CONTINUATION frame */
size_t origlen = frame->hd.length;
frame->hd.length =
session->aob.framebuflen - NGHTTP2_FRAME_HEAD_LENGTH;
rv = session->callbacks.before_frame_send_callback(session, frame, rv = session->callbacks.before_frame_send_callback(session, frame,
session->user_data); session->user_data);
frame->hd.length = origlen;
if(rv != 0) { if(rv != 0) {
return NGHTTP2_ERR_CALLBACK_FAILURE; return NGHTTP2_ERR_CALLBACK_FAILURE;
} }
@ -1558,24 +1592,33 @@ static int session_call_on_frame_send(nghttp2_session *session,
static int nghttp2_session_after_frame_sent(nghttp2_session *session) static int nghttp2_session_after_frame_sent(nghttp2_session *session)
{ {
int rv; int rv;
nghttp2_outbound_item *item = session->aob.item; nghttp2_active_outbound_item *aob = &session->aob;
nghttp2_outbound_item *item = aob->item;
nghttp2_buf *framebuf = &aob->framebuf;
if(item->frame_cat == NGHTTP2_CAT_CTRL) { if(item->frame_cat == NGHTTP2_CAT_CTRL) {
nghttp2_frame *frame; nghttp2_frame *frame;
frame = nghttp2_outbound_item_get_ctrl_frame(session->aob.item);
frame = nghttp2_outbound_item_get_ctrl_frame(item);
if(frame->hd.type == NGHTTP2_HEADERS || if(frame->hd.type == NGHTTP2_HEADERS ||
frame->hd.type == NGHTTP2_PUSH_PROMISE) { frame->hd.type == NGHTTP2_PUSH_PROMISE) {
if(session->aob.framebufmark < session->aob.framebuflen) {
if(framebuf->mark < framebuf->last) {
nghttp2_frame_hd cont_hd; nghttp2_frame_hd cont_hd;
cont_hd.length = nghttp2_min(session->aob.framebuflen -
session->aob.framebufmark, cont_hd.length = nghttp2_min(framebuf->last - framebuf->mark,
NGHTTP2_MAX_FRAME_LENGTH); NGHTTP2_MAX_FRAME_LENGTH);
cont_hd.type = NGHTTP2_CONTINUATION; cont_hd.type = NGHTTP2_CONTINUATION;
cont_hd.stream_id = frame->hd.stream_id; cont_hd.stream_id = frame->hd.stream_id;
cont_hd.flags = NGHTTP2_FLAG_NONE;
/* Reuse previous buffers for frame header */ /* Reuse previous buffers for frame header */
session->aob.framebufoff -= NGHTTP2_FRAME_HEAD_LENGTH; framebuf->pos -= NGHTTP2_FRAME_HEAD_LENGTH;
if(cont_hd.length + session->aob.framebufmark ==
session->aob.framebuflen) { if(cont_hd.length + framebuf->mark == framebuf->last) {
size_t padlen; size_t padlen;
if(cont_hd.length < frame->headers.padlen) { if(cont_hd.length < frame->headers.padlen) {
padlen = cont_hd.length; padlen = cont_hd.length;
} else { } else {
@ -1584,34 +1627,41 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
position. */ position. */
padlen = frame->headers.padlen; padlen = frame->headers.padlen;
} }
cont_hd.flags = NGHTTP2_FLAG_END_HEADERS;
DEBUGF(fprintf(stderr, DEBUGF(fprintf(stderr,
"last CONTINUATION payloadlen=%zu, padlen=%zu\n", "last CONTINUATION payloadlen=%zu, padlen=%zu\n",
cont_hd.length, padlen)); cont_hd.length, padlen));
cont_hd.flags = NGHTTP2_FLAG_END_HEADERS; nghttp2_frame_set_pad(framebuf, &cont_hd.flags, padlen);
rv = nghttp2_frame_add_pad(&session->aob.framebuf, framebuf->mark = framebuf->last;
&session->aob.framebufmax,
&session->aob.framebufoff,
&cont_hd.flags,
cont_hd.length - padlen,
padlen);
if(nghttp2_is_fatal(rv)) {
return rv;
}
/* we reuses previous up to 2 bytes for PAD_HIGH and
PAD_LOW. Because of this, session->aob.framebuflen is 1
or 2 bytes longer. Re-compute the value here. */
session->aob.framebuflen = session->aob.framebufmark =
session->aob.framebufoff + NGHTTP2_FRAME_HEAD_LENGTH +
cont_hd.length;
} else { } else {
cont_hd.flags = NGHTTP2_FLAG_NONE; ssize_t padlen;
session->aob.framebufmark += cont_hd.length;
framebuf->mark += cont_hd.length;
padlen = frame->headers.padlen - (framebuf->last - framebuf->mark);
if(padlen > 0) {
/* frame payload includes a part of padding */
DEBUGF(fprintf(stderr,
"padding across 2 CONTINUATION frames. "
"payloadlen=%zu, padlen=%zd\n",
cont_hd.length, padlen));
nghttp2_frame_set_pad(framebuf, &cont_hd.flags, padlen);
framebuf->mark = framebuf->pos + NGHTTP2_FRAME_HDLEN +
cont_hd.length;
} else {
/* If no padding, nothing to be done here */
}
} }
nghttp2_frame_pack_frame_hd(session->aob.framebuf +
session->aob.framebufoff, nghttp2_frame_pack_frame_hd(framebuf->pos, &cont_hd);
&cont_hd);
return 0; return 0;
} }
} }
@ -1754,7 +1804,7 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
nghttp2_outbound_item* next_item; nghttp2_outbound_item* next_item;
nghttp2_stream *stream; nghttp2_stream *stream;
data_frame = nghttp2_outbound_item_get_data_frame(session->aob.item); data_frame = nghttp2_outbound_item_get_data_frame(aob->item);
stream = nghttp2_session_get_stream(session, data_frame->hd.stream_id); stream = nghttp2_session_get_stream(session, data_frame->hd.stream_id);
/* We update flow control window after a frame was completely /* We update flow control window after a frame was completely
sent. This is possible because we choose payload length not to sent. This is possible because we choose payload length not to
@ -1786,7 +1836,7 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
if(data_frame->eof || if(data_frame->eof ||
nghttp2_session_predicate_data_send(session, nghttp2_session_predicate_data_send(session,
data_frame->hd.stream_id) != 0) { data_frame->hd.stream_id) != 0) {
nghttp2_active_outbound_item_reset(&session->aob); nghttp2_active_outbound_item_reset(aob);
return 0; return 0;
} }
/* Assuming stream is not NULL */ /* Assuming stream is not NULL */
@ -1795,30 +1845,27 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
/* If priority of this stream is higher or equal to other stream /* If priority of this stream is higher or equal to other stream
waiting at the top of the queue, we continue to send this waiting at the top of the queue, we continue to send this
data. */ data. */
if(next_item == NULL || session->aob.item->pri < next_item->pri) { if(next_item == NULL || aob->item->pri < next_item->pri) {
size_t next_readmax; size_t next_readmax;
next_readmax = nghttp2_session_next_data_read(session, stream); next_readmax = nghttp2_session_next_data_read(session, stream);
if(next_readmax == 0) { if(next_readmax == 0) {
nghttp2_stream_defer_data(stream, session->aob.item, nghttp2_stream_defer_data(stream, aob->item,
NGHTTP2_DEFERRED_FLOW_CONTROL); NGHTTP2_DEFERRED_FLOW_CONTROL);
session->aob.item = NULL; aob->item = NULL;
nghttp2_active_outbound_item_reset(&session->aob); nghttp2_active_outbound_item_reset(aob);
return 0; return 0;
} }
rv = nghttp2_session_pack_data(session, rv = nghttp2_session_pack_data(session, framebuf, next_readmax,
&session->aob.framebuf,
&session->aob.framebufmax,
&session->aob.framebufoff,
next_readmax,
data_frame); data_frame);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
if(rv == NGHTTP2_ERR_DEFERRED) { if(rv == NGHTTP2_ERR_DEFERRED) {
nghttp2_stream_defer_data(stream, session->aob.item, nghttp2_stream_defer_data(stream, aob->item, NGHTTP2_DEFERRED_NONE);
NGHTTP2_DEFERRED_NONE); aob->item = NULL;
session->aob.item = NULL; nghttp2_active_outbound_item_reset(aob);
nghttp2_active_outbound_item_reset(&session->aob);
return 0; return 0;
} }
if(rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { if(rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
@ -1828,24 +1875,26 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
rv = nghttp2_session_add_rst_stream(session, rv = nghttp2_session_add_rst_stream(session,
data_frame->hd.stream_id, data_frame->hd.stream_id,
NGHTTP2_INTERNAL_ERROR); NGHTTP2_INTERNAL_ERROR);
nghttp2_active_outbound_item_reset(&session->aob); nghttp2_active_outbound_item_reset(aob);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
return 0; return 0;
} }
assert(rv >= 0); assert(rv >= 0);
session->aob.framebuflen = session->aob.framebufmark = rv; framebuf->mark = framebuf->last;
return 0; return 0;
} }
/* Update seq to interleave other streams with the same /* Update seq to interleave other streams with the same
priority. */ priority. */
session->aob.item->seq = session->next_seq++; aob->item->seq = session->next_seq++;
rv = nghttp2_pq_push(&session->ob_pq, session->aob.item); rv = nghttp2_pq_push(&session->ob_pq, aob->item);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
session->aob.item = NULL; aob->item = NULL;
nghttp2_active_outbound_item_reset(&session->aob); nghttp2_active_outbound_item_reset(&session->aob);
return 0; return 0;
} }
@ -1857,10 +1906,15 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session,
const uint8_t **data_ptr) const uint8_t **data_ptr)
{ {
int rv; int rv;
nghttp2_active_outbound_item *aob;
nghttp2_buf *framebuf;
aob = &session->aob;
framebuf = &aob->framebuf;
*data_ptr = NULL; *data_ptr = NULL;
for(;;) { for(;;) {
switch(session->aob.state) { switch(aob->state) {
case NGHTTP2_OB_POP_ITEM: { case NGHTTP2_OB_POP_ITEM: {
nghttp2_outbound_item *item; nghttp2_outbound_item *item;
ssize_t framebuflen; ssize_t framebuflen;
@ -1895,7 +1949,7 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session,
} }
nghttp2_outbound_item_free(item); nghttp2_outbound_item_free(item);
free(item); free(item);
nghttp2_active_outbound_item_reset(&session->aob); nghttp2_active_outbound_item_reset(aob);
if(framebuflen == NGHTTP2_ERR_HEADER_COMP) { if(framebuflen == NGHTTP2_ERR_HEADER_COMP) {
/* If header compression error occurred, should terminiate /* If header compression error occurred, should terminiate
@ -1908,32 +1962,43 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session,
} }
break; break;
} }
session->aob.item = item; aob->item = item;
session->aob.framebuflen = framebuflen;
if(item->frame_cat == NGHTTP2_CAT_CTRL) { if(item->frame_cat == NGHTTP2_CAT_CTRL) {
nghttp2_frame *frame = nghttp2_outbound_item_get_ctrl_frame(item); nghttp2_frame *frame;
/* We have to get frame size from headers, because /* We have to get frame size from headers, because
frame->hd.length does not always shows the actual frame frame->hd.length does not always shows the actual frame
size, especially for HEADERS size > size, especially for HEADERS size >
NGHTTP2_MAX_FRAME_LENGTH */ NGHTTP2_MAX_FRAME_LENGTH */
session->aob.framebufmark = frame = nghttp2_outbound_item_get_ctrl_frame(item);
session->aob.framebufoff + NGHTTP2_FRAME_HEAD_LENGTH +
nghttp2_get_uint16(session->aob.framebuf + session->aob.framebufoff); framebuf->mark = framebuf->pos + NGHTTP2_FRAME_HEAD_LENGTH +
nghttp2_get_uint16(framebuf->pos);
rv = session_call_before_frame_send(session, frame); rv = session_call_before_frame_send(session, frame);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
} else { } else {
session->aob.framebufmark = session->aob.framebuflen; framebuf->mark = framebuf->last;
} }
session->aob.state = NGHTTP2_OB_SEND_DATA;
DEBUGF(fprintf(stderr, "start transmitting type %d frame %zd bytes\n",
framebuf->pos[2], framebuf->mark - framebuf->pos));
aob->state = NGHTTP2_OB_SEND_DATA;
break; break;
} }
case NGHTTP2_OB_SEND_DATA: { case NGHTTP2_OB_SEND_DATA: {
size_t datalen; size_t datalen;
if(session->aob.framebufoff == session->aob.framebufmark) { if(framebuf->pos == framebuf->mark) {
DEBUGF(fprintf(stderr, "end transmission of frame, left %zd\n",
framebuf->last - framebuf->mark));
/* Frame has completely sent */ /* Frame has completely sent */
rv = nghttp2_session_after_frame_sent(session); rv = nghttp2_session_after_frame_sent(session);
if(rv < 0) { if(rv < 0) {
@ -1945,11 +2010,11 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session,
break; break;
} }
*data_ptr = session->aob.framebuf + session->aob.framebufoff; *data_ptr = framebuf->pos;
datalen = session->aob.framebufmark - session->aob.framebufoff; datalen = framebuf->mark - framebuf->pos;
/* We increment the offset here. If send_callback does not send /* We increment the offset here. If send_callback does not send
everything, we will adjust it. */ everything, we will adjust it. */
session->aob.framebufoff += datalen; framebuf->pos += datalen;
return datalen; return datalen;
} }
@ -1962,6 +2027,9 @@ int nghttp2_session_send(nghttp2_session *session)
const uint8_t *data; const uint8_t *data;
ssize_t datalen; ssize_t datalen;
ssize_t sentlen; ssize_t sentlen;
nghttp2_buf *framebuf;
framebuf = &session->aob.framebuf;
for(;;) { for(;;) {
datalen = nghttp2_session_mem_send(session, &data); datalen = nghttp2_session_mem_send(session, &data);
@ -1973,13 +2041,14 @@ int nghttp2_session_send(nghttp2_session *session)
if(sentlen < 0) { if(sentlen < 0) {
if(sentlen == NGHTTP2_ERR_WOULDBLOCK) { if(sentlen == NGHTTP2_ERR_WOULDBLOCK) {
/* Transmission canceled. Rewind the offset */ /* Transmission canceled. Rewind the offset */
session->aob.framebufoff -= datalen; framebuf->pos -= datalen;
return 0; return 0;
} }
return NGHTTP2_ERR_CALLBACK_FAILURE; return NGHTTP2_ERR_CALLBACK_FAILURE;
} }
/* Rewind the offset to the amount of unsent bytes */ /* Rewind the offset to the amount of unsent bytes */
session->aob.framebufoff -= datalen - sentlen; framebuf->pos -= datalen - sentlen;
} }
return 0; return 0;
} }
@ -2083,82 +2152,6 @@ static int session_detect_idle_stream(nghttp2_session *session,
return 0; return 0;
} }
/*
* Inflates header block in the memory pointed by |in| with |inlen|
* bytes. If this function returns NGHTTP2_ERR_PAUSE, the caller must
* call this function again, until it returns 0 or one of negative
* error code. If |call_header_cb| is zero, the on_header_callback
* are not invoked and the function never return NGHTTP2_ERR_PAUSE. If
* the given |in| is the last chunk of header block, the |final| must
* be nonzero. If header block is successfully processed (which is
* indicated by the return value 0, NGHTTP2_ERR_PAUSE or
* NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE), the number of processed
* input bytes is assigned to the |*readlen_ptr|.
*
* This function return 0 if it succeeds, or one of the negative error
* codes:
*
* NGHTTP2_ERR_CALLBACK_FAILURE
* The callback function failed.
* NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
* The callback returns this error code, indicating that this
* stream should be RST_STREAMed.
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_PAUSE
* The callback function returned NGHTTP2_ERR_PAUSE
* NGHTTP2_ERR_HEADER_COMP
* Header decompression failed
*/
static ssize_t inflate_header_block(nghttp2_session *session,
nghttp2_frame *frame,
size_t *readlen_ptr,
uint8_t *in, size_t inlen,
int final, int call_header_cb)
{
ssize_t rv;
int inflate_flags;
nghttp2_nv nv;
*readlen_ptr = 0;
DEBUGF(fprintf(stderr, "processing header block %zu bytes\n", inlen));
for(;;) {
inflate_flags = 0;
rv = nghttp2_hd_inflate_hd(&session->hd_inflater, &nv, &inflate_flags,
in, inlen, final);
if(nghttp2_is_fatal(rv)) {
return rv;
}
if(rv < 0) {
rv = nghttp2_session_terminate_session(session,
NGHTTP2_COMPRESSION_ERROR);
if(rv != 0) {
return rv;
}
return NGHTTP2_ERR_HEADER_COMP;
}
in += rv;
inlen -= rv;
*readlen_ptr += rv;
if(call_header_cb && (inflate_flags & NGHTTP2_HD_INFLATE_EMIT)) {
rv = session_call_on_header(session, frame, &nv);
/* This handles NGHTTP2_ERR_PAUSE and
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE as well */
if(rv != 0) {
return rv;
}
}
if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
nghttp2_hd_inflate_end_headers(&session->hd_inflater);
break;
}
if((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && inlen == 0) {
break;
}
}
return 0;
}
/* /*
* Handles frame size error. * Handles frame size error.
* *
@ -2238,6 +2231,87 @@ static int nghttp2_session_inflate_handle_invalid_connection
return NGHTTP2_ERR_IGN_HEADER_BLOCK; return NGHTTP2_ERR_IGN_HEADER_BLOCK;
} }
/*
* Inflates header block in the memory pointed by |in| with |inlen|
* bytes. If this function returns NGHTTP2_ERR_PAUSE, the caller must
* call this function again, until it returns 0 or one of negative
* error code. If |call_header_cb| is zero, the on_header_callback
* are not invoked and the function never return NGHTTP2_ERR_PAUSE. If
* the given |in| is the last chunk of header block, the |final| must
* be nonzero. If header block is successfully processed (which is
* indicated by the return value 0, NGHTTP2_ERR_PAUSE or
* NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE), the number of processed
* input bytes is assigned to the |*readlen_ptr|.
*
* This function return 0 if it succeeds, or one of the negative error
* codes:
*
* NGHTTP2_ERR_CALLBACK_FAILURE
* The callback function failed.
* NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
* The callback returns this error code, indicating that this
* stream should be RST_STREAMed.
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_PAUSE
* The callback function returned NGHTTP2_ERR_PAUSE
* NGHTTP2_ERR_HEADER_COMP
* Header decompression failed
*/
static ssize_t inflate_header_block(nghttp2_session *session,
nghttp2_frame *frame,
size_t *readlen_ptr,
uint8_t *in, size_t inlen,
int final, int call_header_cb)
{
ssize_t rv;
int inflate_flags;
nghttp2_nv nv;
*readlen_ptr = 0;
DEBUGF(fprintf(stderr, "processing header block %zu bytes\n", inlen));
for(;;) {
inflate_flags = 0;
rv = nghttp2_hd_inflate_hd(&session->hd_inflater, &nv, &inflate_flags,
in, inlen, final);
if(nghttp2_is_fatal(rv)) {
return rv;
}
if(rv < 0) {
if(session->iframe.state == NGHTTP2_IB_READ_HEADER_BLOCK) {
rv = nghttp2_session_handle_invalid_connection
(session, frame, NGHTTP2_COMPRESSION_ERROR);
} else {
rv = nghttp2_session_terminate_session(session,
NGHTTP2_COMPRESSION_ERROR);
}
if(rv != 0) {
return rv;
}
return NGHTTP2_ERR_HEADER_COMP;
}
in += rv;
inlen -= rv;
*readlen_ptr += rv;
if(call_header_cb && (inflate_flags & NGHTTP2_HD_INFLATE_EMIT)) {
rv = session_call_on_header(session, frame, &nv);
/* This handles NGHTTP2_ERR_PAUSE and
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE as well */
if(rv != 0) {
return rv;
}
}
if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
nghttp2_hd_inflate_end_headers(&session->hd_inflater);
break;
}
if((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && inlen == 0) {
break;
}
}
return 0;
}
/* /*
* Decompress header blocks of incoming request HEADERS and also call * Decompress header blocks of incoming request HEADERS and also call
* additional callbacks. This function can be called again if this * additional callbacks. This function can be called again if this
@ -4488,48 +4562,53 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
} }
ssize_t nghttp2_session_pack_data(nghttp2_session *session, ssize_t nghttp2_session_pack_data(nghttp2_session *session,
uint8_t **buf_ptr, size_t *buflen_ptr, nghttp2_buf *buf,
size_t *bufoff_ptr,
size_t datamax, size_t datamax,
nghttp2_private_data *frame) nghttp2_private_data *frame)
{ {
size_t payloadoff;
ssize_t framelen; ssize_t framelen;
ssize_t rv; ssize_t rv;
int eof_flags; int eof_flags;
uint8_t flags; uint8_t flags;
ssize_t payloadlen; ssize_t payloadlen;
ssize_t padded_payloadlen; ssize_t padded_payloadlen;
size_t padlen;
nghttp2_frame data_frame; nghttp2_frame data_frame;
nghttp2_frame_hd hd;
/* extra 2 bytes for PAD_HIGH and PAD_LOW. We allocate extra 2 bytes /* extra 2 bytes for PAD_HIGH and PAD_LOW. We allocate extra 2 bytes
for padding. Based on the padding length, we adjust the starting for padding. Based on the padding length, we adjust the starting
offset of frame data. The starting offset is assigned into offset of frame data. The starting offset is assigned into
|*bufoff_ptr|. */ |*bufoff_ptr|. */
*bufoff_ptr = 2; buf->pos += 2;
payloadoff = *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH;
framelen = payloadoff + datamax;
rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, framelen); framelen = NGHTTP2_FRAME_HDLEN + datamax;
rv = nghttp2_buf_pos_reserve(buf, framelen);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
eof_flags = 0; eof_flags = 0;
payloadlen = frame->data_prd.read_callback payloadlen = frame->data_prd.read_callback
(session, frame->hd.stream_id, (*buf_ptr) + payloadoff, datamax, (session, frame->hd.stream_id, buf->pos + NGHTTP2_FRAME_HDLEN, datamax,
&eof_flags, &frame->data_prd.source, session->user_data); &eof_flags, &frame->data_prd.source, session->user_data);
if(payloadlen == NGHTTP2_ERR_DEFERRED || if(payloadlen == NGHTTP2_ERR_DEFERRED ||
payloadlen == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { payloadlen == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
DEBUGF(fprintf(stderr, "DATA postponed due to %s\n", DEBUGF(fprintf(stderr, "DATA postponed due to %s\n",
nghttp2_strerror(payloadlen))); nghttp2_strerror(payloadlen)));
return payloadlen; return payloadlen;
} }
if(payloadlen < 0 || datamax < (size_t)payloadlen) { if(payloadlen < 0 || datamax < (size_t)payloadlen) {
/* This is the error code when callback is failed. */ /* This is the error code when callback is failed. */
return NGHTTP2_ERR_CALLBACK_FAILURE; return NGHTTP2_ERR_CALLBACK_FAILURE;
} }
buf->last = buf->pos + NGHTTP2_FRAME_HDLEN + payloadlen;
/* Clear flags, because this may contain previous flags of previous /* Clear flags, because this may contain previous flags of previous
DATA */ DATA */
frame->hd.flags &= (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_SEGMENT); frame->hd.flags &= (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_SEGMENT);
@ -4545,7 +4624,9 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session,
} }
} }
/* The primary reason of data_frame is pass to the user callback */
memset(&data_frame, 0, sizeof(data_frame)); memset(&data_frame, 0, sizeof(data_frame));
data_frame.hd.length = payloadlen; data_frame.hd.length = payloadlen;
data_frame.hd.stream_id = frame->hd.stream_id; data_frame.hd.stream_id = frame->hd.stream_id;
data_frame.hd.type = NGHTTP2_DATA; data_frame.hd.type = NGHTTP2_DATA;
@ -4556,25 +4637,31 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session,
if(nghttp2_is_fatal(padded_payloadlen)) { if(nghttp2_is_fatal(padded_payloadlen)) {
return padded_payloadlen; return padded_payloadlen;
} }
rv = nghttp2_frame_add_pad(buf_ptr, buflen_ptr, bufoff_ptr, &flags,
payloadlen, padded_payloadlen - payloadlen); padlen = padded_payloadlen - payloadlen;
rv = session_reserve_pad_trail(session, padlen);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
frame->padlen = padded_payloadlen - payloadlen;
nghttp2_frame_set_pad(buf, &flags, padlen);
frame->padlen = padlen;
frame->hd.length = padded_payloadlen; frame->hd.length = padded_payloadlen;
/* Set PAD flags so that we can supply frame to the callback with /* Set PAD flags so that we can supply frame to the callback with
the correct flags */ the correct flags */
frame->hd.flags |= flags; frame->hd.flags |= flags;
memset(*buf_ptr + *bufoff_ptr, 0, NGHTTP2_FRAME_HEAD_LENGTH); memset(buf->pos, 0, NGHTTP2_FRAME_HEAD_LENGTH);
nghttp2_put_uint16be(&(*buf_ptr)[*bufoff_ptr], frame->hd.length);
(*buf_ptr)[*bufoff_ptr + 3] = flags; hd = frame->hd;
nghttp2_put_uint32be(&(*buf_ptr)[*bufoff_ptr + 4], frame->hd.stream_id); hd.flags = flags;
return frame->hd.length + NGHTTP2_FRAME_HEAD_LENGTH + *bufoff_ptr; nghttp2_frame_pack_frame_hd(buf->pos, &hd);
return nghttp2_buf_len(buf);
} }
void* nghttp2_session_get_stream_user_data(nghttp2_session *session, void* nghttp2_session_get_stream_user_data(nghttp2_session *session,

View File

@ -38,6 +38,7 @@
#include "nghttp2_buffer.h" #include "nghttp2_buffer.h"
#include "nghttp2_outbound_item.h" #include "nghttp2_outbound_item.h"
#include "nghttp2_int.h" #include "nghttp2_int.h"
#include "nghttp2_buf.h"
/* /*
* Option flags. * Option flags.
@ -54,27 +55,15 @@ typedef enum {
typedef struct { typedef struct {
nghttp2_outbound_item *item; nghttp2_outbound_item *item;
/* Buffer for outbound frames. Used to pack one frame. The memory
pointed by framebuf is initially allocated by nghttp2_buf framebuf;
nghttp2_session_{client,server}_new() and deallocated by
nghttp2_session_del() */
uint8_t *framebuf;
/* The capacity of framebuf in bytes */
size_t framebufmax;
/* The length of the frame stored in framebuf */
size_t framebuflen;
/* The number of bytes has been sent */
size_t framebufoff;
/* Marks the last position to send. This is used to implement
CONTINUATION */
size_t framebufmark;
nghttp2_outbound_state state; nghttp2_outbound_state state;
} nghttp2_active_outbound_item; } nghttp2_active_outbound_item;
/* Buffer length for inbound raw byte stream. */ /* Buffer length for inbound raw byte stream. */
#define NGHTTP2_INBOUND_BUFFER_LENGTH 16384 #define NGHTTP2_INBOUND_BUFFER_LENGTH 16384
#define NGHTTP2_INITIAL_OUTBOUND_FRAMEBUF_LENGTH 4096 #define NGHTTP2_INITIAL_OUTBOUND_FRAMEBUF_LENGTH 16384
#define NGHTTP2_INITIAL_NV_BUFFER_LENGTH 4096 #define NGHTTP2_INITIAL_NV_BUFFER_LENGTH 4096
@ -538,8 +527,7 @@ nghttp2_stream* nghttp2_session_get_stream(nghttp2_session *session,
* The read_callback failed (session error). * The read_callback failed (session error).
*/ */
ssize_t nghttp2_session_pack_data(nghttp2_session *session, ssize_t nghttp2_session_pack_data(nghttp2_session *session,
uint8_t **buf_ptr, size_t *buflen_ptr, nghttp2_buf *buf,
size_t *bufoff_ptr,
size_t datamax, size_t datamax,
nghttp2_private_data *frame); nghttp2_private_data *frame);

View File

@ -291,8 +291,7 @@ cdef extern from 'nghttp2_hd.h':
size_t hd_table_bufsize_max) size_t hd_table_bufsize_max)
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
uint8_t **buf_ptr, size_t *buflen_ptr, nghttp2_buf *buf,
size_t nv_offset,
nghttp2_nv *nva, size_t nvlen) nghttp2_nv *nva, size_t nvlen)
ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
@ -303,3 +302,14 @@ cdef extern from 'nghttp2_hd.h':
nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context, nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context,
size_t index) size_t index)
cdef extern from 'nghttp2_buf.h':
ctypedef struct nghttp2_buf:
uint8_t *pos
uint8_t *last
void nghttp2_buf_init(nghttp2_buf *buf)
void nghttp2_buf_free(nghttp2_buf *buf)

View File

@ -106,25 +106,36 @@ cdef class HDDeflater:
malloc(sizeof(cnghttp2.nghttp2_nv)*\ malloc(sizeof(cnghttp2.nghttp2_nv)*\
len(headers)) len(headers))
cdef cnghttp2.nghttp2_nv *nvap = nva cdef cnghttp2.nghttp2_nv *nvap = nva
for k, v in headers: for k, v in headers:
nvap[0].name = k nvap[0].name = k
nvap[0].namelen = len(k) nvap[0].namelen = len(k)
nvap[0].value = v nvap[0].value = v
nvap[0].valuelen = len(v) nvap[0].valuelen = len(v)
nvap += 1 nvap += 1
cdef uint8_t *out = NULL
cdef cnghttp2.nghttp2_buf buf
cdef size_t outcap = 0 cdef size_t outcap = 0
cdef ssize_t rv cdef ssize_t rv
rv = cnghttp2.nghttp2_hd_deflate_hd(&self._deflater, &out, &outcap,
0, nva, len(headers)) cnghttp2.nghttp2_buf_init(&buf)
rv = cnghttp2.nghttp2_hd_deflate_hd(&self._deflater, &buf,
nva, len(headers))
free(nva) free(nva)
if rv < 0: if rv < 0:
cnghttp2.nghttp2_buf_free(&buf);
raise Exception(_strerror(rv)) raise Exception(_strerror(rv))
cdef bytes res cdef bytes res
try: try:
res = out[:rv] res = buf.pos[:rv]
finally: finally:
cnghttp2.nghttp2_free(out) cnghttp2.nghttp2_buf_free(&buf)
return res return res
def set_no_refset(self, no_refset): def set_no_refset(self, no_refset):

View File

@ -72,12 +72,15 @@ static void to_hex(char *dest, const uint8_t *src, size_t len)
} }
static void output_to_json(nghttp2_hd_deflater *deflater, static void output_to_json(nghttp2_hd_deflater *deflater,
const uint8_t *buf, size_t len, size_t inputlen, nghttp2_buf *buf, size_t inputlen,
nghttp2_nv *nva, size_t nvlen, nghttp2_nv *nva, size_t nvlen,
int seq) int seq)
{ {
json_t *obj; json_t *obj;
char *hex = NULL; char *hex = NULL;
size_t len;
len = nghttp2_buf_len(buf);
if(len > 0) { if(len > 0) {
hex = malloc(len * 2); hex = malloc(len * 2);
@ -88,7 +91,7 @@ static void output_to_json(nghttp2_hd_deflater *deflater,
json_object_set_new(obj, "output_length", json_integer(len)); json_object_set_new(obj, "output_length", json_integer(len));
json_object_set_new(obj, "percentage_of_original_size", json_object_set_new(obj, "percentage_of_original_size",
json_real((double)len / inputlen * 100)); json_real((double)len / inputlen * 100));
to_hex(hex, buf, len); to_hex(hex, buf->pos, len);
if(len == 0) { if(len == 0) {
json_object_set_new(obj, "wire", json_string("")); json_object_set_new(obj, "wire", json_string(""));
} else { } else {
@ -114,17 +117,21 @@ static void deflate_hd(nghttp2_hd_deflater *deflater,
nghttp2_nv *nva, size_t nvlen, size_t inputlen, int seq) nghttp2_nv *nva, size_t nvlen, size_t inputlen, int seq)
{ {
ssize_t rv; ssize_t rv;
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0;
rv = nghttp2_hd_deflate_hd(deflater, &buf, &buflen, 0, nva, nvlen); nghttp2_buf_init(&buf);
rv = nghttp2_hd_deflate_hd(deflater, &buf, nva, nvlen);
if(rv < 0) { if(rv < 0) {
fprintf(stderr, "deflate failed with error code %zd at %d\n", rv, seq); fprintf(stderr, "deflate failed with error code %zd at %d\n", rv, seq);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
input_sum += inputlen; input_sum += inputlen;
output_sum += rv; output_sum += rv;
output_to_json(deflater, buf, rv, inputlen, nva, nvlen, seq);
free(buf); output_to_json(deflater, &buf, inputlen, nva, nvlen, seq);
nghttp2_buf_free(&buf);
} }
static int deflate_hd_json(json_t *obj, nghttp2_hd_deflater *deflater, int seq) static int deflate_hd_json(json_t *obj, nghttp2_hd_deflater *deflater, int seq)

View File

@ -202,6 +202,12 @@ int main(int argc, char* argv[])
test_nghttp2_session_pack_data_with_padding) || test_nghttp2_session_pack_data_with_padding) ||
!CU_add_test(pSuite, "session_pack_headers_with_padding", !CU_add_test(pSuite, "session_pack_headers_with_padding",
test_nghttp2_session_pack_headers_with_padding) || test_nghttp2_session_pack_headers_with_padding) ||
!CU_add_test(pSuite, "session_pack_headers_with_padding2",
test_nghttp2_session_pack_headers_with_padding2) ||
!CU_add_test(pSuite, "session_pack_headers_with_padding3",
test_nghttp2_session_pack_headers_with_padding3) ||
!CU_add_test(pSuite, "session_pack_headers_with_padding4",
test_nghttp2_session_pack_headers_with_padding4) ||
!CU_add_test(pSuite, "pack_settings_payload", !CU_add_test(pSuite, "pack_settings_payload",
test_nghttp2_pack_settings_payload) || test_nghttp2_pack_settings_payload) ||
!CU_add_test(pSuite, "frame_pack_headers", !CU_add_test(pSuite, "frame_pack_headers",

View File

@ -72,14 +72,14 @@ void test_nghttp2_frame_pack_headers()
nghttp2_hd_deflater deflater; nghttp2_hd_deflater deflater;
nghttp2_hd_inflater inflater; nghttp2_hd_inflater inflater;
nghttp2_headers frame, oframe; nghttp2_headers frame, oframe;
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0;
size_t bufoff;
ssize_t framelen; ssize_t framelen;
nghttp2_nv *nva; nghttp2_nv *nva;
ssize_t nvlen; ssize_t nvlen;
nva_out out; nva_out out;
ssize_t nv_offset; ssize_t hdblocklen;
nghttp2_buf_init(&buf);
nva_out_init(&out); nva_out_init(&out);
nghttp2_hd_deflate_init(&deflater); nghttp2_hd_deflate_init(&deflater);
@ -91,22 +91,22 @@ void test_nghttp2_frame_pack_headers()
NGHTTP2_FLAG_END_STREAM|NGHTTP2_FLAG_END_HEADERS, NGHTTP2_FLAG_END_STREAM|NGHTTP2_FLAG_END_HEADERS,
1000000007, 1000000007,
1 << 20, nva, nvlen); 1 << 20, nva, nvlen);
framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame, framelen = nghttp2_frame_pack_headers(&buf, &frame, &deflater);
&deflater);
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf + bufoff, CU_ASSERT(framelen == nghttp2_buf_len(&buf));
framelen - bufoff)); CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH,
check_frame_header(nghttp2_buf_len(&buf) - NGHTTP2_FRAME_HDLEN,
NGHTTP2_HEADERS, NGHTTP2_HEADERS,
NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS, NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS,
1000000007, &oframe.hd); 1000000007, &oframe.hd);
/* We didn't include PRIORITY flag so priority is not packed */ /* We didn't include PRIORITY flag so priority is not packed */
CU_ASSERT(1 << 30 == oframe.pri); CU_ASSERT(1 << 30 == oframe.pri);
nv_offset = bufoff + NGHTTP2_FRAME_HEAD_LENGTH; hdblocklen = nghttp2_buf_len(&buf) - NGHTTP2_FRAME_HDLEN;
CU_ASSERT(framelen - nv_offset == CU_ASSERT(hdblocklen ==
inflate_hd(&inflater, &out, inflate_hd(&inflater, &out,
buf + nv_offset, framelen - nv_offset)); buf.pos + NGHTTP2_FRAME_HDLEN, hdblocklen));
CU_ASSERT(7 == out.nvlen); CU_ASSERT(7 == out.nvlen);
CU_ASSERT(nvnameeq("method", &out.nva[0])); CU_ASSERT(nvnameeq("method", &out.nva[0]));
@ -114,32 +114,33 @@ void test_nghttp2_frame_pack_headers()
nghttp2_frame_headers_free(&oframe); nghttp2_frame_headers_free(&oframe);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
memset(&oframe, 0, sizeof(oframe)); memset(&oframe, 0, sizeof(oframe));
/* Next, include PRIORITY flag */ /* Next, include PRIORITY flag */
frame.hd.flags |= NGHTTP2_FLAG_PRIORITY; frame.hd.flags |= NGHTTP2_FLAG_PRIORITY;
framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame, framelen = nghttp2_frame_pack_headers(&buf, &frame, &deflater);
&deflater);
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf + bufoff, CU_ASSERT(framelen == nghttp2_buf_len(&buf));
framelen - bufoff)); CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH,
check_frame_header(nghttp2_buf_len(&buf) - NGHTTP2_FRAME_HDLEN,
NGHTTP2_HEADERS, NGHTTP2_HEADERS,
NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS |
NGHTTP2_FLAG_PRIORITY, NGHTTP2_FLAG_PRIORITY,
1000000007, &oframe.hd); 1000000007, &oframe.hd);
CU_ASSERT(1 << 20 == oframe.pri); CU_ASSERT(1 << 20 == oframe.pri);
nv_offset = bufoff + NGHTTP2_FRAME_HEAD_LENGTH + 4; hdblocklen = nghttp2_buf_len(&buf) - NGHTTP2_FRAME_HDLEN - 4;
CU_ASSERT(framelen - nv_offset == CU_ASSERT(hdblocklen ==
inflate_hd(&inflater, &out, inflate_hd(&inflater, &out,
buf + nv_offset, framelen - nv_offset)); buf.pos + NGHTTP2_FRAME_HDLEN + 4, hdblocklen));
nghttp2_nv_array_sort(out.nva, out.nvlen); nghttp2_nv_array_sort(out.nva, out.nvlen);
CU_ASSERT(nvnameeq("method", &out.nva[0])); CU_ASSERT(nvnameeq("method", &out.nva[0]));
nva_out_reset(&out); nva_out_reset(&out);
free(buf); nghttp2_buf_free(&buf);
nghttp2_frame_headers_free(&oframe); nghttp2_frame_headers_free(&oframe);
nghttp2_frame_headers_free(&frame); nghttp2_frame_headers_free(&frame);
nghttp2_hd_inflate_free(&inflater); nghttp2_hd_inflate_free(&inflater);
@ -150,9 +151,7 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void)
{ {
nghttp2_hd_deflater deflater; nghttp2_hd_deflater deflater;
nghttp2_headers frame; nghttp2_headers frame;
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0;
size_t bufoff;
ssize_t framelen; ssize_t framelen;
nghttp2_nv *nva; nghttp2_nv *nva;
ssize_t nvlen; ssize_t nvlen;
@ -161,6 +160,8 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void)
size_t big_hdslen = ARRLEN(big_hds); size_t big_hdslen = ARRLEN(big_hds);
size_t i; size_t i;
nghttp2_buf_init(&buf);
for(i = 0; i < big_hdslen; ++i) { for(i = 0; i < big_hdslen; ++i) {
big_hds[i].name = (uint8_t*)"header"; big_hds[i].name = (uint8_t*)"header";
big_hds[i].value = malloc(big_vallen+1); big_hds[i].value = malloc(big_vallen+1);
@ -176,12 +177,11 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void)
NGHTTP2_FLAG_END_STREAM|NGHTTP2_FLAG_END_HEADERS, NGHTTP2_FLAG_END_STREAM|NGHTTP2_FLAG_END_HEADERS,
1000000007, 1000000007,
0, nva, nvlen); 0, nva, nvlen);
framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame, framelen = nghttp2_frame_pack_headers(&buf, &frame, &deflater);
&deflater);
CU_ASSERT_EQUAL(NGHTTP2_ERR_HEADER_COMP, framelen); CU_ASSERT_EQUAL(NGHTTP2_ERR_HEADER_COMP, framelen);
nghttp2_frame_headers_free(&frame); nghttp2_frame_headers_free(&frame);
free(buf); nghttp2_buf_free(&buf);
for(i = 0; i < big_hdslen; ++i) { for(i = 0; i < big_hdslen; ++i) {
free(big_hds[i].value); free(big_hds[i].value);
} }
@ -191,16 +191,21 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void)
void test_nghttp2_frame_pack_priority(void) void test_nghttp2_frame_pack_priority(void)
{ {
nghttp2_priority frame, oframe; nghttp2_priority frame, oframe;
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0;
ssize_t framelen; ssize_t framelen;
nghttp2_buf_init(&buf);
nghttp2_frame_priority_init(&frame, 1000000007, 1 << 30); nghttp2_frame_priority_init(&frame, 1000000007, 1 << 30);
framelen = nghttp2_frame_pack_priority(&buf, &buflen, &frame); framelen = nghttp2_frame_pack_priority(&buf, &frame);
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen));
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
check_frame_header(4, NGHTTP2_PRIORITY, NGHTTP2_FLAG_NONE, 1000000007, check_frame_header(4, NGHTTP2_PRIORITY, NGHTTP2_FLAG_NONE, 1000000007,
&oframe.hd); &oframe.hd);
CU_ASSERT(1 << 30 == oframe.pri); CU_ASSERT(1 << 30 == oframe.pri);
free(buf);
nghttp2_buf_free(&buf);
nghttp2_frame_priority_free(&oframe); nghttp2_frame_priority_free(&oframe);
nghttp2_frame_priority_free(&frame); nghttp2_frame_priority_free(&frame);
} }
@ -208,16 +213,21 @@ void test_nghttp2_frame_pack_priority(void)
void test_nghttp2_frame_pack_rst_stream(void) void test_nghttp2_frame_pack_rst_stream(void)
{ {
nghttp2_rst_stream frame, oframe; nghttp2_rst_stream frame, oframe;
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0;
ssize_t framelen; ssize_t framelen;
nghttp2_buf_init(&buf);
nghttp2_frame_rst_stream_init(&frame, 1000000007, NGHTTP2_PROTOCOL_ERROR); nghttp2_frame_rst_stream_init(&frame, 1000000007, NGHTTP2_PROTOCOL_ERROR);
framelen = nghttp2_frame_pack_rst_stream(&buf, &buflen, &frame); framelen = nghttp2_frame_pack_rst_stream(&buf, &frame);
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen));
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
check_frame_header(4, NGHTTP2_RST_STREAM, NGHTTP2_FLAG_NONE, 1000000007, check_frame_header(4, NGHTTP2_RST_STREAM, NGHTTP2_FLAG_NONE, 1000000007,
&oframe.hd); &oframe.hd);
CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == oframe.error_code); CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == oframe.error_code);
free(buf);
nghttp2_buf_free(&buf);
nghttp2_frame_rst_stream_free(&oframe); nghttp2_frame_rst_stream_free(&oframe);
nghttp2_frame_rst_stream_free(&frame); nghttp2_frame_rst_stream_free(&frame);
} }
@ -225,24 +235,33 @@ void test_nghttp2_frame_pack_rst_stream(void)
void test_nghttp2_frame_pack_settings() void test_nghttp2_frame_pack_settings()
{ {
nghttp2_settings frame, oframe; nghttp2_settings frame, oframe;
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0;
ssize_t framelen; ssize_t framelen;
int i; int i;
nghttp2_settings_entry iv[3]; nghttp2_settings_entry iv[] =
iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; {
iv[0].value = 256; {
iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 256
iv[1].value = 16384; },
iv[2].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE; {
iv[2].value = 4096; NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, 16384
},
{
NGHTTP2_SETTINGS_HEADER_TABLE_SIZE, 4096
}
};
nghttp2_buf_init(&buf);
nghttp2_frame_settings_init(&frame, NGHTTP2_FLAG_NONE, nghttp2_frame_settings_init(&frame, NGHTTP2_FLAG_NONE,
nghttp2_frame_iv_copy(iv, 3), 3); nghttp2_frame_iv_copy(iv, 3), 3);
framelen = nghttp2_frame_pack_settings(&buf, &buflen, &frame); framelen = nghttp2_frame_pack_settings(&buf, &frame);
CU_ASSERT(NGHTTP2_FRAME_HEAD_LENGTH + CU_ASSERT(NGHTTP2_FRAME_HEAD_LENGTH +
3 * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH == framelen); 3 * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH == framelen);
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen)); CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
check_frame_header(3 * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH, check_frame_header(3 * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH,
NGHTTP2_SETTINGS, NGHTTP2_FLAG_NONE, 0, &oframe.hd); NGHTTP2_SETTINGS, NGHTTP2_FLAG_NONE, 0, &oframe.hd);
CU_ASSERT(3 == oframe.niv); CU_ASSERT(3 == oframe.niv);
@ -251,7 +270,7 @@ void test_nghttp2_frame_pack_settings()
CU_ASSERT(iv[i].value == oframe.iv[i].value); CU_ASSERT(iv[i].value == oframe.iv[i].value);
} }
free(buf); nghttp2_buf_free(&buf);
nghttp2_frame_settings_free(&frame); nghttp2_frame_settings_free(&frame);
nghttp2_frame_settings_free(&oframe); nghttp2_frame_settings_free(&oframe);
} }
@ -261,14 +280,14 @@ void test_nghttp2_frame_pack_push_promise()
nghttp2_hd_deflater deflater; nghttp2_hd_deflater deflater;
nghttp2_hd_inflater inflater; nghttp2_hd_inflater inflater;
nghttp2_push_promise frame, oframe; nghttp2_push_promise frame, oframe;
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0;
size_t bufoff;
ssize_t framelen; ssize_t framelen;
nghttp2_nv *nva; nghttp2_nv *nva;
ssize_t nvlen; ssize_t nvlen;
nva_out out; nva_out out;
ssize_t nv_offset; ssize_t hdblocklen;
nghttp2_buf_init(&buf);
nva_out_init(&out); nva_out_init(&out);
nghttp2_hd_deflate_init(&deflater); nghttp2_hd_deflate_init(&deflater);
@ -278,26 +297,27 @@ void test_nghttp2_frame_pack_push_promise()
nvlen = HEADERS_LENGTH; nvlen = HEADERS_LENGTH;
nghttp2_frame_push_promise_init(&frame, NGHTTP2_FLAG_END_HEADERS, nghttp2_frame_push_promise_init(&frame, NGHTTP2_FLAG_END_HEADERS,
1000000007, (1U << 31) - 1, nva, nvlen); 1000000007, (1U << 31) - 1, nva, nvlen);
framelen = nghttp2_frame_pack_push_promise(&buf, &buflen, &bufoff, &frame, framelen = nghttp2_frame_pack_push_promise(&buf, &frame, &deflater);
&deflater);
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, CU_ASSERT(framelen == nghttp2_buf_len(&buf));
buf + bufoff, framelen - bufoff)); CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH,
check_frame_header(nghttp2_buf_len(&buf) - NGHTTP2_FRAME_HDLEN,
NGHTTP2_PUSH_PROMISE, NGHTTP2_PUSH_PROMISE,
NGHTTP2_FLAG_END_HEADERS, 1000000007, &oframe.hd); NGHTTP2_FLAG_END_HEADERS, 1000000007, &oframe.hd);
CU_ASSERT((1U << 31) - 1 == oframe.promised_stream_id); CU_ASSERT((1U << 31) - 1 == oframe.promised_stream_id);
nv_offset = bufoff + NGHTTP2_FRAME_HEAD_LENGTH + 4; hdblocklen = nghttp2_buf_len(&buf) - NGHTTP2_FRAME_HDLEN - 4;
CU_ASSERT(framelen - nv_offset == CU_ASSERT(hdblocklen ==
inflate_hd(&inflater, &out, buf + nv_offset, framelen - nv_offset)); inflate_hd(&inflater, &out,
buf.pos + NGHTTP2_FRAME_HDLEN + 4, hdblocklen));
CU_ASSERT(7 == out.nvlen); CU_ASSERT(7 == out.nvlen);
CU_ASSERT(nvnameeq("method", &out.nva[0])); CU_ASSERT(nvnameeq("method", &out.nva[0]));
CU_ASSERT(nvvalueeq("GET", &out.nva[0])); CU_ASSERT(nvvalueeq("GET", &out.nva[0]));
nva_out_reset(&out); nva_out_reset(&out);
free(buf); nghttp2_buf_free(&buf);
nghttp2_frame_push_promise_free(&oframe); nghttp2_frame_push_promise_free(&oframe);
nghttp2_frame_push_promise_free(&frame); nghttp2_frame_push_promise_free(&frame);
nghttp2_hd_inflate_free(&inflater); nghttp2_hd_inflate_free(&inflater);
@ -307,17 +327,22 @@ void test_nghttp2_frame_pack_push_promise()
void test_nghttp2_frame_pack_ping(void) void test_nghttp2_frame_pack_ping(void)
{ {
nghttp2_ping frame, oframe; nghttp2_ping frame, oframe;
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0;
ssize_t framelen; ssize_t framelen;
const uint8_t opaque_data[] = "01234567"; const uint8_t opaque_data[] = "01234567";
nghttp2_buf_init(&buf);
nghttp2_frame_ping_init(&frame, NGHTTP2_FLAG_ACK, opaque_data); nghttp2_frame_ping_init(&frame, NGHTTP2_FLAG_ACK, opaque_data);
framelen = nghttp2_frame_pack_ping(&buf, &buflen, &frame); framelen = nghttp2_frame_pack_ping(&buf, &frame);
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen));
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
check_frame_header(8, NGHTTP2_PING, NGHTTP2_FLAG_ACK, 0, &oframe.hd); check_frame_header(8, NGHTTP2_PING, NGHTTP2_FLAG_ACK, 0, &oframe.hd);
CU_ASSERT(memcmp(opaque_data, oframe.opaque_data, sizeof(opaque_data) - 1) CU_ASSERT(memcmp(opaque_data, oframe.opaque_data, sizeof(opaque_data) - 1)
== 0); == 0);
free(buf);
nghttp2_buf_free(&buf);
nghttp2_frame_ping_free(&oframe); nghttp2_frame_ping_free(&oframe);
nghttp2_frame_ping_free(&frame); nghttp2_frame_ping_free(&frame);
} }
@ -325,17 +350,20 @@ void test_nghttp2_frame_pack_ping(void)
void test_nghttp2_frame_pack_goaway() void test_nghttp2_frame_pack_goaway()
{ {
nghttp2_goaway frame, oframe; nghttp2_goaway frame, oframe;
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0;
ssize_t framelen; ssize_t framelen;
size_t opaque_data_len = 16; size_t opaque_data_len = 16;
uint8_t *opaque_data = malloc(opaque_data_len); uint8_t *opaque_data = malloc(opaque_data_len);
nghttp2_buf_init(&buf);
memcpy(opaque_data, "0123456789abcdef", opaque_data_len); memcpy(opaque_data, "0123456789abcdef", opaque_data_len);
nghttp2_frame_goaway_init(&frame, 1000000007, NGHTTP2_PROTOCOL_ERROR, nghttp2_frame_goaway_init(&frame, 1000000007, NGHTTP2_PROTOCOL_ERROR,
opaque_data, opaque_data_len); opaque_data, opaque_data_len);
framelen = nghttp2_frame_pack_goaway(&buf, &buflen, &frame); framelen = nghttp2_frame_pack_goaway(&buf, &frame);
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen));
CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
check_frame_header(24, NGHTTP2_GOAWAY, NGHTTP2_FLAG_NONE, 0, &oframe.hd); check_frame_header(24, NGHTTP2_GOAWAY, NGHTTP2_FLAG_NONE, 0, &oframe.hd);
CU_ASSERT(1000000007 == oframe.last_stream_id); CU_ASSERT(1000000007 == oframe.last_stream_id);
CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == oframe.error_code); CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == oframe.error_code);
@ -344,7 +372,8 @@ void test_nghttp2_frame_pack_goaway()
CU_ASSERT(NULL == oframe.opaque_data); CU_ASSERT(NULL == oframe.opaque_data);
/* CU_ASSERT(opaque_data_len == oframe.opaque_data_len); */ /* CU_ASSERT(opaque_data_len == oframe.opaque_data_len); */
/* CU_ASSERT(memcmp(opaque_data, oframe.opaque_data, opaque_data_len) == 0); */ /* CU_ASSERT(memcmp(opaque_data, oframe.opaque_data, opaque_data_len) == 0); */
free(buf);
nghttp2_buf_free(&buf);
nghttp2_frame_goaway_free(&oframe); nghttp2_frame_goaway_free(&oframe);
nghttp2_frame_goaway_free(&frame); nghttp2_frame_goaway_free(&frame);
} }
@ -352,19 +381,22 @@ void test_nghttp2_frame_pack_goaway()
void test_nghttp2_frame_pack_window_update(void) void test_nghttp2_frame_pack_window_update(void)
{ {
nghttp2_window_update frame, oframe; nghttp2_window_update frame, oframe;
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0;
ssize_t framelen; ssize_t framelen;
nghttp2_buf_init(&buf);
nghttp2_frame_window_update_init(&frame, NGHTTP2_FLAG_NONE, nghttp2_frame_window_update_init(&frame, NGHTTP2_FLAG_NONE,
1000000007, 4096); 1000000007, 4096);
framelen = nghttp2_frame_pack_window_update(&buf, &buflen, framelen = nghttp2_frame_pack_window_update(&buf, &frame);
&frame);
CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen)); CU_ASSERT(framelen == nghttp2_buf_len(&buf));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &buf));
check_frame_header(4, NGHTTP2_WINDOW_UPDATE, NGHTTP2_FLAG_NONE, check_frame_header(4, NGHTTP2_WINDOW_UPDATE, NGHTTP2_FLAG_NONE,
1000000007, &oframe.hd); 1000000007, &oframe.hd);
CU_ASSERT(4096 == oframe.window_size_increment); CU_ASSERT(4096 == oframe.window_size_increment);
free(buf);
nghttp2_buf_free(&buf);
nghttp2_frame_window_update_free(&oframe); nghttp2_frame_window_update_free(&oframe);
nghttp2_frame_window_update_free(&frame); nghttp2_frame_window_update_free(&frame);
} }

View File

@ -52,77 +52,83 @@ void test_nghttp2_hd_deflate(void)
MAKE_NV("cookie", "k1=v1")}; MAKE_NV("cookie", "k1=v1")};
nghttp2_nv nva5[] = {MAKE_NV(":path", "/style.css"), nghttp2_nv nva5[] = {MAKE_NV(":path", "/style.css"),
MAKE_NV("x-nghttp2", "")}; MAKE_NV("x-nghttp2", "")};
size_t nv_offset = 12; nghttp2_buf buf;
uint8_t *buf = NULL;
size_t buflen = 0;
ssize_t blocklen; ssize_t blocklen;
nva_out out; nva_out out;
nghttp2_buf_init(&buf);
nva_out_init(&out); nva_out_init(&out);
CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater)); CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater));
CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater)); CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater));
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, nv_offset, nva1,
sizeof(nva1)/sizeof(nghttp2_nv)); blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva1, ARRLEN(nva1));
CU_ASSERT(blocklen > 0); CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
inflate_hd(&inflater, &out, buf + nv_offset, blocklen)); CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(3 == out.nvlen); CU_ASSERT(3 == out.nvlen);
assert_nv_equal(nva1, out.nva, 3); assert_nv_equal(nva1, out.nva, 3);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
/* Second headers */ /* Second headers */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, nv_offset, nva2, blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva2, ARRLEN(nva2));
sizeof(nva2)/sizeof(nghttp2_nv));
CU_ASSERT(blocklen > 0); CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
inflate_hd(&inflater, &out, buf + nv_offset, blocklen)); CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(2 == out.nvlen); CU_ASSERT(2 == out.nvlen);
assert_nv_equal(nva2, out.nva, 2); assert_nv_equal(nva2, out.nva, 2);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
/* Third headers, including same header field name, but value is not /* Third headers, including same header field name, but value is not
the same. */ the same. */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, nv_offset, nva3, blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva3, ARRLEN(nva3));
sizeof(nva3)/sizeof(nghttp2_nv));
CU_ASSERT(blocklen > 0); CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
inflate_hd(&inflater, &out, buf + nv_offset, blocklen)); CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(3 == out.nvlen); CU_ASSERT(3 == out.nvlen);
assert_nv_equal(nva3, out.nva, 3); assert_nv_equal(nva3, out.nva, 3);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
/* Fourth headers, including duplicate header fields. */ /* Fourth headers, including duplicate header fields. */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, nv_offset, nva4, blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva4, ARRLEN(nva4));
sizeof(nva4)/sizeof(nghttp2_nv));
CU_ASSERT(blocklen > 0); CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
inflate_hd(&inflater, &out, buf + nv_offset, blocklen)); CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(3 == out.nvlen); CU_ASSERT(3 == out.nvlen);
assert_nv_equal(nva4, out.nva, 3); assert_nv_equal(nva4, out.nva, 3);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
/* Fifth headers includes empty value */ /* Fifth headers includes empty value */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, nv_offset, nva5, blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva5, ARRLEN(nva5));
sizeof(nva5)/sizeof(nghttp2_nv));
CU_ASSERT(blocklen > 0); CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
inflate_hd(&inflater, &out, buf + nv_offset, blocklen)); CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(2 == out.nvlen); CU_ASSERT(2 == out.nvlen);
assert_nv_equal(nva5, out.nva, 2); assert_nv_equal(nva5, out.nva, 2);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
/* Cleanup */ /* Cleanup */
free(buf); nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater); nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater); nghttp2_hd_deflate_free(&deflater);
} }
@ -136,41 +142,46 @@ void test_nghttp2_hd_deflate_same_indexed_repr(void)
nghttp2_nv nva2[] = {MAKE_NV("cookie", "alpha"), nghttp2_nv nva2[] = {MAKE_NV("cookie", "alpha"),
MAKE_NV("cookie", "alpha"), MAKE_NV("cookie", "alpha"),
MAKE_NV("cookie", "alpha")}; MAKE_NV("cookie", "alpha")};
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0;
ssize_t blocklen; ssize_t blocklen;
nva_out out; nva_out out;
nghttp2_buf_init(&buf);
nva_out_init(&out); nva_out_init(&out);
CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater)); CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater));
CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater)); CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater));
/* Encode 2 same headers. cookie:alpha is not in the reference set, /* Encode 2 same headers. cookie:alpha is not in the reference set,
so first emit literal repr and then 2 emits of indexed repr. */ so first emit literal repr and then 2 emits of indexed repr. */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva1, blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva1, ARRLEN(nva1));
sizeof(nva1)/sizeof(nghttp2_nv));
CU_ASSERT(blocklen > 0); CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf, blocklen)); CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(2 == out.nvlen); CU_ASSERT(2 == out.nvlen);
assert_nv_equal(nva1, out.nva, 2); assert_nv_equal(nva1, out.nva, 2);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
/* Encode 3 same headers. This time, cookie:alpha is in the /* Encode 3 same headers. This time, cookie:alpha is in the
reference set, so the encoder emits indexed repr 6 times */ reference set, so the encoder emits indexed repr 6 times */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva2, blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva2, ARRLEN(nva2));
sizeof(nva2)/sizeof(nghttp2_nv));
CU_ASSERT(blocklen == 6); CU_ASSERT(blocklen == 6);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf, blocklen)); CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(3 == out.nvlen); CU_ASSERT(3 == out.nvlen);
assert_nv_equal(nva2, out.nva, 3); assert_nv_equal(nva2, out.nva, 3);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
/* Cleanup */ /* Cleanup */
free(buf); nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater); nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater); nghttp2_hd_deflate_free(&deflater);
} }
@ -181,8 +192,7 @@ void test_nghttp2_hd_deflate_common_header_eviction(void)
nghttp2_hd_inflater inflater; nghttp2_hd_inflater inflater;
nghttp2_nv nva[] = {MAKE_NV("h1", ""), nghttp2_nv nva[] = {MAKE_NV("h1", ""),
MAKE_NV("h2", "")}; MAKE_NV("h2", "")};
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0;
ssize_t blocklen; ssize_t blocklen;
/* Default header table capacity is 4096. Adding 2 byte header name /* Default header table capacity is 4096. Adding 2 byte header name
and 4060 byte value, which is 4094 bytes including overhead, to and 4060 byte value, which is 4094 bytes including overhead, to
@ -191,6 +201,8 @@ void test_nghttp2_hd_deflate_common_header_eviction(void)
nva_out out; nva_out out;
size_t i; size_t i;
nghttp2_buf_init(&buf);
nva_out_init(&out); nva_out_init(&out);
memset(value, '0', sizeof(value)); memset(value, '0', sizeof(value));
for(i = 0; i < 2; ++i) { for(i = 0; i < 2; ++i) {
@ -203,35 +215,42 @@ void test_nghttp2_hd_deflate_common_header_eviction(void)
/* First emit "h1: ..." to put it in the reference set (index /* First emit "h1: ..." to put it in the reference set (index
= 0). */ = 0). */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 1); blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 1);
CU_ASSERT(blocklen > 0); CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf, blocklen)); CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(1 == out.nvlen); CU_ASSERT(1 == out.nvlen);
nghttp2_nv_array_sort(nva, 1); nghttp2_nv_array_sort(nva, 1);
assert_nv_equal(nva, out.nva, 1); assert_nv_equal(nva, out.nva, 1);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
/* Encode with second header */ /* Encode with second header */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2);
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
CU_ASSERT(blocklen > 0); CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
/* Check common header "h1: ...:, which is removed from the /* Check common header "h1: ...:, which is removed from the
header table because of eviction, is still emitted by the header table because of eviction, is still emitted by the
inflater */ inflater */
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf, blocklen)); CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(2 == out.nvlen); CU_ASSERT(2 == out.nvlen);
nghttp2_nv_array_sort(nva, 2); nghttp2_nv_array_sort(nva, 2);
assert_nv_equal(nva, out.nva, 2); assert_nv_equal(nva, out.nva, 2);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
CU_ASSERT(1 == deflater.ctx.hd_table.len); CU_ASSERT(1 == deflater.ctx.hd_table.len);
CU_ASSERT(1 == inflater.ctx.hd_table.len); CU_ASSERT(1 == inflater.ctx.hd_table.len);
free(buf); nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater); nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater); nghttp2_hd_deflate_free(&deflater);
} }
@ -240,8 +259,7 @@ void test_nghttp2_hd_deflate_clear_refset(void)
{ {
nghttp2_hd_deflater deflater; nghttp2_hd_deflater deflater;
nghttp2_hd_inflater inflater; nghttp2_hd_inflater inflater;
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0;
ssize_t blocklen; ssize_t blocklen;
nghttp2_nv nv[] = { nghttp2_nv nv[] = {
MAKE_NV(":path", "/"), MAKE_NV(":path", "/"),
@ -250,6 +268,8 @@ void test_nghttp2_hd_deflate_clear_refset(void)
size_t i; size_t i;
nva_out out; nva_out out;
nghttp2_buf_init(&buf);
nva_out_init(&out); nva_out_init(&out);
nghttp2_hd_deflate_init2(&deflater, nghttp2_hd_deflate_init2(&deflater,
NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE); NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE);
@ -257,18 +277,18 @@ void test_nghttp2_hd_deflate_clear_refset(void)
nghttp2_hd_inflate_init(&inflater); nghttp2_hd_inflate_init(&inflater);
for(i = 0; i < 2; ++i) { for(i = 0; i < 2; ++i) {
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, nv, ARRLEN(nv));
nv, ARRLEN(nv));
CU_ASSERT(blocklen > 1); CU_ASSERT(blocklen > 1);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf, blocklen)); CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(ARRLEN(nv) == out.nvlen); CU_ASSERT(ARRLEN(nv) == out.nvlen);
assert_nv_equal(nv, out.nva, ARRLEN(nv)); assert_nv_equal(nv, out.nva, ARRLEN(nv));
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
} }
free(buf); nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater); nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater); nghttp2_hd_deflate_free(&deflater);
} }
@ -276,9 +296,8 @@ void test_nghttp2_hd_deflate_clear_refset(void)
void test_nghttp2_hd_inflate_indname_noinc(void) void test_nghttp2_hd_inflate_indname_noinc(void)
{ {
nghttp2_hd_inflater inflater; nghttp2_hd_inflater inflater;
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0; ssize_t blocklen;
size_t offset = 0;
nghttp2_nv nv[] = { nghttp2_nv nv[] = {
/* Huffman */ /* Huffman */
MAKE_NV("user-agent", "nghttp2"), MAKE_NV("user-agent", "nghttp2"),
@ -288,42 +307,53 @@ void test_nghttp2_hd_inflate_indname_noinc(void)
size_t i; size_t i;
nva_out out; nva_out out;
nghttp2_buf_init(&buf);
nva_out_init(&out); nva_out_init(&out);
nghttp2_hd_inflate_init(&inflater); nghttp2_hd_inflate_init(&inflater);
for(i = 0; i < ARRLEN(nv); ++i) { for(i = 0; i < ARRLEN(nv); ++i) {
offset = 0; CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, 56,
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 56,
nv[i].value, nv[i].valuelen, nv[i].value, nv[i].valuelen,
0)); 0));
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
blocklen = nghttp2_buf_len(&buf);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(1 == out.nvlen); CU_ASSERT(1 == out.nvlen);
assert_nv_equal(&nv[i], out.nva, 1); assert_nv_equal(&nv[i], out.nva, 1);
CU_ASSERT(0 == inflater.ctx.hd_table.len); CU_ASSERT(0 == inflater.ctx.hd_table.len);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
} }
free(buf); nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater); nghttp2_hd_inflate_free(&inflater);
} }
void test_nghttp2_hd_inflate_indname_inc(void) void test_nghttp2_hd_inflate_indname_inc(void)
{ {
nghttp2_hd_inflater inflater; nghttp2_hd_inflater inflater;
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0; ssize_t blocklen;
size_t offset = 0;
nghttp2_nv nv = MAKE_NV("user-agent", "nghttp2"); nghttp2_nv nv = MAKE_NV("user-agent", "nghttp2");
nva_out out; nva_out out;
nghttp2_buf_init(&buf);
nva_out_init(&out); nva_out_init(&out);
nghttp2_hd_inflate_init(&inflater); nghttp2_hd_inflate_init(&inflater);
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 56, CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, 56,
nv.value, nv.valuelen, 1)); nv.value, nv.valuelen, 1));
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
blocklen = nghttp2_buf_len(&buf);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(1 == out.nvlen); CU_ASSERT(1 == out.nvlen);
assert_nv_equal(&nv, out.nva, 1); assert_nv_equal(&nv, out.nva, 1);
@ -333,33 +363,38 @@ void test_nghttp2_hd_inflate_indname_inc(void)
inflater.ctx.hd_table.len-1)->nv, 1); inflater.ctx.hd_table.len-1)->nv, 1);
nva_out_reset(&out); nva_out_reset(&out);
free(buf); nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater); nghttp2_hd_inflate_free(&inflater);
} }
void test_nghttp2_hd_inflate_indname_inc_eviction(void) void test_nghttp2_hd_inflate_indname_inc_eviction(void)
{ {
nghttp2_hd_inflater inflater; nghttp2_hd_inflater inflater;
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0; ssize_t blocklen;
size_t offset = 0;
uint8_t value[1024]; uint8_t value[1024];
nva_out out; nva_out out;
nghttp2_buf_init(&buf);
nva_out_init(&out); nva_out_init(&out);
nghttp2_hd_inflate_init(&inflater); nghttp2_hd_inflate_init(&inflater);
memset(value, '0', sizeof(value)); memset(value, '0', sizeof(value));
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 13, CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, 13,
value, sizeof(value), 1)); value, sizeof(value), 1));
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 14, CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, 14,
value, sizeof(value), 1)); value, sizeof(value), 1));
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 15, CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, 15,
value, sizeof(value), 1)); value, sizeof(value), 1));
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 16, CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, 16,
value, sizeof(value), 1)); value, sizeof(value), 1));
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset)); blocklen = nghttp2_buf_len(&buf);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(4 == out.nvlen); CU_ASSERT(4 == out.nvlen);
CU_ASSERT(14 == out.nva[0].namelen); CU_ASSERT(14 == out.nva[0].namelen);
@ -367,20 +402,20 @@ void test_nghttp2_hd_inflate_indname_inc_eviction(void)
CU_ASSERT(sizeof(value) == out.nva[0].valuelen); CU_ASSERT(sizeof(value) == out.nva[0].valuelen);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
CU_ASSERT(3 == inflater.ctx.hd_table.len); CU_ASSERT(3 == inflater.ctx.hd_table.len);
CU_ASSERT(GET_TABLE_ENT(&inflater.ctx, 0)->flags & NGHTTP2_HD_FLAG_REFSET); CU_ASSERT(GET_TABLE_ENT(&inflater.ctx, 0)->flags & NGHTTP2_HD_FLAG_REFSET);
free(buf); nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater); nghttp2_hd_inflate_free(&inflater);
} }
void test_nghttp2_hd_inflate_newname_noinc(void) void test_nghttp2_hd_inflate_newname_noinc(void)
{ {
nghttp2_hd_inflater inflater; nghttp2_hd_inflater inflater;
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0; ssize_t blocklen;
size_t offset = 0;
nghttp2_nv nv[] = { nghttp2_nv nv[] = {
/* Expecting huffman for both */ /* Expecting huffman for both */
MAKE_NV("my-long-content-length", "nghttp2"), MAKE_NV("my-long-content-length", "nghttp2"),
@ -394,40 +429,49 @@ void test_nghttp2_hd_inflate_newname_noinc(void)
size_t i; size_t i;
nva_out out; nva_out out;
nghttp2_buf_init(&buf);
nva_out_init(&out); nva_out_init(&out);
nghttp2_hd_inflate_init(&inflater); nghttp2_hd_inflate_init(&inflater);
for(i = 0; i < ARRLEN(nv); ++i) { for(i = 0; i < ARRLEN(nv); ++i) {
offset = 0; CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &nv[i], 0));
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset,
&nv[i], 0)); blocklen = nghttp2_buf_len(&buf);
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(1 == out.nvlen); CU_ASSERT(1 == out.nvlen);
assert_nv_equal(&nv[i], out.nva, 1); assert_nv_equal(&nv[i], out.nva, 1);
CU_ASSERT(0 == inflater.ctx.hd_table.len); CU_ASSERT(0 == inflater.ctx.hd_table.len);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
} }
free(buf); nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater); nghttp2_hd_inflate_free(&inflater);
} }
void test_nghttp2_hd_inflate_newname_inc(void) void test_nghttp2_hd_inflate_newname_inc(void)
{ {
nghttp2_hd_inflater inflater; nghttp2_hd_inflater inflater;
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0; ssize_t blocklen;
size_t offset = 0;
nghttp2_nv nv = MAKE_NV("x-rel", "nghttp2"); nghttp2_nv nv = MAKE_NV("x-rel", "nghttp2");
nva_out out; nva_out out;
nghttp2_buf_init(&buf);
nva_out_init(&out); nva_out_init(&out);
nghttp2_hd_inflate_init(&inflater); nghttp2_hd_inflate_init(&inflater);
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset, CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &nv, 1));
&nv, 1));
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset)); blocklen = nghttp2_buf_len(&buf);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(1 == out.nvlen); CU_ASSERT(1 == out.nvlen);
assert_nv_equal(&nv, out.nva, 1); assert_nv_equal(&nv, out.nva, 1);
@ -437,20 +481,21 @@ void test_nghttp2_hd_inflate_newname_inc(void)
inflater.ctx.hd_table.len-1)->nv, 1); inflater.ctx.hd_table.len-1)->nv, 1);
nva_out_reset(&out); nva_out_reset(&out);
free(buf); nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater); nghttp2_hd_inflate_free(&inflater);
} }
void test_nghttp2_hd_inflate_clearall_inc(void) void test_nghttp2_hd_inflate_clearall_inc(void)
{ {
nghttp2_hd_inflater inflater; nghttp2_hd_inflater inflater;
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0; ssize_t blocklen;
size_t offset = 0;
nghttp2_nv nv; nghttp2_nv nv;
uint8_t value[4060]; uint8_t value[4060];
nva_out out; nva_out out;
nghttp2_buf_init(&buf);
nva_out_init(&out); nva_out_init(&out);
/* Total 4097 bytes space required to hold this entry */ /* Total 4097 bytes space required to hold this entry */
nv.name = (uint8_t*)"alpha"; nv.name = (uint8_t*)"alpha";
@ -461,18 +506,22 @@ void test_nghttp2_hd_inflate_clearall_inc(void)
nghttp2_hd_inflate_init(&inflater); nghttp2_hd_inflate_init(&inflater);
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset, CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &nv, 1));
&nv, 1));
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset)); blocklen = nghttp2_buf_len(&buf);
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(1 == out.nvlen); CU_ASSERT(1 == out.nvlen);
assert_nv_equal(&nv, out.nva, 1); assert_nv_equal(&nv, out.nva, 1);
CU_ASSERT(0 == inflater.ctx.hd_table.len); CU_ASSERT(0 == inflater.ctx.hd_table.len);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
/* Do it again */ /* Do it again */
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset)); CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(1 == out.nvlen); CU_ASSERT(1 == out.nvlen);
assert_nv_equal(&nv, out.nva, 1); assert_nv_equal(&nv, out.nva, 1);
@ -484,18 +533,21 @@ void test_nghttp2_hd_inflate_clearall_inc(void)
header table */ header table */
nv.valuelen = sizeof(value) - 1; nv.valuelen = sizeof(value) - 1;
offset = 0; CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &nv, 1));
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset,
&nv, 1)); blocklen = nghttp2_buf_len(&buf);
CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset));
CU_ASSERT(blocklen > 0);
CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf.pos, blocklen));
CU_ASSERT(1 == out.nvlen); CU_ASSERT(1 == out.nvlen);
assert_nv_equal(&nv, out.nva, 1); assert_nv_equal(&nv, out.nva, 1);
CU_ASSERT(1 == inflater.ctx.hd_table.len); CU_ASSERT(1 == inflater.ctx.hd_table.len);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
free(buf); nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater); nghttp2_hd_inflate_free(&inflater);
} }
@ -531,11 +583,11 @@ void test_nghttp2_hd_change_table_size(void)
nghttp2_hd_inflater inflater; nghttp2_hd_inflater inflater;
nghttp2_nv nva[] = { MAKE_NV(":method", "GET"), nghttp2_nv nva[] = { MAKE_NV(":method", "GET"),
MAKE_NV(":path", "/") }; MAKE_NV(":path", "/") };
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0;
ssize_t rv; ssize_t rv;
nva_out out; nva_out out;
size_t offset;
nghttp2_buf_init(&buf);
nva_out_init(&out); nva_out_init(&out);
@ -554,17 +606,19 @@ void test_nghttp2_hd_change_table_size(void)
CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max); CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max);
/* This will emit encoding context update with header table size 4096 */ /* This will emit encoding context update with header table size 4096 */
rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2); rv = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
CU_ASSERT(rv > 0); CU_ASSERT(rv > 0);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
CU_ASSERT(2 == deflater.ctx.hd_table.len); CU_ASSERT(2 == deflater.ctx.hd_table.len);
CU_ASSERT(4096 == deflater.ctx.hd_table_bufsize_max); CU_ASSERT(4096 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv)); CU_ASSERT(rv == inflate_hd(&inflater, &out, buf.pos, rv));
CU_ASSERT(2 == inflater.ctx.hd_table.len); CU_ASSERT(2 == inflater.ctx.hd_table.len);
CU_ASSERT(4096 == inflater.ctx.hd_table_bufsize_max); CU_ASSERT(4096 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max); CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
/* inflater changes header table size to 1024 */ /* inflater changes header table size to 1024 */
CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 1024)); CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 1024));
@ -577,17 +631,19 @@ void test_nghttp2_hd_change_table_size(void)
CU_ASSERT(1024 == inflater.ctx.hd_table_bufsize_max); CU_ASSERT(1024 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(1024 == inflater.settings_hd_table_bufsize_max); CU_ASSERT(1024 == inflater.settings_hd_table_bufsize_max);
rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2); rv = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
CU_ASSERT(rv >= 0); CU_ASSERT(rv >= 0);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
CU_ASSERT(2 == deflater.ctx.hd_table.len); CU_ASSERT(2 == deflater.ctx.hd_table.len);
CU_ASSERT(1024 == deflater.ctx.hd_table_bufsize_max); CU_ASSERT(1024 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv)); CU_ASSERT(rv == inflate_hd(&inflater, &out, buf.pos, rv));
CU_ASSERT(2 == inflater.ctx.hd_table.len); CU_ASSERT(2 == inflater.ctx.hd_table.len);
CU_ASSERT(1024 == inflater.ctx.hd_table_bufsize_max); CU_ASSERT(1024 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(1024 == inflater.settings_hd_table_bufsize_max); CU_ASSERT(1024 == inflater.settings_hd_table_bufsize_max);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
/* inflater changes header table size to 0 */ /* inflater changes header table size to 0 */
CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 0)); CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 0));
@ -602,25 +658,27 @@ void test_nghttp2_hd_change_table_size(void)
CU_ASSERT(0 == inflater.ctx.hd_table_bufsize_max); CU_ASSERT(0 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(0 == inflater.settings_hd_table_bufsize_max); CU_ASSERT(0 == inflater.settings_hd_table_bufsize_max);
rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2); rv = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
CU_ASSERT(rv >= 0); CU_ASSERT(rv >= 0);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
CU_ASSERT(0 == deflater.ctx.hd_table.len); CU_ASSERT(0 == deflater.ctx.hd_table.len);
CU_ASSERT(0 == deflater.ctx.hd_table_bufsize_max); CU_ASSERT(0 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv)); CU_ASSERT(rv == inflate_hd(&inflater, &out, buf.pos, rv));
CU_ASSERT(0 == inflater.ctx.hd_table.len); CU_ASSERT(0 == inflater.ctx.hd_table.len);
CU_ASSERT(0 == inflater.ctx.hd_table_bufsize_max); CU_ASSERT(0 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(0 == inflater.settings_hd_table_bufsize_max); CU_ASSERT(0 == inflater.settings_hd_table_bufsize_max);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
free(buf); nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater); nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater); nghttp2_hd_deflate_free(&deflater);
/* Check table buffer is expanded */ /* Check table buffer is expanded */
buf = NULL; nghttp2_buf_init(&buf);
buflen = 0;
nghttp2_hd_deflate_init2(&deflater, 8192); nghttp2_hd_deflate_init2(&deflater, 8192);
nghttp2_hd_inflate_init(&inflater); nghttp2_hd_inflate_init(&inflater);
@ -635,17 +693,19 @@ void test_nghttp2_hd_change_table_size(void)
CU_ASSERT(8000 == inflater.ctx.hd_table_bufsize_max); CU_ASSERT(8000 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max); CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max);
rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2); rv = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
CU_ASSERT(rv > 0); CU_ASSERT(rv > 0);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
CU_ASSERT(2 == deflater.ctx.hd_table.len); CU_ASSERT(2 == deflater.ctx.hd_table.len);
CU_ASSERT(8000 == deflater.ctx.hd_table_bufsize_max); CU_ASSERT(8000 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv)); CU_ASSERT(rv == inflate_hd(&inflater, &out, buf.pos, rv));
CU_ASSERT(2 == inflater.ctx.hd_table.len); CU_ASSERT(2 == inflater.ctx.hd_table.len);
CU_ASSERT(8000 == inflater.ctx.hd_table_bufsize_max); CU_ASSERT(8000 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max); CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 16383)); CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 16383));
CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 16383)); CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 16383));
@ -657,26 +717,29 @@ void test_nghttp2_hd_change_table_size(void)
CU_ASSERT(16383 == inflater.ctx.hd_table_bufsize_max); CU_ASSERT(16383 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(16383 == inflater.settings_hd_table_bufsize_max); CU_ASSERT(16383 == inflater.settings_hd_table_bufsize_max);
rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2); rv = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
CU_ASSERT(rv >= 0); CU_ASSERT(rv >= 0);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
CU_ASSERT(2 == deflater.ctx.hd_table.len); CU_ASSERT(2 == deflater.ctx.hd_table.len);
CU_ASSERT(8192 == deflater.ctx.hd_table_bufsize_max); CU_ASSERT(8192 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv)); CU_ASSERT(rv == inflate_hd(&inflater, &out, buf.pos, rv));
CU_ASSERT(2 == inflater.ctx.hd_table.len); CU_ASSERT(2 == inflater.ctx.hd_table.len);
CU_ASSERT(8192 == inflater.ctx.hd_table_bufsize_max); CU_ASSERT(8192 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(16383 == inflater.settings_hd_table_bufsize_max); CU_ASSERT(16383 == inflater.settings_hd_table_bufsize_max);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
/* Lastly, check the error condition */ /* Lastly, check the error condition */
offset = 0;
rv = nghttp2_hd_emit_table_size(&buf, &buflen, &offset, 25600); rv = nghttp2_hd_emit_table_size(&buf, 25600);
CU_ASSERT(rv == 0); CU_ASSERT(rv == 0);
CU_ASSERT(NGHTTP2_ERR_HEADER_COMP == CU_ASSERT(NGHTTP2_ERR_HEADER_COMP ==
inflate_hd(&inflater, &out, buf, offset)); inflate_hd(&inflater, &out, buf.pos, nghttp2_buf_len(&buf)));
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
nghttp2_hd_inflate_free(&inflater); nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater); nghttp2_hd_deflate_free(&deflater);
@ -690,19 +753,21 @@ void test_nghttp2_hd_change_table_size(void)
CU_ASSERT(4096 == deflater.ctx.hd_table_bufsize_max); CU_ASSERT(4096 == deflater.ctx.hd_table_bufsize_max);
/* This emits context update with buffer size 1024 */ /* This emits context update with buffer size 1024 */
rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2); rv = nghttp2_hd_deflate_hd(&deflater, &buf, nva, 2);
CU_ASSERT(rv > 0); CU_ASSERT(rv > 0);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
CU_ASSERT(2 == deflater.ctx.hd_table.len); CU_ASSERT(2 == deflater.ctx.hd_table.len);
CU_ASSERT(1024 == deflater.ctx.hd_table_bufsize_max); CU_ASSERT(1024 == deflater.ctx.hd_table_bufsize_max);
CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv)); CU_ASSERT(rv == inflate_hd(&inflater, &out, buf.pos, rv));
CU_ASSERT(2 == inflater.ctx.hd_table.len); CU_ASSERT(2 == inflater.ctx.hd_table.len);
CU_ASSERT(1024 == inflater.ctx.hd_table_bufsize_max); CU_ASSERT(1024 == inflater.ctx.hd_table_bufsize_max);
CU_ASSERT(4096 == inflater.settings_hd_table_bufsize_max); CU_ASSERT(4096 == inflater.settings_hd_table_bufsize_max);
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_buf_reset(&buf);
free(buf); nghttp2_buf_free(&buf);
nghttp2_hd_inflate_free(&inflater); nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater); nghttp2_hd_deflate_free(&deflater);
} }
@ -711,22 +776,25 @@ static void check_deflate_inflate(nghttp2_hd_deflater *deflater,
nghttp2_hd_inflater *inflater, nghttp2_hd_inflater *inflater,
nghttp2_nv *nva, size_t nvlen) nghttp2_nv *nva, size_t nvlen)
{ {
uint8_t *buf = NULL; nghttp2_buf buf;
size_t buflen = 0;
ssize_t blocklen; ssize_t blocklen;
nva_out out; nva_out out;
nva_out_init(&out); nghttp2_buf_init(&buf);
blocklen = nghttp2_hd_deflate_hd(deflater, &buf, &buflen, 0, nva, nvlen);
assert(blocklen >= 0);
CU_ASSERT(blocklen == inflate_hd(inflater, &out, buf, blocklen)); nva_out_init(&out);
blocklen = nghttp2_hd_deflate_hd(deflater, &buf, nva, nvlen);
CU_ASSERT(blocklen >= 0);
CU_ASSERT(blocklen == nghttp2_buf_len(&buf));
CU_ASSERT(blocklen == inflate_hd(inflater, &out, buf.pos, blocklen));
CU_ASSERT(nvlen == out.nvlen); CU_ASSERT(nvlen == out.nvlen);
assert_nv_equal(nva, out.nva, nvlen); assert_nv_equal(nva, out.nva, nvlen);
nva_out_reset(&out); nva_out_reset(&out);
free(buf); nghttp2_buf_free(&buf);
} }
void test_nghttp2_hd_deflate_inflate(void) void test_nghttp2_hd_deflate_inflate(void)

View File

@ -346,37 +346,39 @@ void test_nghttp2_session_recv(void)
const nghttp2_nv nv[] = { const nghttp2_nv nv[] = {
MAKE_NV("url", "/") MAKE_NV("url", "/")
}; };
uint8_t *framedata = NULL; nghttp2_buf buf;
size_t framedatalen = 0;
size_t bufoff;
ssize_t framelen; ssize_t framelen;
nghttp2_frame frame; nghttp2_frame frame;
size_t i; ssize_t i;
nghttp2_outbound_item *item; nghttp2_outbound_item *item;
nghttp2_nv *nva; nghttp2_nv *nva;
ssize_t nvlen; ssize_t nvlen;
nghttp2_hd_deflater deflater; nghttp2_hd_deflater deflater;
nghttp2_buf_init(&buf);
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.send_callback = null_send_callback; callbacks.send_callback = null_send_callback;
callbacks.recv_callback = scripted_recv_callback; callbacks.recv_callback = scripted_recv_callback;
callbacks.on_frame_recv_callback = on_frame_recv_callback; callbacks.on_frame_recv_callback = on_frame_recv_callback;
user_data.df = &df; user_data.df = &df;
nghttp2_session_server_new(&session, &callbacks, &user_data); nghttp2_session_server_new(&session, &callbacks, &user_data);
nghttp2_hd_deflate_init(&deflater); nghttp2_hd_deflate_init(&deflater);
nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv)); nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv));
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
1, NGHTTP2_PRI_DEFAULT, nva, nvlen); 1, NGHTTP2_PRI_DEFAULT, nva, nvlen);
framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff, framelen = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
&frame.headers,
&deflater); scripted_data_feed_init(&df, buf.pos, nghttp2_buf_len(&buf));
scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff);
/* Send 1 byte per each read */ /* Send 1 byte per each read */
for(i = 0; i < framelen - bufoff; ++i) { for(i = 0; i < nghttp2_buf_len(&buf); ++i) {
df.feedseq[i] = 1; df.feedseq[i] = 1;
} }
nghttp2_frame_headers_free(&frame.headers); nghttp2_frame_headers_free(&frame.headers);
user_data.frame_recv_cb_called = 0; user_data.frame_recv_cb_called = 0;
@ -385,16 +387,16 @@ void test_nghttp2_session_recv(void)
} }
CU_ASSERT(1 == user_data.frame_recv_cb_called); CU_ASSERT(1 == user_data.frame_recv_cb_called);
nghttp2_buf_reset(&buf);
/* Received HEADERS without header block, which is valid */ /* Received HEADERS without header block, which is valid */
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
5, NGHTTP2_PRI_DEFAULT, NULL, 0); 5, NGHTTP2_PRI_DEFAULT, NULL, 0);
framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff, framelen = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
&frame.headers,
&deflater);
nghttp2_frame_headers_free(&frame.headers); nghttp2_frame_headers_free(&frame.headers);
scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff); scripted_data_feed_init(&df, buf.pos, nghttp2_buf_len(&buf));
user_data.frame_recv_cb_called = 0; user_data.frame_recv_cb_called = 0;
CU_ASSERT(0 == nghttp2_session_recv(session)); CU_ASSERT(0 == nghttp2_session_recv(session));
CU_ASSERT(1 == user_data.frame_recv_cb_called); CU_ASSERT(1 == user_data.frame_recv_cb_called);
@ -405,15 +407,21 @@ void test_nghttp2_session_recv(void)
/* Some tests for frame too large */ /* Some tests for frame too large */
nghttp2_session_server_new(&session, &callbacks, &user_data); nghttp2_session_server_new(&session, &callbacks, &user_data);
nghttp2_buf_reset(&buf);
/* Receive PING with too large payload */ /* Receive PING with too large payload */
nghttp2_frame_ping_init(&frame.ping, NGHTTP2_FLAG_NONE, NULL); nghttp2_frame_ping_init(&frame.ping, NGHTTP2_FLAG_NONE, NULL);
nghttp2_reserve_buffer(&framedata, &framedatalen, 77);
framelen = nghttp2_frame_pack_ping(&framedata, &framedatalen, &frame.ping); framelen = nghttp2_frame_pack_ping(&buf, &frame.ping);
/* Add extra 16 bytes */
nghttp2_buf_pos_reserve(&buf, nghttp2_buf_len(&buf) + 16);
buf.last += 16;
nghttp2_put_uint16be(buf.pos, frame.hd.length + 16);
nghttp2_frame_ping_free(&frame.ping); nghttp2_frame_ping_free(&frame.ping);
nghttp2_put_uint16be(&framedata[0], scripted_data_feed_init(&df, buf.pos, nghttp2_buf_len(&buf));
framedatalen - NGHTTP2_FRAME_HEAD_LENGTH);
scripted_data_feed_init(&df, framedata, framedatalen);
user_data.frame_recv_cb_called = 0; user_data.frame_recv_cb_called = 0;
CU_ASSERT(0 == nghttp2_session_recv(session)); CU_ASSERT(0 == nghttp2_session_recv(session));
CU_ASSERT(0 == user_data.frame_recv_cb_called); CU_ASSERT(0 == user_data.frame_recv_cb_called);
@ -422,7 +430,7 @@ void test_nghttp2_session_recv(void)
CU_ASSERT(NGHTTP2_FRAME_SIZE_ERROR == OB_CTRL(item)->goaway.error_code); CU_ASSERT(NGHTTP2_FRAME_SIZE_ERROR == OB_CTRL(item)->goaway.error_code);
CU_ASSERT(0 == nghttp2_session_send(session)); CU_ASSERT(0 == nghttp2_session_send(session));
free(framedata); nghttp2_buf_free(&buf);
nghttp2_session_del(session); nghttp2_session_del(session);
} }
@ -432,13 +440,13 @@ void test_nghttp2_session_recv_invalid_stream_id(void)
nghttp2_session_callbacks callbacks; nghttp2_session_callbacks callbacks;
scripted_data_feed df; scripted_data_feed df;
my_user_data user_data; my_user_data user_data;
uint8_t *framedata = NULL; nghttp2_buf buf;
size_t framedatalen = 0;
size_t bufoff;
ssize_t framelen; ssize_t framelen;
nghttp2_frame frame; nghttp2_frame frame;
nghttp2_hd_deflater deflater; nghttp2_hd_deflater deflater;
nghttp2_buf_init(&buf);
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.recv_callback = scripted_recv_callback; callbacks.recv_callback = scripted_recv_callback;
callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback; callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
@ -450,17 +458,17 @@ void test_nghttp2_session_recv_invalid_stream_id(void)
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 2, nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 2,
NGHTTP2_PRI_DEFAULT, NULL, 0); NGHTTP2_PRI_DEFAULT, NULL, 0);
framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff, framelen = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
&frame.headers,
&deflater);
scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff); CU_ASSERT(framelen == nghttp2_buf_len(&buf));
scripted_data_feed_init(&df, buf.pos, nghttp2_buf_len(&buf));
nghttp2_frame_headers_free(&frame.headers); nghttp2_frame_headers_free(&frame.headers);
CU_ASSERT(0 == nghttp2_session_recv(session)); CU_ASSERT(0 == nghttp2_session_recv(session));
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called); CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
free(framedata); nghttp2_buf_free(&buf);
nghttp2_hd_deflate_free(&deflater); nghttp2_hd_deflate_free(&deflater);
nghttp2_session_del(session); nghttp2_session_del(session);
} }
@ -474,15 +482,15 @@ void test_nghttp2_session_recv_invalid_frame(void)
const nghttp2_nv nv[] = { const nghttp2_nv nv[] = {
MAKE_NV("url", "/") MAKE_NV("url", "/")
}; };
uint8_t *framedata = NULL; nghttp2_buf buf;
size_t framedatalen = 0;
size_t bufoff;
ssize_t framelen; ssize_t framelen;
nghttp2_frame frame; nghttp2_frame frame;
nghttp2_nv *nva; nghttp2_nv *nva;
ssize_t nvlen; ssize_t nvlen;
nghttp2_hd_deflater deflater; nghttp2_hd_deflater deflater;
nghttp2_buf_init(&buf);
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.recv_callback = scripted_recv_callback; callbacks.recv_callback = scripted_recv_callback;
callbacks.send_callback = null_send_callback; callbacks.send_callback = null_send_callback;
@ -495,11 +503,11 @@ void test_nghttp2_session_recv_invalid_frame(void)
nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv)); nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv));
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1, nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1,
NGHTTP2_PRI_DEFAULT, nva, nvlen); NGHTTP2_PRI_DEFAULT, nva, nvlen);
framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff, framelen = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
&frame.headers,
&deflater);
scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff); CU_ASSERT(framelen == nghttp2_buf_len(&buf));
scripted_data_feed_init(&df, buf.pos, nghttp2_buf_len(&buf));
CU_ASSERT(0 == nghttp2_session_recv(session)); CU_ASSERT(0 == nghttp2_session_recv(session));
CU_ASSERT(0 == nghttp2_session_send(session)); CU_ASSERT(0 == nghttp2_session_send(session));
@ -507,13 +515,13 @@ void test_nghttp2_session_recv_invalid_frame(void)
/* Receive exactly same bytes of HEADERS is treated as subsequent /* Receive exactly same bytes of HEADERS is treated as subsequent
HEADERS (e.g., trailers */ HEADERS (e.g., trailers */
scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff); scripted_data_feed_init(&df, buf.pos, nghttp2_buf_len(&buf));
CU_ASSERT(0 == nghttp2_session_recv(session)); CU_ASSERT(0 == nghttp2_session_recv(session));
CU_ASSERT(0 == nghttp2_session_send(session)); CU_ASSERT(0 == nghttp2_session_send(session));
CU_ASSERT(0 == user_data.frame_send_cb_called); CU_ASSERT(0 == user_data.frame_send_cb_called);
free(framedata); nghttp2_buf_free(&buf);
nghttp2_frame_headers_free(&frame.headers); nghttp2_frame_headers_free(&frame.headers);
nghttp2_hd_deflate_free(&deflater); nghttp2_hd_deflate_free(&deflater);
@ -672,11 +680,7 @@ void test_nghttp2_session_recv_continuation(void)
nghttp2_nv *nva; nghttp2_nv *nva;
size_t nvlen; size_t nvlen;
nghttp2_frame frame; nghttp2_frame frame;
uint8_t *framedata = NULL; nghttp2_buf buf;
size_t framedatacap = 0;
size_t framedatalen;
size_t bufoff;
size_t framedataoff;
ssize_t rv; ssize_t rv;
my_user_data ud; my_user_data ud;
nghttp2_hd_deflater deflater; nghttp2_hd_deflater deflater;
@ -684,6 +688,8 @@ void test_nghttp2_session_recv_continuation(void)
size_t datalen; size_t datalen;
nghttp2_frame_hd cont_hd; nghttp2_frame_hd cont_hd;
nghttp2_buf_init(&buf);
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.on_header_callback = on_header_callback; callbacks.on_header_callback = on_header_callback;
callbacks.on_begin_headers_callback = on_begin_headers_callback; callbacks.on_begin_headers_callback = on_begin_headers_callback;
@ -696,15 +702,16 @@ void test_nghttp2_session_recv_continuation(void)
nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1));
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_NONE, nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_NONE,
1, NGHTTP2_PRI_DEFAULT, nva, nvlen); 1, NGHTTP2_PRI_DEFAULT, nva, nvlen);
framedatalen = nghttp2_frame_pack_headers(&framedata, &framedatacap, rv = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
&bufoff,
&frame.headers, CU_ASSERT(rv == nghttp2_buf_len(&buf));
&deflater);
nghttp2_frame_headers_free(&frame.headers); nghttp2_frame_headers_free(&frame.headers);
memcpy(data, framedata + bufoff, 9); /* HEADERS's payload is 1 byte */
memcpy(data, buf.pos, 9);
datalen = 9; datalen = 9;
framedataoff = bufoff + NGHTTP2_FRAME_HEAD_LENGTH + 1; buf.pos += 9;
nghttp2_put_uint16be(data, 1); nghttp2_put_uint16be(data, 1);
@ -715,25 +722,25 @@ void test_nghttp2_session_recv_continuation(void)
cont_hd.stream_id = 1; cont_hd.stream_id = 1;
nghttp2_frame_pack_frame_hd(data + datalen, &cont_hd); nghttp2_frame_pack_frame_hd(data + datalen, &cont_hd);
datalen += NGHTTP2_FRAME_HEAD_LENGTH; datalen += NGHTTP2_FRAME_HDLEN;
memcpy(data + datalen, framedata + framedataoff, cont_hd.length); memcpy(data + datalen, buf.pos, cont_hd.length);
datalen += cont_hd.length; datalen += cont_hd.length;
framedataoff += cont_hd.length; buf.pos += cont_hd.length;
/* Second CONTINUATION, rest of the bytes */ /* Second CONTINUATION, rest of the bytes */
cont_hd.length = framedatalen - framedataoff; cont_hd.length = nghttp2_buf_len(&buf);
cont_hd.flags = NGHTTP2_FLAG_END_HEADERS; cont_hd.flags = NGHTTP2_FLAG_END_HEADERS;
cont_hd.stream_id = 1; cont_hd.stream_id = 1;
nghttp2_frame_pack_frame_hd(data + datalen, &cont_hd); nghttp2_frame_pack_frame_hd(data + datalen, &cont_hd);
datalen += NGHTTP2_FRAME_HEAD_LENGTH; datalen += NGHTTP2_FRAME_HEAD_LENGTH;
memcpy(data + datalen, framedata + framedataoff, cont_hd.length); memcpy(data + datalen, buf.pos, cont_hd.length);
datalen += cont_hd.length; datalen += cont_hd.length;
framedataoff += cont_hd.length; buf.pos += cont_hd.length;
assert(framedataoff == framedatalen); CU_ASSERT(0 == nghttp2_buf_len(&buf));
ud.header_cb_called = 0; ud.header_cb_called = 0;
rv = nghttp2_session_mem_recv(session, data, datalen); rv = nghttp2_session_mem_recv(session, data, datalen);
@ -752,19 +759,25 @@ void test_nghttp2_session_recv_continuation(void)
nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1));
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_NONE, nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_NONE,
1, NGHTTP2_PRI_DEFAULT, nva, nvlen); 1, NGHTTP2_PRI_DEFAULT, nva, nvlen);
framedatalen = nghttp2_frame_pack_headers(&framedata, &framedatacap, &bufoff, nghttp2_buf_reset(&buf);
&frame.headers, rv = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
&deflater);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
nghttp2_frame_headers_free(&frame.headers); nghttp2_frame_headers_free(&frame.headers);
memcpy(data, framedata + bufoff, framedatalen - bufoff); memcpy(data, buf.pos, nghttp2_buf_len(&buf));
datalen = framedatalen - bufoff; datalen = nghttp2_buf_len(&buf);
/* Followed by PRIORITY */ /* Followed by PRIORITY */
nghttp2_frame_priority_init(&frame.priority, 1, 0); nghttp2_frame_priority_init(&frame.priority, 1, 0);
framedatalen = nghttp2_frame_pack_priority(&framedata, &framedatacap, nghttp2_buf_reset(&buf);
&frame.priority);
memcpy(data + datalen, framedata, framedatalen); rv = nghttp2_frame_pack_priority(&buf, &frame.priority);
datalen += framedatalen;
CU_ASSERT(rv == nghttp2_buf_len(&buf));
memcpy(data + datalen, buf.pos, nghttp2_buf_len(&buf));
datalen += nghttp2_buf_len(&buf);
ud.begin_headers_cb_called = 0; ud.begin_headers_cb_called = 0;
rv = nghttp2_session_mem_recv(session, data, datalen); rv = nghttp2_session_mem_recv(session, data, datalen);
@ -774,7 +787,7 @@ void test_nghttp2_session_recv_continuation(void)
CU_ASSERT(NGHTTP2_GOAWAY == CU_ASSERT(NGHTTP2_GOAWAY ==
OB_CTRL_TYPE(nghttp2_session_get_next_ob_item(session))); OB_CTRL_TYPE(nghttp2_session_get_next_ob_item(session)));
free(framedata); nghttp2_buf_free(&buf);
nghttp2_hd_deflate_free(&deflater); nghttp2_hd_deflate_free(&deflater);
nghttp2_session_del(session); nghttp2_session_del(session);
} }
@ -790,14 +803,13 @@ void test_nghttp2_session_recv_premature_headers(void)
nghttp2_nv *nva; nghttp2_nv *nva;
size_t nvlen; size_t nvlen;
nghttp2_frame frame; nghttp2_frame frame;
uint8_t *framedata = NULL; nghttp2_buf buf;
size_t framedatacap = 0;
size_t framedatalen;
ssize_t rv; ssize_t rv;
my_user_data ud; my_user_data ud;
nghttp2_hd_deflater deflater; nghttp2_hd_deflater deflater;
nghttp2_outbound_item *item; nghttp2_outbound_item *item;
size_t bufoff = 0;
nghttp2_buf_init(&buf);
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
@ -808,24 +820,24 @@ void test_nghttp2_session_recv_premature_headers(void)
nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1));
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
1, NGHTTP2_PRI_DEFAULT, nva, nvlen); 1, NGHTTP2_PRI_DEFAULT, nva, nvlen);
framedatalen = nghttp2_frame_pack_headers(&framedata, &framedatacap, rv = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
&bufoff,
&frame.headers, CU_ASSERT(rv == nghttp2_buf_len(&buf));
&deflater);
nghttp2_frame_headers_free(&frame.headers); nghttp2_frame_headers_free(&frame.headers);
/* Intentionally feed payload cutting last 1 byte off */ /* Intentionally feed payload cutting last 1 byte off */
nghttp2_put_uint16be(framedata + bufoff, frame.hd.length - 1); nghttp2_put_uint16be(buf.pos, frame.hd.length - 1);
rv = nghttp2_session_mem_recv(session, framedata + bufoff, rv = nghttp2_session_mem_recv(session, buf.pos, nghttp2_buf_len(&buf) - 1);
framedatalen - bufoff - 1);
CU_ASSERT((ssize_t)(framedatalen - bufoff - 1) == rv); CU_ASSERT((ssize_t)(nghttp2_buf_len(&buf) - 1) == rv);
item = nghttp2_session_get_next_ob_item(session); item = nghttp2_session_get_next_ob_item(session);
CU_ASSERT(NULL != item); CU_ASSERT(NULL != item);
CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(item)); CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(item));
CU_ASSERT(NGHTTP2_COMPRESSION_ERROR == OB_CTRL(item)->goaway.error_code); CU_ASSERT(NGHTTP2_COMPRESSION_ERROR == OB_CTRL(item)->goaway.error_code);
free(framedata); nghttp2_buf_free(&buf);
nghttp2_hd_deflate_free(&deflater); nghttp2_hd_deflate_free(&deflater);
nghttp2_session_del(session); nghttp2_session_del(session);
} }
@ -843,14 +855,11 @@ void test_nghttp2_session_continue(void)
MAKE_NV("user-agent", "nghttp2/1.0.0"), MAKE_NV("user-agent", "nghttp2/1.0.0"),
MAKE_NV("alpha", "bravo") MAKE_NV("alpha", "bravo")
}; };
uint8_t *framedata = NULL; nghttp2_buf buf;
size_t framedatalen = 0; size_t framelen1, framelen2;
ssize_t framelen1, framelen2;
ssize_t rv; ssize_t rv;
uint8_t buffer[4096]; uint8_t buffer[4096];
uint8_t *bufp = buffer; nghttp2_buf databuf;
size_t buflen;
size_t bufoff;
nghttp2_frame frame; nghttp2_frame frame;
nghttp2_nv *nva; nghttp2_nv *nva;
ssize_t nvlen; ssize_t nvlen;
@ -858,6 +867,9 @@ void test_nghttp2_session_continue(void)
nghttp2_frame_hd data_hd; nghttp2_frame_hd data_hd;
nghttp2_hd_deflater deflater; nghttp2_hd_deflater deflater;
nghttp2_buf_init(&buf);
nghttp2_buf_wrap_init(&databuf, buffer, sizeof(buffer));
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.send_callback = null_send_callback; callbacks.send_callback = null_send_callback;
callbacks.on_frame_recv_callback = on_frame_recv_callback; callbacks.on_frame_recv_callback = on_frame_recv_callback;
@ -873,38 +885,40 @@ void test_nghttp2_session_continue(void)
nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1));
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
1, NGHTTP2_PRI_DEFAULT, nva, nvlen); 1, NGHTTP2_PRI_DEFAULT, nva, nvlen);
framelen1 = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff, rv = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
&frame.headers,
&deflater); CU_ASSERT(rv == nghttp2_buf_len(&buf));
nghttp2_frame_headers_free(&frame.headers); nghttp2_frame_headers_free(&frame.headers);
memcpy(buffer, framedata + bufoff, framelen1 - bufoff); framelen1 = nghttp2_buf_len(&buf);
framelen1 -= bufoff; databuf.last = nghttp2_cpymem(databuf.last, buf.pos, nghttp2_buf_len(&buf));
nvlen = nghttp2_nv_array_copy(&nva, nv2, ARRLEN(nv2)); nvlen = nghttp2_nv_array_copy(&nva, nv2, ARRLEN(nv2));
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
3, NGHTTP2_PRI_DEFAULT, nva, nvlen); 3, NGHTTP2_PRI_DEFAULT, nva, nvlen);
framelen2 = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff, nghttp2_buf_reset(&buf);
&frame.headers, rv = nghttp2_frame_pack_headers(&buf, &frame.headers, &deflater);
&deflater);
CU_ASSERT(rv == nghttp2_buf_len(&buf));
nghttp2_frame_headers_free(&frame.headers); nghttp2_frame_headers_free(&frame.headers);
memcpy(buffer + framelen1, framedata + bufoff, framelen2 - bufoff); framelen2 = nghttp2_buf_len(&buf);
framelen2 -= bufoff; databuf.last = nghttp2_cpymem(databuf.last, buf.pos, nghttp2_buf_len(&buf));
buflen = framelen1 + framelen2;
/* Receive 1st HEADERS and pause */ /* Receive 1st HEADERS and pause */
user_data.begin_headers_cb_called = 0; user_data.begin_headers_cb_called = 0;
user_data.header_cb_called = 0; user_data.header_cb_called = 0;
rv = nghttp2_session_mem_recv(session, bufp, buflen); rv = nghttp2_session_mem_recv(session,
databuf.pos, nghttp2_buf_len(&databuf));
bufp += rv; CU_ASSERT(rv >= 0);
buflen -= rv; databuf.pos += rv;
recv_frame = user_data.frame; recv_frame = user_data.frame;
CU_ASSERT(NGHTTP2_HEADERS == recv_frame->hd.type); CU_ASSERT(NGHTTP2_HEADERS == recv_frame->hd.type);
CU_ASSERT((size_t)framelen1 - NGHTTP2_FRAME_HEAD_LENGTH == CU_ASSERT(framelen1 - NGHTTP2_FRAME_HEAD_LENGTH == recv_frame->hd.length);
recv_frame->hd.length);
CU_ASSERT(1 == user_data.begin_headers_cb_called); CU_ASSERT(1 == user_data.begin_headers_cb_called);
CU_ASSERT(1 == user_data.header_cb_called); CU_ASSERT(1 == user_data.header_cb_called);
@ -914,10 +928,11 @@ void test_nghttp2_session_continue(void)
/* get 2nd header field */ /* get 2nd header field */
user_data.begin_headers_cb_called = 0; user_data.begin_headers_cb_called = 0;
user_data.header_cb_called = 0; user_data.header_cb_called = 0;
rv = nghttp2_session_mem_recv(session, bufp, buflen); rv = nghttp2_session_mem_recv(session,
databuf.pos, nghttp2_buf_len(&databuf));
bufp += rv; CU_ASSERT(rv >= 0);
buflen -= rv; databuf.pos += rv;
CU_ASSERT(0 == user_data.begin_headers_cb_called); CU_ASSERT(0 == user_data.begin_headers_cb_called);
CU_ASSERT(1 == user_data.header_cb_called); CU_ASSERT(1 == user_data.header_cb_called);
@ -927,15 +942,15 @@ void test_nghttp2_session_continue(void)
/* will call end_headers_callback and receive 2nd HEADERS and pause */ /* will call end_headers_callback and receive 2nd HEADERS and pause */
user_data.begin_headers_cb_called = 0; user_data.begin_headers_cb_called = 0;
user_data.header_cb_called = 0; user_data.header_cb_called = 0;
rv = nghttp2_session_mem_recv(session, bufp, buflen); rv = nghttp2_session_mem_recv(session,
databuf.pos, nghttp2_buf_len(&databuf));
bufp += rv; CU_ASSERT(rv >= 0);
buflen -= rv; databuf.pos += rv;
recv_frame = user_data.frame; recv_frame = user_data.frame;
CU_ASSERT(NGHTTP2_HEADERS == recv_frame->hd.type); CU_ASSERT(NGHTTP2_HEADERS == recv_frame->hd.type);
CU_ASSERT((size_t)framelen2 - NGHTTP2_FRAME_HEAD_LENGTH == CU_ASSERT(framelen2 - NGHTTP2_FRAME_HEAD_LENGTH == recv_frame->hd.length);
recv_frame->hd.length);
CU_ASSERT(1 == user_data.begin_headers_cb_called); CU_ASSERT(1 == user_data.begin_headers_cb_called);
CU_ASSERT(1 == user_data.header_cb_called); CU_ASSERT(1 == user_data.header_cb_called);
@ -945,10 +960,11 @@ void test_nghttp2_session_continue(void)
/* get 2nd header field */ /* get 2nd header field */
user_data.begin_headers_cb_called = 0; user_data.begin_headers_cb_called = 0;
user_data.header_cb_called = 0; user_data.header_cb_called = 0;
rv = nghttp2_session_mem_recv(session, bufp, buflen); rv = nghttp2_session_mem_recv(session,
databuf.pos, nghttp2_buf_len(&databuf));
bufp += rv; CU_ASSERT(rv >= 0);
buflen -= rv; databuf.pos += rv;
CU_ASSERT(0 == user_data.begin_headers_cb_called); CU_ASSERT(0 == user_data.begin_headers_cb_called);
CU_ASSERT(1 == user_data.header_cb_called); CU_ASSERT(1 == user_data.header_cb_called);
@ -959,10 +975,11 @@ void test_nghttp2_session_continue(void)
user_data.begin_headers_cb_called = 0; user_data.begin_headers_cb_called = 0;
user_data.header_cb_called = 0; user_data.header_cb_called = 0;
user_data.frame_recv_cb_called = 0; user_data.frame_recv_cb_called = 0;
rv = nghttp2_session_mem_recv(session, bufp, buflen); rv = nghttp2_session_mem_recv(session,
databuf.pos, nghttp2_buf_len(&databuf));
bufp += rv; CU_ASSERT(rv >= 0);
buflen -= rv; databuf.pos += rv;
CU_ASSERT(0 == user_data.begin_headers_cb_called); CU_ASSERT(0 == user_data.begin_headers_cb_called);
CU_ASSERT(0 == user_data.header_cb_called); CU_ASSERT(0 == user_data.header_cb_called);
@ -973,13 +990,18 @@ void test_nghttp2_session_continue(void)
data_hd.type = NGHTTP2_DATA; data_hd.type = NGHTTP2_DATA;
data_hd.flags = NGHTTP2_FLAG_NONE; data_hd.flags = NGHTTP2_FLAG_NONE;
data_hd.stream_id = 1; data_hd.stream_id = 1;
nghttp2_frame_pack_frame_hd(buffer, &data_hd);
bufp = buffer; nghttp2_buf_reset(&databuf);
buflen = sizeof(buffer); nghttp2_frame_pack_frame_hd(databuf.pos, &data_hd);
/* Intentionally specify larger buffer size to see pause is kicked /* Intentionally specify larger buffer size to see pause is kicked
in. */ in. */
databuf.last = databuf.end;
user_data.frame_recv_cb_called = 0; user_data.frame_recv_cb_called = 0;
rv = nghttp2_session_mem_recv(session, buffer, sizeof(buffer)); rv = nghttp2_session_mem_recv(session,
databuf.pos, nghttp2_buf_len(&databuf));
CU_ASSERT(16 + NGHTTP2_FRAME_HEAD_LENGTH == rv); CU_ASSERT(16 + NGHTTP2_FRAME_HEAD_LENGTH == rv);
CU_ASSERT(0 == user_data.frame_recv_cb_called); CU_ASSERT(0 == user_data.frame_recv_cb_called);
@ -987,7 +1009,8 @@ void test_nghttp2_session_continue(void)
pause again in on_data_chunk_recv_callback since we pass same pause again in on_data_chunk_recv_callback since we pass same
DATA frame. */ DATA frame. */
user_data.frame_recv_cb_called = 0; user_data.frame_recv_cb_called = 0;
rv = nghttp2_session_mem_recv(session, buffer, sizeof(buffer)); rv = nghttp2_session_mem_recv(session,
databuf.pos, nghttp2_buf_len(&databuf));
CU_ASSERT(16 + NGHTTP2_FRAME_HEAD_LENGTH == rv); CU_ASSERT(16 + NGHTTP2_FRAME_HEAD_LENGTH == rv);
CU_ASSERT(1 == user_data.frame_recv_cb_called); CU_ASSERT(1 == user_data.frame_recv_cb_called);
@ -997,7 +1020,7 @@ void test_nghttp2_session_continue(void)
CU_ASSERT(0 == rv); CU_ASSERT(0 == rv);
CU_ASSERT(1 == user_data.frame_recv_cb_called); CU_ASSERT(1 == user_data.frame_recv_cb_called);
free(framedata); nghttp2_buf_free(&buf);
nghttp2_hd_deflate_free(&deflater); nghttp2_hd_deflate_free(&deflater);
nghttp2_session_del(session); nghttp2_session_del(session);
} }
@ -1022,13 +1045,16 @@ void test_nghttp2_session_add_frame(void)
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.send_callback = accumulator_send_callback; callbacks.send_callback = accumulator_send_callback;
memset(aux_data, 0, sizeof(nghttp2_headers_aux_data)); memset(aux_data, 0, sizeof(nghttp2_headers_aux_data));
acc.length = 0; acc.length = 0;
user_data.acc = &acc; user_data.acc = &acc;
CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &user_data)); CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &user_data));
frame = malloc(sizeof(nghttp2_frame)); frame = malloc(sizeof(nghttp2_frame));
nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv)); nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv));
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,
-1, NGHTTP2_PRI_DEFAULT, nva, nvlen); -1, NGHTTP2_PRI_DEFAULT, nva, nvlen);
@ -2239,6 +2265,8 @@ void test_nghttp2_submit_data(void)
my_user_data ud; my_user_data ud;
nghttp2_private_data *data_frame; nghttp2_private_data *data_frame;
nghttp2_frame_hd hd; nghttp2_frame_hd hd;
nghttp2_active_outbound_item *aob;
nghttp2_buf *framebuf;
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.send_callback = block_count_send_callback; callbacks.send_callback = block_count_send_callback;
@ -2246,6 +2274,8 @@ void test_nghttp2_submit_data(void)
data_prd.read_callback = fixed_length_data_source_read_callback; data_prd.read_callback = fixed_length_data_source_read_callback;
ud.data_source_length = NGHTTP2_DATA_PAYLOAD_LENGTH * 2; ud.data_source_length = NGHTTP2_DATA_PAYLOAD_LENGTH * 2;
CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud)); CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud));
aob = &session->aob;
framebuf = &aob->framebuf;
nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
NGHTTP2_PRI_DEFAULT, NGHTTP2_STREAM_OPENING, NGHTTP2_PRI_DEFAULT, NGHTTP2_STREAM_OPENING,
@ -2253,12 +2283,12 @@ void test_nghttp2_submit_data(void)
CU_ASSERT(0 == nghttp2_submit_data(session, CU_ASSERT(0 == nghttp2_submit_data(session,
NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_STREAM |
NGHTTP2_FLAG_END_SEGMENT, 1, &data_prd)); NGHTTP2_FLAG_END_SEGMENT, 1, &data_prd));
ud.block_count = 0; ud.block_count = 0;
CU_ASSERT(0 == nghttp2_session_send(session)); CU_ASSERT(0 == nghttp2_session_send(session));
data_frame = nghttp2_outbound_item_get_data_frame(session->aob.item); data_frame = nghttp2_outbound_item_get_data_frame(aob->item);
nghttp2_frame_unpack_frame_hd(&hd, nghttp2_frame_unpack_frame_hd(&hd, framebuf->pos);
session->aob.framebuf +
session->aob.framebufoff);
CU_ASSERT(NGHTTP2_FLAG_NONE == hd.flags); CU_ASSERT(NGHTTP2_FLAG_NONE == hd.flags);
/* frame->hd.flags has these flags */ /* frame->hd.flags has these flags */
CU_ASSERT((NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_SEGMENT) == CU_ASSERT((NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_SEGMENT) ==
@ -2266,10 +2296,9 @@ void test_nghttp2_submit_data(void)
ud.block_count = 1; ud.block_count = 1;
CU_ASSERT(0 == nghttp2_session_send(session)); CU_ASSERT(0 == nghttp2_session_send(session));
data_frame = nghttp2_outbound_item_get_data_frame(session->aob.item); data_frame = nghttp2_outbound_item_get_data_frame(aob->item);
nghttp2_frame_unpack_frame_hd(&hd, nghttp2_frame_unpack_frame_hd(&hd, framebuf->pos);
session->aob.framebuf +
session->aob.framebufoff);
/* This is the last frame, so we must have following flags */ /* This is the last frame, so we must have following flags */
CU_ASSERT((NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_SEGMENT) == hd.flags); CU_ASSERT((NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_SEGMENT) == hd.flags);
/* frame->hd.flags has these flags */ /* frame->hd.flags has these flags */
@ -4100,8 +4129,8 @@ void test_nghttp2_session_pack_data_with_padding(void)
/* Check reception of this DATA frame */ /* Check reception of this DATA frame */
check_session_recv_data_with_padding check_session_recv_data_with_padding
(session->aob.framebuf + session->aob.framebufoff, (session->aob.framebuf.pos,
session->aob.framebufmark - session->aob.framebufoff, session->aob.framebuf.mark - session->aob.framebuf.pos,
datalen); datalen);
nghttp2_session_del(session); nghttp2_session_del(session);
@ -4126,8 +4155,8 @@ void test_nghttp2_session_pack_data_with_padding(void)
/* Check reception of this DATA frame */ /* Check reception of this DATA frame */
check_session_recv_data_with_padding check_session_recv_data_with_padding
(session->aob.framebuf + session->aob.framebufoff, (session->aob.framebuf.pos,
session->aob.framebufmark - session->aob.framebufoff, session->aob.framebuf.mark - session->aob.framebuf.pos,
datalen); datalen);
nghttp2_session_del(session); nghttp2_session_del(session);
@ -4158,6 +4187,8 @@ void test_nghttp2_session_pack_headers_with_padding(void)
acc.length = 0; acc.length = 0;
ud.acc = &acc; ud.acc = &acc;
/* In this test, padding is laid out across 2 frames: HEADERS and
CONTINUATION frames */
nghttp2_session_client_new(&session, &callbacks, &ud); nghttp2_session_client_new(&session, &callbacks, &ud);
nghttp2_session_server_new(&sv_session, &callbacks, &ud); nghttp2_session_server_new(&sv_session, &callbacks, &ud);
@ -4193,6 +4224,147 @@ void test_nghttp2_session_pack_headers_with_padding(void)
nghttp2_session_del(session); nghttp2_session_del(session);
} }
void test_nghttp2_session_pack_headers_with_padding2(void)
{
nghttp2_session *session, *sv_session;
accumulator acc;
my_user_data ud;
nghttp2_session_callbacks callbacks;
nghttp2_nv nva[16382];
size_t i;
for(i = 0; i < ARRLEN(nva); ++i) {
nva[i].name = (uint8_t*)":path";
nva[i].namelen = 5;
nva[i].value = (uint8_t*)"/";
nva[i].valuelen = 1;
}
memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = accumulator_send_callback;
callbacks.on_frame_send_callback = on_frame_send_callback;
callbacks.select_padding_callback = select_padding_callback;
callbacks.on_frame_recv_callback = on_frame_recv_callback;
acc.length = 0;
ud.acc = &acc;
/* In this test, padding is laid out across 2 frames: HEADERS and
CONTINUATION frames */
nghttp2_session_client_new(&session, &callbacks, &ud);
nghttp2_session_server_new(&sv_session, &callbacks, &ud);
ud.padding_boundary = 16385;
CU_ASSERT(0 ==
nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT,
nva, ARRLEN(nva), NULL, NULL));
CU_ASSERT(0 == nghttp2_session_send(session));
CU_ASSERT(acc.length > NGHTTP2_MAX_FRAME_LENGTH);
ud.frame_recv_cb_called = 0;
CU_ASSERT((ssize_t)acc.length ==
nghttp2_session_mem_recv(sv_session, acc.buf, acc.length));
CU_ASSERT(1 == ud.frame_recv_cb_called);
CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(sv_session));
nghttp2_session_del(sv_session);
nghttp2_session_del(session);
}
void test_nghttp2_session_pack_headers_with_padding3(void)
{
nghttp2_session *session, *sv_session;
accumulator acc;
my_user_data ud;
nghttp2_session_callbacks callbacks;
nghttp2_nv nva[8192];
size_t i;
for(i = 0; i < ARRLEN(nva); ++i) {
nva[i].name = (uint8_t*)":path";
nva[i].namelen = 5;
nva[i].value = (uint8_t*)"/";
nva[i].valuelen = 1;
}
memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = accumulator_send_callback;
callbacks.on_frame_send_callback = on_frame_send_callback;
callbacks.select_padding_callback = select_padding_callback;
callbacks.on_frame_recv_callback = on_frame_recv_callback;
acc.length = 0;
ud.acc = &acc;
/* In this test, padding is included in the last CONTINUATION
frame */
nghttp2_session_client_new(&session, &callbacks, &ud);
nghttp2_session_server_new(&sv_session, &callbacks, &ud);
ud.padding_boundary = 16385;
CU_ASSERT(0 ==
nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT,
nva, ARRLEN(nva), NULL, NULL));
CU_ASSERT(0 == nghttp2_session_send(session));
CU_ASSERT(acc.length > NGHTTP2_MAX_FRAME_LENGTH);
ud.frame_recv_cb_called = 0;
CU_ASSERT((ssize_t)acc.length ==
nghttp2_session_mem_recv(sv_session, acc.buf, acc.length));
CU_ASSERT(1 == ud.frame_recv_cb_called);
CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(sv_session));
nghttp2_session_del(sv_session);
nghttp2_session_del(session);
}
void test_nghttp2_session_pack_headers_with_padding4(void)
{
nghttp2_session *session, *sv_session;
accumulator acc;
my_user_data ud;
nghttp2_session_callbacks callbacks;
nghttp2_nv nva[1];
nva[0].name = (uint8_t*)":path";
nva[0].namelen = 5;
nva[0].value = (uint8_t*)"/";
nva[0].valuelen = 1;
memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = accumulator_send_callback;
callbacks.on_frame_send_callback = on_frame_send_callback;
callbacks.select_padding_callback = select_padding_callback;
callbacks.on_frame_recv_callback = on_frame_recv_callback;
acc.length = 0;
ud.acc = &acc;
/* In this test, padding is included in the first HEADERS frame */
nghttp2_session_client_new(&session, &callbacks, &ud);
nghttp2_session_server_new(&sv_session, &callbacks, &ud);
ud.padding_boundary = 16385;
CU_ASSERT(0 ==
nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT,
nva, ARRLEN(nva), NULL, NULL));
CU_ASSERT(0 == nghttp2_session_send(session));
CU_ASSERT(acc.length < NGHTTP2_MAX_FRAME_LENGTH);
ud.frame_recv_cb_called = 0;
CU_ASSERT((ssize_t)acc.length ==
nghttp2_session_mem_recv(sv_session, acc.buf, acc.length));
CU_ASSERT(1 == ud.frame_recv_cb_called);
CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(sv_session));
nghttp2_session_del(sv_session);
nghttp2_session_del(session);
}
void test_nghttp2_pack_settings_payload(void) void test_nghttp2_pack_settings_payload(void)
{ {
nghttp2_settings_entry iv[2]; nghttp2_settings_entry iv[2];

View File

@ -92,6 +92,9 @@ void test_nghttp2_session_set_option(void);
void test_nghttp2_session_data_backoff_by_high_pri_frame(void); void test_nghttp2_session_data_backoff_by_high_pri_frame(void);
void test_nghttp2_session_pack_data_with_padding(void); void test_nghttp2_session_pack_data_with_padding(void);
void test_nghttp2_session_pack_headers_with_padding(void); void test_nghttp2_session_pack_headers_with_padding(void);
void test_nghttp2_session_pack_headers_with_padding2(void);
void test_nghttp2_session_pack_headers_with_padding3(void);
void test_nghttp2_session_pack_headers_with_padding4(void);
void test_nghttp2_pack_settings_payload(void); void test_nghttp2_pack_settings_payload(void);
#endif /* NGHTTP2_SESSION_TEST_H */ #endif /* NGHTTP2_SESSION_TEST_H */

View File

@ -28,6 +28,11 @@
#include <CUnit/CUnit.h> #include <CUnit/CUnit.h>
int unpack_framebuf(nghttp2_frame *frame, nghttp2_buf *buf)
{
return unpack_frame(frame, buf->pos, nghttp2_buf_len(buf));
}
int unpack_frame(nghttp2_frame *frame, const uint8_t *in, size_t len) int unpack_frame(nghttp2_frame *frame, const uint8_t *in, size_t len)
{ {
ssize_t rv = 0; ssize_t rv = 0;

View File

@ -54,6 +54,8 @@
free(a); \ free(a); \
} while(0); } while(0);
int unpack_framebuf(nghttp2_frame *frame, nghttp2_buf *buf);
int unpack_frame(nghttp2_frame *frame, const uint8_t *in, size_t len); int unpack_frame(nghttp2_frame *frame, const uint8_t *in, size_t len);
int strmemeq(const char *a, const uint8_t *b, size_t bn); int strmemeq(const char *a, const uint8_t *b, size_t bn);