Incremental name/value block decompression

This commit is contained in:
Tatsuhiro Tsujikawa 2012-05-25 10:46:40 +09:00
parent a18f04e8c7
commit a6ae4fc72c
15 changed files with 740 additions and 455 deletions

View File

@ -27,6 +27,9 @@
#include <assert.h>
#include <string.h>
#include "spdylay_net.h"
#include "spdylay_helper.h"
void spdylay_buffer_init(spdylay_buffer *buffer, size_t chunk_capacity)
{
buffer->root.data = NULL;
@ -99,6 +102,27 @@ void spdylay_buffer_advance(spdylay_buffer *buffer, size_t amount)
assert(buffer->last_offset <= buffer->capacity);
}
int spdylay_buffer_write(spdylay_buffer *buffer, const uint8_t *data,
size_t len)
{
int rv;
size_t i;
while(len) {
size_t writelen;
if(spdylay_buffer_avail(buffer) == 0) {
if((rv = spdylay_buffer_alloc(buffer)) != 0) {
return rv;
}
}
writelen = spdylay_min(spdylay_buffer_avail(buffer), len);
memcpy(spdylay_buffer_get(buffer), data, writelen);
data += writelen;
len -= writelen;
spdylay_buffer_advance(buffer, writelen);
}
return 0;
}
size_t spdylay_buffer_length(spdylay_buffer *buffer)
{
return buffer->len;
@ -130,3 +154,66 @@ void spdylay_buffer_reset(spdylay_buffer *buffer)
buffer->len = 0;
buffer->last_offset = buffer->capacity;
}
void spdylay_buffer_reader_init(spdylay_buffer_reader *reader,
spdylay_buffer *buffer)
{
reader->buffer = buffer;
reader->current = buffer->root.next;
reader->offset = 0;
}
uint8_t spdylay_buffer_reader_uint8(spdylay_buffer_reader *reader)
{
uint8_t out;
spdylay_buffer_reader_data(reader, &out, sizeof(uint8_t));
return out;
}
uint16_t spdylay_buffer_reader_uint16(spdylay_buffer_reader *reader)
{
uint16_t out;
spdylay_buffer_reader_data(reader, (uint8_t*)&out, sizeof(uint16_t));
return ntohs(out);
}
uint32_t spdylay_buffer_reader_uint32(spdylay_buffer_reader *reader)
{
uint32_t out;
spdylay_buffer_reader_data(reader, (uint8_t*)&out, sizeof(uint32_t));
return ntohl(out);
}
void spdylay_buffer_reader_data(spdylay_buffer_reader *reader,
uint8_t *out, size_t len)
{
while(len) {
size_t remlen, readlen;
remlen = reader->buffer->capacity - reader->offset;
readlen = spdylay_min(remlen, len);
memcpy(out, reader->current->data + reader->offset, readlen);
out += readlen;
len -= readlen;
reader->offset += readlen;
if(reader->buffer->capacity == reader->offset) {
reader->current = reader->current->next;
reader->offset = 0;
}
}
}
void spdylay_buffer_reader_advance(spdylay_buffer_reader *reader,
size_t amount)
{
while(amount) {
size_t remlen, skiplen;
remlen = reader->buffer->capacity - reader->offset;
skiplen = spdylay_min(remlen, amount);
amount -= skiplen;
reader->offset += skiplen;
if(reader->buffer->capacity == reader->offset) {
reader->current = reader->current->next;
reader->offset = 0;
}
}
}

View File

@ -66,6 +66,23 @@ size_t spdylay_buffer_avail(spdylay_buffer *buffer);
/* Advances buffer pointer by amount. This reduces available buffer
length. */
void spdylay_buffer_advance(spdylay_buffer *buffer, size_t amount);
/*
* Writes the |data| with the |len| bytes starting at the current
* position of the |buffer|. The new chunk buffer will be allocated on
* the course of the write and the current position is updated. If
* this function succeeds, the total length of the |buffer| will be
* increased by |len|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* SPDYLAY_ERR_NOMEM
* Out of memory.
*/
int spdylay_buffer_write(spdylay_buffer *buffer, const uint8_t *data,
size_t len);
/*
* Allocate new chunk buffer. This will increase total length of
* buffer (returned by spdylay_buffer_length) by capacity-last_offset.
@ -94,4 +111,53 @@ void spdylay_buffer_serialize(spdylay_buffer *buffer, uint8_t *buf);
allocated memory space; they are reused. */
void spdylay_buffer_reset(spdylay_buffer *buffer);
/*
* Reader interface to read data from spdylay_buffer sequentially.
*/
typedef struct {
/* The buffer to read */
spdylay_buffer *buffer;
/* Pointer to the current chunk to read. */
spdylay_buffer_chunk *current;
/* Offset to the current chunk data to read. */
size_t offset;
} spdylay_buffer_reader;
/*
* Initializes the |reader| with the |buffer|.
*/
void spdylay_buffer_reader_init(spdylay_buffer_reader *reader,
spdylay_buffer *buffer);
/*
* Reads 1 byte and return it. This function will advance the current
* position by 1.
*/
uint8_t spdylay_buffer_reader_uint8(spdylay_buffer_reader *reader);
/*
* Reads 2 bytes integer in network byte order and returns it in host
* byte order. This function will advance the current position by 2.
*/
uint16_t spdylay_buffer_reader_uint16(spdylay_buffer_reader *reader);
/*
* Reads 4 bytes integer in network byte order and returns it in host
* byte order. This function will advance the current position by 4.
*/
uint32_t spdylay_buffer_reader_uint32(spdylay_buffer_reader *reader);
/*
* Reads |len| bytes and store them in the |out|. This function will
* advance the current position by |len|.
*/
void spdylay_buffer_reader_data(spdylay_buffer_reader *reader,
uint8_t *out, size_t len);
/*
* Advances the current position by |amount|.
*/
void spdylay_buffer_reader_advance(spdylay_buffer_reader *reader,
size_t amount);
#endif /* SPDYLAY_BUFFER_H */

View File

@ -110,20 +110,23 @@ ssize_t spdylay_frame_alloc_pack_nv(uint8_t **buf_ptr,
return framelen;
}
int spdylay_frame_count_unpack_nv_space
(size_t *nvlen_ptr, size_t *buflen_ptr, const uint8_t *in, size_t inlen,
size_t len_size)
int spdylay_frame_count_unpack_nv_space(size_t *nvlen_ptr, size_t *buflen_ptr,
spdylay_buffer *in, size_t len_size)
{
uint32_t n;
size_t buflen = 0;
size_t nvlen = 0;
size_t off = 0;
size_t inlen = spdylay_buffer_length(in);
size_t i;
spdylay_buffer_reader reader;
if(inlen < len_size) {
return SPDYLAY_ERR_INVALID_FRAME;
}
spdylay_buffer_reader_init(&reader, in);
/* TODO limit n in a reasonable number */
n = spdylay_frame_get_nv_len(in, len_size);
n = spdylay_frame_get_nv_len(&reader, len_size);
off += len_size;
for(i = 0; i < n; ++i) {
uint32_t len;
@ -132,16 +135,20 @@ int spdylay_frame_count_unpack_nv_space
if(inlen-off < len_size) {
return SPDYLAY_ERR_INVALID_FRAME;
}
len = spdylay_frame_get_nv_len(in+off, len_size);
len = spdylay_frame_get_nv_len(&reader, len_size);
off += len_size;
if(inlen-off < len) {
return SPDYLAY_ERR_INVALID_FRAME;
}
buflen += len+1;
off += len;
if(j == 0) {
spdylay_buffer_reader_advance(&reader, len);
}
}
for(j = off, off -= len; off != j; ++off) {
if(in[off] == '\0') {
uint8_t b = spdylay_buffer_reader_uint8(&reader);
if(b == '\0') {
++nvlen;
}
}
@ -149,7 +156,6 @@ int spdylay_frame_count_unpack_nv_space
}
if(inlen == off) {
*nvlen_ptr = nvlen;
*buflen_ptr = buflen+(nvlen*2+1)*sizeof(char*);
return 0;
} else {
@ -157,89 +163,7 @@ int spdylay_frame_count_unpack_nv_space
}
}
static int spdylay_length_prefix_str_compar2(const void *lhs, const void *rhs)
{
ssize_t lhslen, rhslen, complen;
int r;
lhslen = spdylay_get_uint16(*(uint8_t**)lhs);
rhslen = spdylay_get_uint16(*(uint8_t**)rhs);
complen = spdylay_min(lhslen, rhslen);
r = memcmp(*(uint8_t**)lhs+2, *(uint8_t**)rhs+2, complen);
if(r == 0) {
return lhslen-rhslen;
} else {
return r;
}
}
static int spdylay_length_prefix_str_compar4(const void *lhs, const void *rhs)
{
ssize_t lhslen, rhslen, complen;
int r;
/* Assuming the returned value does not exceed the maximum value of
ssize_t */
lhslen = spdylay_get_uint32(*(uint8_t**)lhs);
rhslen = spdylay_get_uint32(*(uint8_t**)rhs);
complen = spdylay_min(lhslen, rhslen);
r = memcmp(*(uint8_t**)lhs+4, *(uint8_t**)rhs+4, complen);
if(r == 0) {
return lhslen-rhslen;
} else {
return r;
}
}
int spdylay_frame_unpack_nv_check_name(uint8_t *buf, size_t buflen,
const uint8_t *in, size_t inlen,
size_t len_size)
{
uint32_t n;
size_t i;
const uint8_t **idx;
n = spdylay_frame_get_nv_len(in, len_size);
assert(n*sizeof(char*) <= buflen);
in += len_size;
idx = (const uint8_t**)buf;
for(i = 0; i < n; ++i) {
uint32_t len;
size_t j;
len = spdylay_frame_get_nv_len(in, len_size);
if(len == 0) {
return SPDYLAY_ERR_INVALID_HEADER_BLOCK;
}
*idx++ = in;
in += len_size;
for(j = 0; j < len; ++j) {
unsigned char c = in[j];
if(c < 0x20 || c > 0x7e || ('A' <= c && c <= 'Z')) {
return SPDYLAY_ERR_INVALID_HEADER_BLOCK;
}
}
in += len;
len = spdylay_frame_get_nv_len(in, len_size);
in += len_size+len;
}
if(n > 0) {
uint32_t len1, len2;
qsort(buf, n, sizeof(uint8_t*),
len_size == 2 ?
spdylay_length_prefix_str_compar2 :
spdylay_length_prefix_str_compar4);
idx = (const uint8_t**)buf;
len1 = spdylay_frame_get_nv_len(*idx, len_size);
for(i = 1; i < n; ++i) {
len2 = spdylay_frame_get_nv_len(*(idx+i), len_size);
if(len1 == len2 && memcmp(*(idx+i-1)+len_size, *(idx+i)+len_size,
len1) == 0) {
return SPDYLAY_ERR_INVALID_HEADER_BLOCK;
}
len1 = len2;
}
}
return 0;
}
int spdylay_frame_unpack_nv(char ***nv_ptr, const uint8_t *in, size_t inlen,
int spdylay_frame_unpack_nv(char ***nv_ptr, spdylay_buffer *in,
size_t len_size)
{
size_t nvlen, buflen;
@ -248,44 +172,42 @@ int spdylay_frame_unpack_nv(char ***nv_ptr, const uint8_t *in, size_t inlen,
char *buf, **idx, *data;
uint32_t n;
int invalid_header_block = 0;
r = spdylay_frame_count_unpack_nv_space(&nvlen, &buflen, in, inlen, len_size);
spdylay_buffer_reader reader;
r = spdylay_frame_count_unpack_nv_space(&nvlen, &buflen, in, len_size);
if(r != 0) {
return r;
}
buf = malloc(buflen);
if(buf == NULL) {
return SPDYLAY_ERR_NOMEM;
}
r = spdylay_frame_unpack_nv_check_name((uint8_t*)buf, buflen, in, inlen,
len_size);
if(r == SPDYLAY_ERR_INVALID_HEADER_BLOCK) {
invalid_header_block = 1;
r = 0;
} else if(r != 0) {
free(buf);
return r;
}
spdylay_buffer_reader_init(&reader, in);
idx = (char**)buf;
data = buf+(nvlen*2+1)*sizeof(char*);
n = spdylay_frame_get_nv_len(in, len_size);
in += len_size;
n = spdylay_frame_get_nv_len(&reader, len_size);
for(i = 0; i < n; ++i) {
uint32_t len;
char *name, *val;
char *stop;
len = spdylay_frame_get_nv_len(in, len_size);
in += len_size;
len = spdylay_frame_get_nv_len(&reader, len_size);
if(len == 0) {
invalid_header_block = 1;
}
name = data;
memcpy(data, in, len);
data += len;
spdylay_buffer_reader_data(&reader, (uint8_t*)data, len);
for(stop = data+len; data != stop; ++data) {
unsigned char c = *data;
if(c < 0x20 || c > 0x7e || ('A' <= c && c <= 'Z')) {
invalid_header_block = 1;
}
}
*data = '\0';
++data;
in += len;
len = spdylay_frame_get_nv_len(in, len_size);
in += len_size;
len = spdylay_frame_get_nv_len(&reader, len_size);
val = data;
memcpy(data, in, len);
spdylay_buffer_reader_data(&reader, (uint8_t*)data, len);
for(stop = data+len; data != stop; ++data) {
if(*data == '\0') {
@ -299,7 +221,6 @@ int spdylay_frame_unpack_nv(char ***nv_ptr, const uint8_t *in, size_t inlen,
}
*data = '\0';
++data;
in += len;
*idx++ = name;
*idx++ = val;
@ -307,31 +228,17 @@ int spdylay_frame_unpack_nv(char ***nv_ptr, const uint8_t *in, size_t inlen,
*idx = NULL;
assert((size_t)((char*)idx - buf) == (nvlen*2)*sizeof(char*));
*nv_ptr = (char**)buf;
return invalid_header_block ? SPDYLAY_ERR_INVALID_HEADER_BLOCK : 0;
}
int spdylay_frame_alloc_unpack_nv(char ***nv_ptr,
spdylay_buffer *inflatebuf,
uint8_t **nvbuf_ptr,
size_t *nvbuflen_ptr,
const uint8_t *in, size_t inlen,
size_t len_size,
spdylay_zlib *inflater)
{
ssize_t nvspace;
int r;
nvspace = spdylay_zlib_inflate_hd(inflater, inflatebuf, in, inlen);
if(nvspace < 0) {
return nvspace;
} else {
r = spdylay_reserve_buffer(nvbuf_ptr, nvbuflen_ptr, nvspace);
if(r != 0) {
return SPDYLAY_ERR_NOMEM;
if(!invalid_header_block) {
spdylay_frame_nv_sort(*nv_ptr);
for(i = 2; i < nvlen*2; i += 2) {
if(strcmp((*nv_ptr)[i-2], (*nv_ptr)[i]) == 0 &&
(*nv_ptr)[i-2] != (*nv_ptr)[i]) {
invalid_header_block = 1;
break;
}
}
spdylay_buffer_serialize(inflatebuf, *nvbuf_ptr);
r = spdylay_frame_unpack_nv(nv_ptr, *nvbuf_ptr, nvspace, len_size);
return r;
}
return invalid_header_block ? SPDYLAY_ERR_INVALID_HEADER_BLOCK : 0;
}
size_t spdylay_frame_count_nv_space(char **nv, size_t len_size)
@ -730,8 +637,6 @@ void spdylay_frame_data_init(spdylay_data *frame, int32_t stream_id,
void spdylay_frame_data_free(spdylay_data *frame)
{}
#define SPDYLAY_SYN_STREAM_NV_OFFSET 18
ssize_t spdylay_frame_pack_syn_stream(uint8_t **buf_ptr,
size_t *buflen_ptr,
uint8_t **nvbuf_ptr,
@ -767,16 +672,13 @@ ssize_t spdylay_frame_pack_syn_stream(uint8_t **buf_ptr,
}
int spdylay_frame_unpack_syn_stream(spdylay_syn_stream *frame,
spdylay_buffer *inflatebuf,
uint8_t **nvbuf_ptr,
size_t *nvbuflen_ptr,
const uint8_t *head, size_t headlen,
const uint8_t *payload, size_t payloadlen,
spdylay_zlib *inflater)
spdylay_buffer *inflatebuf)
{
int r;
size_t len_size;
if(payloadlen < 12) {
if(headlen + payloadlen != SPDYLAY_SYN_STREAM_NV_OFFSET) {
return SPDYLAY_ERR_INVALID_FRAME;
}
spdylay_frame_unpack_ctrl_hd(&frame->hd, head);
@ -793,17 +695,10 @@ int spdylay_frame_unpack_syn_stream(spdylay_syn_stream *frame,
} else {
frame->slot = 0;
}
r = spdylay_frame_alloc_unpack_nv(&frame->nv, inflatebuf,
nvbuf_ptr, nvbuflen_ptr,
payload+10, payloadlen-10,
len_size,
inflater);
r = spdylay_frame_unpack_nv(&frame->nv, inflatebuf, len_size);
return r;
}
#define SPDYLAY_SPDY2_SYN_REPLY_NV_OFFSET 14
#define SPDYLAY_SPDY3_SYN_REPLY_NV_OFFSET 12
ssize_t spdylay_frame_pack_syn_reply(uint8_t **buf_ptr,
size_t *buflen_ptr,
uint8_t **nvbuf_ptr,
@ -813,14 +708,13 @@ ssize_t spdylay_frame_pack_syn_reply(uint8_t **buf_ptr,
{
ssize_t framelen;
size_t len_size;
size_t nv_offset;
ssize_t nv_offset;
len_size = spdylay_frame_get_len_size(frame->hd.version);
if(len_size == 0) {
return SPDYLAY_ERR_UNSUPPORTED_VERSION;
}
nv_offset = frame->hd.version == SPDYLAY_PROTO_SPDY2 ?
SPDYLAY_SPDY2_SYN_REPLY_NV_OFFSET : SPDYLAY_SPDY3_SYN_REPLY_NV_OFFSET;
nv_offset = spdylay_frame_nv_offset(SPDYLAY_SYN_REPLY, frame->hd.version);
assert(nv_offset > 0);
framelen = spdylay_frame_alloc_pack_nv(buf_ptr, buflen_ptr,
nvbuf_ptr, nvbuflen_ptr,
frame->nv, nv_offset,
@ -836,30 +730,25 @@ ssize_t spdylay_frame_pack_syn_reply(uint8_t **buf_ptr,
}
int spdylay_frame_unpack_syn_reply(spdylay_syn_reply *frame,
spdylay_buffer *inflatebuf,
uint8_t **nvbuf_ptr,
size_t *nvbuflen_ptr,
const uint8_t *head, size_t headlen,
const uint8_t *payload, size_t payloadlen,
spdylay_zlib *inflater)
spdylay_buffer *inflatebuf)
{
int r;
size_t len_size;
size_t nv_offset;
if(payloadlen < 8) {
return SPDYLAY_ERR_INVALID_FRAME;
}
ssize_t nv_offset;
spdylay_frame_unpack_ctrl_hd(&frame->hd, head);
len_size = spdylay_frame_get_len_size(frame->hd.version);
if(len_size == 0) {
return SPDYLAY_ERR_UNSUPPORTED_VERSION;
}
nv_offset = frame->hd.version == SPDYLAY_PROTO_SPDY2 ? 6 : 4;
nv_offset = spdylay_frame_nv_offset(SPDYLAY_SYN_REPLY, frame->hd.version);
assert(nv_offset > 0);
if((ssize_t)(headlen + payloadlen) != nv_offset) {
return SPDYLAY_ERR_INVALID_FRAME;
}
frame->stream_id = spdylay_get_uint32(payload) & SPDYLAY_STREAM_ID_MASK;
r = spdylay_frame_alloc_unpack_nv(&frame->nv, inflatebuf,
nvbuf_ptr, nvbuflen_ptr,
payload+nv_offset, payloadlen-nv_offset,
len_size, inflater);
r = spdylay_frame_unpack_nv(&frame->nv, inflatebuf, len_size);
return r;
}
@ -941,9 +830,6 @@ int spdylay_frame_unpack_goaway(spdylay_goaway *frame,
return 0;
}
#define SPDYLAY_SPDY2_HEADERS_NV_OFFSET 14
#define SPDYLAY_SPDY3_HEADERS_NV_OFFSET 12
ssize_t spdylay_frame_pack_headers(uint8_t **buf_ptr, size_t *buflen_ptr,
uint8_t **nvbuf_ptr, size_t *nvbuflen_ptr,
spdylay_headers *frame,
@ -956,8 +842,8 @@ ssize_t spdylay_frame_pack_headers(uint8_t **buf_ptr, size_t *buflen_ptr,
if(len_size == 0) {
return SPDYLAY_ERR_UNSUPPORTED_VERSION;
}
nv_offset = frame->hd.version == SPDYLAY_PROTO_SPDY2 ?
SPDYLAY_SPDY2_HEADERS_NV_OFFSET : SPDYLAY_SPDY3_HEADERS_NV_OFFSET;
nv_offset = spdylay_frame_nv_offset(SPDYLAY_HEADERS, frame->hd.version);
assert(nv_offset > 0);
framelen = spdylay_frame_alloc_pack_nv(buf_ptr, buflen_ptr,
nvbuf_ptr, nvbuflen_ptr,
frame->nv, nv_offset,
@ -973,30 +859,25 @@ ssize_t spdylay_frame_pack_headers(uint8_t **buf_ptr, size_t *buflen_ptr,
}
int spdylay_frame_unpack_headers(spdylay_headers *frame,
spdylay_buffer *inflatebuf,
uint8_t **nvbuf_ptr,
size_t *nvbuflen_ptr,
const uint8_t *head, size_t headlen,
const uint8_t *payload, size_t payloadlen,
spdylay_zlib *inflater)
spdylay_buffer *inflatebuf)
{
int r;
size_t len_size;
size_t nv_offset;
if(payloadlen < 8) {
return SPDYLAY_ERR_INVALID_FRAME;
}
ssize_t nv_offset;
spdylay_frame_unpack_ctrl_hd(&frame->hd, head);
len_size = spdylay_frame_get_len_size(frame->hd.version);
if(len_size == 0) {
return SPDYLAY_ERR_UNSUPPORTED_VERSION;
}
nv_offset = frame->hd.version == SPDYLAY_PROTO_SPDY2 ? 6 : 4;
nv_offset = spdylay_frame_nv_offset(SPDYLAY_HEADERS, frame->hd.version);
assert(nv_offset > 0);
if((ssize_t)(headlen + payloadlen) != nv_offset) {
return SPDYLAY_ERR_INVALID_FRAME;
}
frame->stream_id = spdylay_get_uint32(payload) & SPDYLAY_STREAM_ID_MASK;
r = spdylay_frame_alloc_unpack_nv(&frame->nv, inflatebuf,
nvbuf_ptr, nvbuflen_ptr,
payload+nv_offset, payloadlen-nv_offset,
len_size, inflater);
r = spdylay_frame_unpack_nv(&frame->nv, inflatebuf, len_size);
return r;
}
@ -1317,3 +1198,30 @@ void spdylay_frame_iv_sort(spdylay_settings_entry *iv, size_t niv)
{
qsort(iv, niv, sizeof(spdylay_settings_entry), spdylay_settings_entry_compar);
}
ssize_t spdylay_frame_nv_offset(spdylay_frame_type type, uint16_t version)
{
switch(type) {
case SPDYLAY_SYN_STREAM:
return SPDYLAY_SYN_STREAM_NV_OFFSET;
case SPDYLAY_SYN_REPLY: {
if(version == SPDYLAY_PROTO_SPDY2) {
return SPDYLAY_SPDY2_SYN_REPLY_NV_OFFSET;
} else if(version == SPDYLAY_PROTO_SPDY3) {
return SPDYLAY_SPDY3_SYN_REPLY_NV_OFFSET;
}
break;
}
case SPDYLAY_HEADERS: {
if(version == SPDYLAY_PROTO_SPDY2) {
return SPDYLAY_SPDY2_HEADERS_NV_OFFSET;
} else if(version == SPDYLAY_PROTO_SPDY3) {
return SPDYLAY_SPDY3_HEADERS_NV_OFFSET;
}
break;
}
default:
break;
}
return -1;
}

View File

@ -46,8 +46,19 @@
/* The number of bytes of frame header. */
#define SPDYLAY_FRAME_HEAD_LENGTH 8
#define spdylay_frame_get_nv_len(IN, LEN_SIZE) \
(LEN_SIZE == 2 ? spdylay_get_uint16(IN) : spdylay_get_uint32(IN))
/* The offset to the name/value header block in the frame (including
frame header) */
#define SPDYLAY_SYN_STREAM_NV_OFFSET 18
#define SPDYLAY_SPDY2_SYN_REPLY_NV_OFFSET 14
#define SPDYLAY_SPDY3_SYN_REPLY_NV_OFFSET 12
#define SPDYLAY_SPDY2_HEADERS_NV_OFFSET 14
#define SPDYLAY_SPDY3_HEADERS_NV_OFFSET 12
#define spdylay_frame_get_nv_len(RED, LEN_SIZE) \
(LEN_SIZE == 2 ? spdylay_buffer_reader_uint16(RED) : \
spdylay_buffer_reader_uint32(RED))
#define spdylay_frame_put_nv_len(OUT, VAL, LEN_SIZE) \
(LEN_SIZE == 2 ? \
@ -124,15 +135,13 @@ ssize_t spdylay_frame_pack_syn_stream(uint8_t **buf_ptr,
spdylay_zlib *deflater);
/*
* Unpacks SYN_STREAM frame byte sequence into |frame|. Header is
* given in head and headlen. In spdy/2 spec, headlen is 8
* bytes. |payload| is the data after length field of the header.
* Unpacks SYN_STREAM frame byte sequence into |frame|. The control
* frame header is given in |head| with |headlen| length. In spdy/3
* spec, headlen is 8 bytes. |payload| is the data after length field
* of the header and just before name/value header block.
*
* |inflatebuf| is used to buffer name/value pairs while inflating
* them using |inflater|. The caller must reset |inflatebuf| before
* the call. |*nvbuf_ptr|, |*nvbuflen_ptr| is used to store temporal
* inflated name/value pairs. This function expands |*nvbuf_ptr| as
* necessary and updates these variables.
* The |inflatebuf| contains inflated name/value header block in wire
* foramt.
*
* This function also validates the name/value pairs. If unpacking
* succeeds but validation fails, it is indicated by returning
@ -147,18 +156,13 @@ ssize_t spdylay_frame_pack_syn_stream(uint8_t **buf_ptr,
* The input data are invalid.
* SPDYLAY_ERR_UNSUPPORTED_VERSION
* The version is not supported.
* SPDYLAY_ERR_ZLIB
* The inflate operation failed.
* SPDYLAY_ERR_NOMEM
* Out of memory.
*/
int spdylay_frame_unpack_syn_stream(spdylay_syn_stream *frame,
spdylay_buffer *inflatebuf,
uint8_t **nvbuf_ptr,
size_t *nvbuflen_ptr,
const uint8_t *head, size_t headlen,
const uint8_t *payload, size_t payloadlen,
spdylay_zlib *inflater);
spdylay_buffer *inflatebuf);
/*
* Packs SYN_REPLY frame |frame| in wire frame format and store it in
@ -194,11 +198,8 @@ ssize_t spdylay_frame_pack_syn_reply(uint8_t **buf_ptr,
/*
* Unpacks SYN_REPLY frame byte sequence into |frame|.
*
* |inflatebuf| is used to buffer name/value pairs while inflating
* them using |inflater|. The caller must reset |inflatebuf| before
* the call. |*nvbuf_ptr|, |*nvbuflen_ptr| is used to store temporal
* inflated name/value pairs. This function expands |*nvbuf_ptr| as
* necessary and updates these variables.
* The |inflatebuf| contains inflated name/value header block in wire
* foramt.
*
* This function also validates the name/value pairs. If unpacking
* succeeds but validation fails, it is indicated by returning
@ -213,18 +214,13 @@ ssize_t spdylay_frame_pack_syn_reply(uint8_t **buf_ptr,
* The version is not supported.
* SPDYLAY_ERR_INVALID_FRAME
* The input data are invalid.
* SPDYLAY_ERR_ZLIB
* The inflate operation failed.
* SPDYLAY_ERR_NOMEM
* Out of memory.
*/
int spdylay_frame_unpack_syn_reply(spdylay_syn_reply *frame,
spdylay_buffer *inflatebuf,
uint8_t **nvbuf_ptr,
size_t *nvbuflen_ptr,
const uint8_t *head, size_t headlen,
const uint8_t *payload, size_t payloadlen,
spdylay_zlib *inflater);
spdylay_buffer *inflatebuf);
/*
* Packs PING frame |frame| in wire format and store it in
@ -318,11 +314,8 @@ ssize_t spdylay_frame_pack_headers(uint8_t **buf_ptr, size_t *buflen_ptr,
/*
* Unpacks HEADERS wire format into |frame|.
*
* |inflatebuf| is used to buffer name/value pairs while inflating
* them using |inflater|. The caller must reset |inflatebuf| before
* the call. |*nvbuf_ptr|, |*nvbuflen_ptr| is used to store temporal
* inflated name/value pairs. This function expands |*nvbuf_ptr| as
* necessary and updates these variables.
* The |inflatebuf| contains inflated name/value header block in wire
* foramt.
*
* This function also validates the name/value pairs. If unpacking
* succeeds but validation fails, it is indicated by returning
@ -337,18 +330,13 @@ ssize_t spdylay_frame_pack_headers(uint8_t **buf_ptr, size_t *buflen_ptr,
* The version is not supported.
* SPDYLAY_ERR_INVALID_FRAME
* The input data are invalid.
* SPDYLAY_ERR_ZLIB
* The inflate operation failed.
* SPDYLAY_ERR_NOMEM
* Out of memory.
*/
int spdylay_frame_unpack_headers(spdylay_headers *frame,
spdylay_buffer *inflatebuf,
uint8_t **nvbuf_ptr,
size_t *nvbuflen_ptr,
const uint8_t *head, size_t headlen,
const uint8_t *payload, size_t payloadlen,
spdylay_zlib *inflater);
spdylay_buffer *inflatebuf);
/*
* Packs RST_STREAM frame |frame| in wire frame format and store it in
@ -517,11 +505,11 @@ ssize_t spdylay_frame_alloc_pack_nv(uint8_t **buf_ptr,
/*
* Counts number of name/value pair in |in| and computes length of
* buffers to store unpacked name/value pair and store them in
* |*num_nv_ptr| and |*buf_size_ptr| respectively. |len_size| is the
* |*nvlen_ptr| and |*buflen_ptr| respectively. |len_size| is the
* number of bytes in length of name/value pair and it must be 2 or
* 4. We use folloing data structure in |*buf_size_ptr|. First part
* of the data is array of pointer to name/value pair. Supporse the
* buf pointer points to the data region and N is the number of
* 4. We use folloing data structure in |*buflen_ptr| size. First
* part of the data is array of pointer to name/value pair. Supporse
* the buf pointer points to the data region and N is the number of
* name/value pair. First (N*2+1)*sizeof(char*) bytes contain array
* of pointer to name/value pair and terminating NULL. Each pointer
* to name/value pair points to the string in remaining data. For
@ -533,7 +521,7 @@ ssize_t spdylay_frame_alloc_pack_nv(uint8_t **buf_ptr,
* data, corresponding index is assigned to name/value pointers. In
* this case, the name string is reused.
*
* With the above stragety, |*buf_size_ptr| is calculated as
* With the above stragety, |*buflen_ptr| is calculated as
* (N*2+1)*sizeof(char*)+sum(strlen(name)+1+strlen(value)+1){for each
* name/value pair}.
*
@ -543,35 +531,14 @@ ssize_t spdylay_frame_alloc_pack_nv(uint8_t **buf_ptr,
* SPDYLAY_ERR_INVALID_FRAME
* The input data are invalid.
*/
int spdylay_frame_count_unpack_nv_space
(size_t *num_nv_ptr, size_t *buf_size_ptr, const uint8_t *in, size_t inlen,
size_t len_size);
int spdylay_frame_count_unpack_nv_space(size_t *nvlen_ptr, size_t *buflen_ptr,
spdylay_buffer *in, size_t len_size);
/*
* Validates name of Name/Value header Block. The |buf| is the
* allocated buffer with the length at least |buflen| bytes. The
* |buflen| must be at least the number of Name/Value pairs in the
* packed name/value header block |in|. The length of |in| is given in
* |inlen|. The |buf| is used as a work memory to validate header
* names and the caller must not use its content on return.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* SPDYLAY_ERR_INVALID_HEADER_BLOCK
* There are duplicate header names; or the header names are not
* encoded in US-ASCII character set and not lower cased; or the
* header name is zero-length string.
*/
int spdylay_frame_unpack_nv_check_name(uint8_t *buf, size_t buflen,
const uint8_t *in, size_t inlen,
size_t len_size);
/*
* Unpacks name/value pairs in wire format |in| with length |inlen|
* and stores them in |*nv_ptr|. Thif function allocates enough
* memory to store name/value pairs in |*nv_ptr|. |len_size| is the
* number of bytes in length of name/value pair and it must be 2 or 4.
* Unpacks name/value header block in wire format |in| and stores them
* in |*nv_ptr|. Thif function allocates enough memory to store
* name/value pairs in |*nv_ptr|. |len_size| is the number of bytes
* in length of name/value pair and it must be 2 or 4.
*
* This function also validates the name/value pairs. If unpacking
* succeeds but validation fails, it is indicated by returning
@ -586,49 +553,16 @@ int spdylay_frame_unpack_nv_check_name(uint8_t *buf, size_t buflen,
* negative error codes:
*
* SPDYLAY_ERR_INVALID_HEADER_BLOCK
* Unpacking succeeds but the header block is invalid.
* Unpacking succeeds but the header block is invalid. The
* possible reasons are: There are duplicate header names; or the
* header names are not encoded in US-ASCII character set and not
* lower cased; or the header name is zero-length string.
* SPDYLAY_ERR_NOMEM
* Out of memory.
*/
int spdylay_frame_unpack_nv(char ***nv_ptr, const uint8_t *in, size_t inlen,
int spdylay_frame_unpack_nv(char ***nv_ptr, spdylay_buffer *in,
size_t len_size);
/*
* Unpacks name/value pairs from buffer |in| with length |inlen|. The
* necessary memory area required for output is allocated and its
* pointer is assigned to |nv_ptr|. |inflatebuf| is used for inflate
* operation. |*nvbuf_ptr| is used for temporarily stored inflated
* name/value pair in wire format. It is expanded as necessary.
* |len_size| is the number of bytes used in name/value length. It
* must be either 2 or 4.
*
* This function also validates the name/value pairs. If unpacking
* succeeds but validation fails, it is indicated by returning
* SPDYLAY_ERR_INVALID_HEADER_BLOCK.
*
* If error other than SPDYLAY_ERR_INVALID_HEADER_BLOCK is returned,
* the |nv_ptr| is not assigned. In other words,
* SPDYLAY_ERR_INVALID_HEADER_BLOCK means unpacking succeeded, but
* header block validation failed.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* SPDYLAY_ERR_INVALID_HEADER_BLOCK
* Unpacking succeeds but the header block is invalid.
* SPDYLAY_ERR_ZLIB
* The inflate operation failed.
* SPDYLAY_ERR_NOMEM
* Out of memory.
*/
int spdylay_frame_alloc_unpack_nv(char ***nv_ptr,
spdylay_buffer *inflatebuf,
uint8_t **nvbuf_ptr,
size_t *nvbuflen_ptr,
const uint8_t *in, size_t inlen,
size_t len_size,
spdylay_zlib *inflater);
/*
* Initializes SYN_STREAM frame |frame| with given values. |frame|
* takes ownership of |nv|, so caller must not free it. If stream_id
@ -793,4 +727,12 @@ spdylay_settings_entry* spdylay_frame_iv_copy(const spdylay_settings_entry *iv,
*/
void spdylay_frame_iv_sort(spdylay_settings_entry *iv, size_t niv);
/*
* Returns the offset of the name/header block in the frame, including
* frame header. If |type| is neither SPDYLAY_SYN_STREAM,
* SPDYLAY_SYN_REPLY nor SPDYLAY_HEADERS, this function returns -1.
* If |version| is unknown, this function returns -1.
*/
ssize_t spdylay_frame_nv_offset(spdylay_frame_type type, uint16_t version);
#endif /* SPDYLAY_FRAME_H */

View File

@ -111,8 +111,29 @@ static int spdylay_outbound_item_compar(const void *lhsx, const void *rhsx)
static void spdylay_inbound_frame_reset(spdylay_inbound_frame *iframe)
{
iframe->state = SPDYLAY_RECV_HEAD;
iframe->len = iframe->off = 0;
iframe->payloadlen = iframe->buflen = iframe->off = 0;
iframe->headbufoff = 0;
spdylay_buffer_reset(&iframe->inflatebuf);
iframe->error_code = 0;
}
/*
* Returns the number of bytes before name/value header block for the
* incoming frame. If the incoming frame does not have name/value
* block, this function returns -1.
*/
static size_t spdylay_inbound_frame_payload_nv_offset
(spdylay_inbound_frame *iframe)
{
uint16_t type, version;
ssize_t offset;
type = spdylay_get_uint16(&iframe->headbuf[2]);
version = spdylay_get_uint16(&iframe->headbuf[0]) & SPDYLAY_VERSION_MASK;
offset = spdylay_frame_nv_offset(type, version);
if(offset != -1) {
offset -= SPDYLAY_HEAD_LEN;
}
return offset;
}
static int spdylay_session_new(spdylay_session **session_ptr,
@ -183,8 +204,6 @@ static int spdylay_session_new(spdylay_session **session_ptr,
}
(*session_ptr)->nvbuflen = SPDYLAY_INITIAL_NV_BUFFER_LENGTH;
spdylay_buffer_init(&(*session_ptr)->inflatebuf, 4096);
memset((*session_ptr)->remote_settings, 0,
sizeof((*session_ptr)->remote_settings));
(*session_ptr)->remote_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] =
@ -208,6 +227,8 @@ static int spdylay_session_new(spdylay_session **session_ptr,
goto fail_iframe_buf;
}
(*session_ptr)->iframe.bufmax = SPDYLAY_INITIAL_INBOUND_FRAMEBUF_LENGTH;
spdylay_buffer_init(&(*session_ptr)->iframe.inflatebuf, 4096);
spdylay_inbound_frame_reset(&(*session_ptr)->iframe);
r = spdylay_client_cert_vector_init(&(*session_ptr)->cli_certvec,
@ -315,7 +336,7 @@ void spdylay_session_del(spdylay_session *session)
spdylay_active_outbound_item_reset(&session->aob);
free(session->aob.framebuf);
free(session->nvbuf);
spdylay_buffer_free(&session->inflatebuf);
spdylay_buffer_free(&session->iframe.inflatebuf);
free(session->iframe.buf);
spdylay_client_cert_vector_free(&session->cli_certvec);
free(session);
@ -2068,7 +2089,7 @@ static void spdylay_session_handle_parse_error(spdylay_session *session,
session->iframe.headbuf,
sizeof(session->iframe.headbuf),
session->iframe.buf,
session->iframe.len,
session->iframe.buflen,
error_code,
session->user_data);
}
@ -2083,16 +2104,16 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session)
type = spdylay_get_uint16(&session->iframe.headbuf[2]);
switch(type) {
case SPDYLAY_SYN_STREAM:
spdylay_buffer_reset(&session->inflatebuf);
r = spdylay_frame_unpack_syn_stream(&frame.syn_stream,
&session->inflatebuf,
&session->nvbuf,
&session->nvbuflen,
session->iframe.headbuf,
sizeof(session->iframe.headbuf),
session->iframe.buf,
session->iframe.len,
&session->hd_inflater);
if(session->iframe.error_code == 0) {
r = spdylay_frame_unpack_syn_stream(&frame.syn_stream,
session->iframe.headbuf,
sizeof(session->iframe.headbuf),
session->iframe.buf,
session->iframe.buflen,
&session->iframe.inflatebuf);
} else {
r = session->iframe.error_code;
}
if(r == 0) {
if(session->version == SPDYLAY_PROTO_SPDY2) {
spdylay_frame_nv_2to3(frame.syn_stream.nv);
@ -2113,16 +2134,16 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session)
}
break;
case SPDYLAY_SYN_REPLY:
spdylay_buffer_reset(&session->inflatebuf);
r = spdylay_frame_unpack_syn_reply(&frame.syn_reply,
&session->inflatebuf,
&session->nvbuf,
&session->nvbuflen,
session->iframe.headbuf,
sizeof(session->iframe.headbuf),
session->iframe.buf,
session->iframe.len,
&session->hd_inflater);
if(session->iframe.error_code == 0) {
r = spdylay_frame_unpack_syn_reply(&frame.syn_reply,
session->iframe.headbuf,
sizeof(session->iframe.headbuf),
session->iframe.buf,
session->iframe.buflen,
&session->iframe.inflatebuf);
} else {
r = session->iframe.error_code;
}
if(r == 0) {
if(session->version == SPDYLAY_PROTO_SPDY2) {
spdylay_frame_nv_2to3(frame.syn_reply.nv);
@ -2144,7 +2165,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session)
session->iframe.headbuf,
sizeof(session->iframe.headbuf),
session->iframe.buf,
session->iframe.len);
session->iframe.buflen);
if(r == 0) {
r = spdylay_session_on_rst_stream_received(session, &frame);
spdylay_frame_rst_stream_free(&frame.rst_stream);
@ -2158,7 +2179,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session)
session->iframe.headbuf,
sizeof(session->iframe.headbuf),
session->iframe.buf,
session->iframe.len);
session->iframe.buflen);
if(r == 0) {
r = spdylay_session_on_settings_received(session, &frame);
spdylay_frame_settings_free(&frame.settings);
@ -2174,7 +2195,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session)
session->iframe.headbuf,
sizeof(session->iframe.headbuf),
session->iframe.buf,
session->iframe.len);
session->iframe.buflen);
if(r == 0) {
r = spdylay_session_on_ping_received(session, &frame);
spdylay_frame_ping_free(&frame.ping);
@ -2188,7 +2209,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session)
session->iframe.headbuf,
sizeof(session->iframe.headbuf),
session->iframe.buf,
session->iframe.len);
session->iframe.buflen);
if(r == 0) {
r = spdylay_session_on_goaway_received(session, &frame);
spdylay_frame_goaway_free(&frame.goaway);
@ -2198,16 +2219,16 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session)
}
break;
case SPDYLAY_HEADERS:
spdylay_buffer_reset(&session->inflatebuf);
r = spdylay_frame_unpack_headers(&frame.headers,
&session->inflatebuf,
&session->nvbuf,
&session->nvbuflen,
session->iframe.headbuf,
sizeof(session->iframe.headbuf),
session->iframe.buf,
session->iframe.len,
&session->hd_inflater);
if(session->iframe.error_code == 0) {
r = spdylay_frame_unpack_headers(&frame.headers,
session->iframe.headbuf,
sizeof(session->iframe.headbuf),
session->iframe.buf,
session->iframe.buflen,
&session->iframe.inflatebuf);
} else {
r = session->iframe.error_code;
}
if(r == 0) {
if(session->version == SPDYLAY_PROTO_SPDY2) {
spdylay_frame_nv_2to3(frame.headers.nv);
@ -2229,7 +2250,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session)
session->iframe.headbuf,
sizeof(session->iframe.headbuf),
session->iframe.buf,
session->iframe.len);
session->iframe.buflen);
if(r == 0) {
r = spdylay_session_on_window_update_received(session, &frame);
spdylay_frame_window_update_free(&frame.window_update);
@ -2243,7 +2264,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session)
session->iframe.headbuf,
sizeof(session->iframe.headbuf),
session->iframe.buf,
session->iframe.len);
session->iframe.buflen);
if(r == 0) {
r = spdylay_session_on_credential_received(session, &frame);
spdylay_frame_credential_free(&frame.credential);
@ -2260,7 +2281,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session)
session->iframe.headbuf,
sizeof(session->iframe.headbuf),
session->iframe.buf,
session->iframe.len,
session->iframe.buflen,
session->user_data);
}
}
@ -2414,39 +2435,85 @@ ssize_t spdylay_session_mem_recv(spdylay_session *session,
session->iframe.headbufoff += readlen;
if(session->iframe.headbufoff == SPDYLAY_HEAD_LEN) {
session->iframe.state = SPDYLAY_RECV_PAYLOAD;
payloadlen = spdylay_get_uint32(&session->iframe.headbuf[4]) &
session->iframe.payloadlen =
spdylay_get_uint32(&session->iframe.headbuf[4]) &
SPDYLAY_LENGTH_MASK;
if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
/* control frame */
session->iframe.len = payloadlen;
ssize_t buflen;
buflen = spdylay_inbound_frame_payload_nv_offset(&session->iframe);
if(buflen == -1) {
/* TODO Check if payloadlen is small enough for buffering */
buflen = session->iframe.payloadlen;
} else if(buflen < (ssize_t)session->iframe.payloadlen) {
session->iframe.state = SPDYLAY_RECV_PAYLOAD_PRE_NV;
}
/* buflen >= session->iframe.payloadlen means frame is
malformed. In this case, we just buffer these bytes and
handle error later. */
session->iframe.buflen = buflen;
/* TODO On error case, go into SPDYLAY_RECV_PAYLOAD_IGN state and
discard any input bytes. */
r = spdylay_reserve_buffer(&session->iframe.buf,
&session->iframe.bufmax,
session->iframe.len);
buflen);
if(r != 0) {
/* FATAL */
assert(r < SPDYLAY_ERR_FATAL);
return r;
}
session->iframe.off = 0;
} else {
session->iframe.len = payloadlen;
session->iframe.off = 0;
}
} else {
break;
}
}
if(session->iframe.state == SPDYLAY_RECV_PAYLOAD) {
size_t rempayloadlen = session->iframe.len - session->iframe.off;
if(session->iframe.state == SPDYLAY_RECV_PAYLOAD ||
session->iframe.state == SPDYLAY_RECV_PAYLOAD_PRE_NV ||
session->iframe.state == SPDYLAY_RECV_PAYLOAD_NV) {
size_t rempayloadlen;
size_t bufavail, readlen;
int32_t data_stream_id = 0;
uint8_t data_flags = SPDYLAY_DATA_FLAG_NONE;
bufavail = inlimit-inmark;
rempayloadlen = session->iframe.payloadlen - session->iframe.off;
bufavail = inlimit - inmark;
if(rempayloadlen > 0 && bufavail == 0) {
break;
}
readlen = spdylay_min(bufavail, rempayloadlen);
if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
if(session->iframe.state == SPDYLAY_RECV_PAYLOAD_PRE_NV) {
size_t pnvlen, rpnvlen, readpnvlen;
pnvlen = spdylay_inbound_frame_payload_nv_offset(&session->iframe);
rpnvlen = pnvlen - session->iframe.off;
readpnvlen = spdylay_min(rpnvlen, readlen);
memcpy(session->iframe.buf+session->iframe.off, inmark, readpnvlen);
readlen -= readpnvlen;
session->iframe.off += readpnvlen;
inmark += readpnvlen;
if(session->iframe.off == pnvlen) {
session->iframe.state = SPDYLAY_RECV_PAYLOAD_NV;
}
}
if(session->iframe.state == SPDYLAY_RECV_PAYLOAD_NV) {
/* For frame with name/value header block, the compressed
portion of the block is incrementally decompressed. The
result is stored in inflatebuf. */
if(session->iframe.error_code == 0) {
ssize_t decomplen;
decomplen = spdylay_zlib_inflate_hd(&session->hd_inflater,
&session->iframe.inflatebuf,
inmark, readlen);
/* TODO If total length in inflatebuf exceeds certain limit,
set TOO_LARGE_FRAME to error_code and issue RST_STREAM
later. */
if(decomplen < 0) {
session->iframe.error_code = decomplen;
}
}
} else if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
memcpy(session->iframe.buf+session->iframe.off, inmark, readlen);
} else {
/* For data frame, We don't buffer data. Instead, just pass
@ -2469,7 +2536,7 @@ ssize_t spdylay_session_mem_recv(spdylay_session *session,
if(session->flow_control &&
!spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
if(readlen > 0 &&
(session->iframe.len != session->iframe.off ||
(session->iframe.payloadlen != session->iframe.off ||
(data_flags & SPDYLAY_DATA_FLAG_FIN) == 0)) {
r = spdylay_session_update_recv_window_size(session,
data_stream_id,
@ -2481,7 +2548,7 @@ ssize_t spdylay_session_mem_recv(spdylay_session *session,
}
}
}
if(session->iframe.len == session->iframe.off) {
if(session->iframe.payloadlen == session->iframe.off) {
if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
r = spdylay_session_process_ctrl_frame(session);
} else {

View File

@ -87,9 +87,18 @@ typedef struct {
/* Maxmum size of client certificate vector */
#define SPDYLAY_MAX_CLIENT_CERT_VECTOR_LENGTH 255
/* Internal state when receiving incoming frame */
typedef enum {
/* Receiving frame header */
SPDYLAY_RECV_HEAD,
SPDYLAY_RECV_PAYLOAD
/* Receiving frame payload (comes after length field) */
SPDYLAY_RECV_PAYLOAD,
/* Receiving frame payload that comes before name/value header
block. Applied only for SYN_STREAM, SYN_REPLY and HEADERS. */
SPDYLAY_RECV_PAYLOAD_PRE_NV,
/* Receiving name/value header block in frame payload. Applied only
for SYN_STREAM, SYN_REPLY and HEADERS. */
SPDYLAY_RECV_PAYLOAD_NV
} spdylay_inbound_state;
#define SPDYLAY_HEAD_LEN 8
@ -107,10 +116,22 @@ typedef struct {
uint8_t *buf;
/* Capacity of buf */
size_t bufmax;
/* For frames without name/value header block, this is how many
bytes are going to filled in buf. For frames with the block, buf
only contains bytes that come before ther block, but this value
includes the length of the block. buflen <= bufmax must be
fulfilled. */
size_t buflen;
/* length in Length field */
size_t len;
/* How many bytes are filled in buf */
size_t payloadlen;
/* How many bytes are received for this frame. off <= payloadlen
must be fulfilled. */
size_t off;
/* Buffer used to store name/value pairs while inflating them using
zlib on unpack */
spdylay_buffer inflatebuf;
/* Error code */
int error_code;
} spdylay_inbound_frame;
typedef enum {
@ -161,9 +182,6 @@ struct spdylay_session {
uint8_t *nvbuf;
/* The number of bytes allocated for nvbuf */
size_t nvbuflen;
/* Buffer used to store name/value pairs while inflating them using
zlib on unpack */
spdylay_buffer inflatebuf;
spdylay_zlib hd_deflater;
spdylay_zlib hd_inflater;

View File

@ -29,12 +29,14 @@ check_PROGRAMS = main failmalloc
OBJECTS = main.c spdylay_pq_test.c spdylay_map_test.c spdylay_queue_test.c \
spdylay_buffer_test.c spdylay_zlib_test.c spdylay_session_test.c \
spdylay_frame_test.c spdylay_stream_test.c spdylay_npn_test.c \
spdylay_client_cert_vector_test.c spdylay_gzip_test.c
spdylay_client_cert_vector_test.c spdylay_gzip_test.c \
spdylay_test_helper.c
HFILES = spdylay_pq_test.h spdylay_map_test.h spdylay_queue_test.h \
spdylay_buffer_test.h spdylay_zlib_test.h spdylay_session_test.h \
spdylay_frame_test.h spdylay_stream_test.h spdylay_npn_test.h \
spdylay_client_cert_vector_test.h spdylay_gzip_test.h
spdylay_client_cert_vector_test.h spdylay_gzip_test.h \
spdylay_test_helper.h
main_SOURCES = $(HFILES) $(OBJECTS)
@ -42,7 +44,8 @@ main_LDADD = ${top_builddir}/lib/libspdylay.la
main_LDFLAGS = -static @CUNIT_LIBS@
failmalloc_SOURCES = failmalloc.c failmalloc_test.c failmalloc_test.h \
malloc_wrapper.c malloc_wrapper.h
malloc_wrapper.c malloc_wrapper.h \
spdylay_test_helper.c spdylay_test_helper.h
failmalloc_LDADD = $(main_LDADD) -ldl
failmalloc_LDFLAGS = $(main_LDFLAGS)

View File

@ -34,6 +34,7 @@
#include "spdylay_frame.h"
#include "spdylay_helper.h"
#include "malloc_wrapper.h"
#include "spdylay_test_helper.h"
static char* strcopy(const char* s)
{
@ -431,13 +432,8 @@ static void run_spdylay_frame_pack_syn_stream(void)
if(framelen < 0) {
goto fail;
}
rv = spdylay_frame_unpack_syn_stream(&oframe.syn_stream,
&inflatebuf,
&nvbuf, &nvbuflen,
&buf[0], SPDYLAY_FRAME_HEAD_LENGTH,
&buf[SPDYLAY_FRAME_HEAD_LENGTH],
framelen-SPDYLAY_FRAME_HEAD_LENGTH,
&inflater);
rv = unpack_frame_with_nv_block(SPDYLAY_SYN_STREAM, SPDYLAY_PROTO_SPDY3,
&oframe, &inflater, buf, framelen);
if(rv != 0) {
goto fail;
}

View File

@ -69,6 +69,7 @@ int main(int argc, char* argv[])
!CU_add_test(pSuite, "map", test_spdylay_map) ||
!CU_add_test(pSuite, "queue", test_spdylay_queue) ||
!CU_add_test(pSuite, "buffer", test_spdylay_buffer) ||
!CU_add_test(pSuite, "buffer_reader", test_spdylay_buffer_reader) ||
!CU_add_test(pSuite, "zlib_spdy2", test_spdylay_zlib_spdy2) ||
!CU_add_test(pSuite, "zlib_spdy3", test_spdylay_zlib_spdy3) ||
!CU_add_test(pSuite, "npn", test_spdylay_npn) ||

View File

@ -29,6 +29,7 @@
#include <stdio.h>
#include "spdylay_buffer.h"
#include "spdylay_net.h"
void test_spdylay_buffer(void)
{
@ -79,3 +80,45 @@ void test_spdylay_buffer(void)
spdylay_buffer_free(&buffer);
}
void test_spdylay_buffer_reader(void)
{
spdylay_buffer buffer;
spdylay_buffer_reader reader;
uint16_t val16;
uint32_t val32;
uint8_t temp[256];
spdylay_buffer_init(&buffer, 3);
spdylay_buffer_write(&buffer, (const uint8_t*)"hello", 5);
val16 = htons(678);
spdylay_buffer_write(&buffer, (const uint8_t*)&val16, sizeof(uint16_t));
val32 = htonl(1000000007);
spdylay_buffer_write(&buffer, (const uint8_t*)&val32, sizeof(uint32_t));
spdylay_buffer_write(&buffer, (const uint8_t*)"world", 5);
CU_ASSERT(5+2+4+5 == spdylay_buffer_length(&buffer));
spdylay_buffer_reader_init(&reader, &buffer);
spdylay_buffer_reader_data(&reader, temp, 5);
CU_ASSERT(memcmp(temp, "hello", 5) == 0);
CU_ASSERT(678 == spdylay_buffer_reader_uint16(&reader));
CU_ASSERT(1000000007 == spdylay_buffer_reader_uint32(&reader));
CU_ASSERT('w' == spdylay_buffer_reader_uint8(&reader));
CU_ASSERT('o' == spdylay_buffer_reader_uint8(&reader));
CU_ASSERT('r' == spdylay_buffer_reader_uint8(&reader));
CU_ASSERT('l' == spdylay_buffer_reader_uint8(&reader));
CU_ASSERT('d' == spdylay_buffer_reader_uint8(&reader));
spdylay_buffer_reader_init(&reader, &buffer);
spdylay_buffer_reader_advance(&reader, 5);
CU_ASSERT(678 == spdylay_buffer_reader_uint16(&reader));
spdylay_buffer_reader_advance(&reader, 1);
spdylay_buffer_reader_advance(&reader, 1);
spdylay_buffer_reader_advance(&reader, 1);
spdylay_buffer_reader_advance(&reader, 1);
CU_ASSERT('w' == spdylay_buffer_reader_uint8(&reader));
spdylay_buffer_free(&buffer);
}

View File

@ -26,5 +26,6 @@
#define SPDYLAY_BUFFER_TEST_H
void test_spdylay_buffer(void);
void test_spdylay_buffer_reader(void);
#endif /* SPDYLAY_BUFFER_TEST_H */

View File

@ -28,6 +28,7 @@
#include "spdylay_frame.h"
#include "spdylay_helper.h"
#include "spdylay_test_helper.h"
static const char *headers[] = {
"method", "GET",
@ -36,7 +37,7 @@ static const char *headers[] = {
"x-head", "foo",
"x-head", "bar",
"version", "HTTP/1.1",
"empty", "",
"x-empty", "",
NULL
};
@ -45,30 +46,40 @@ static void test_spdylay_frame_unpack_nv_with(size_t len_size)
uint8_t out[1024];
char **nv;
size_t inlen = spdylay_frame_pack_nv(out, (char**)headers, len_size);
CU_ASSERT(0 == spdylay_frame_unpack_nv(&nv, out, inlen, len_size));
spdylay_buffer buffer;
spdylay_buffer_init(&buffer, 4096);
spdylay_buffer_write(&buffer, out, inlen);
CU_ASSERT(0 == spdylay_frame_unpack_nv(&nv, &buffer, len_size));
CU_ASSERT(strcmp("method", nv[0]) == 0);
CU_ASSERT(strcmp("GET", nv[1]) == 0);
CU_ASSERT(strcmp("scheme", nv[2]) == 0);
CU_ASSERT(strcmp("https", nv[3]) == 0);
CU_ASSERT(strcmp("url", nv[4]) == 0);
CU_ASSERT(strcmp("/", nv[5]) == 0);
CU_ASSERT(strcmp("x-head", nv[6]) == 0);
CU_ASSERT(strcmp("foo", nv[7]) == 0);
CU_ASSERT(strcmp("x-head", nv[8]) == 0);
CU_ASSERT(strcmp("bar", nv[9]) == 0);
CU_ASSERT(strcmp("version", nv[10]) == 0);
CU_ASSERT(strcmp("HTTP/1.1", nv[11]) == 0);
CU_ASSERT(strcmp("empty", nv[12]) == 0);
CU_ASSERT(strcmp("", nv[13]) == 0);
CU_ASSERT(strcmp("version", nv[6]) == 0);
CU_ASSERT(strcmp("HTTP/1.1", nv[7]) == 0);
CU_ASSERT(strcmp("x-empty", nv[8]) == 0);
CU_ASSERT(strcmp("", nv[9]) == 0);
CU_ASSERT(strcmp("x-head", nv[10]) == 0);
CU_ASSERT(strcmp("foo", nv[11]) == 0);
CU_ASSERT(strcmp("x-head", nv[12]) == 0);
CU_ASSERT(strcmp("bar", nv[13]) == 0);
spdylay_frame_nv_del(nv);
/* Create in-sequence NUL bytes */
memcpy(&out[len_size+len_size+strlen(headers[0])+len_size+
strlen(headers[1])-2],
/* Assuming first chunk has enough space to store 1st name/value
pair. */
memcpy(&buffer.root.next->data[len_size +
len_size + strlen(headers[0]) +
len_size + strlen(headers[1])-2],
"\0\0", 2);
CU_ASSERT(SPDYLAY_ERR_INVALID_HEADER_BLOCK ==
spdylay_frame_unpack_nv(&nv, out, inlen, len_size));
spdylay_frame_unpack_nv(&nv, &buffer, len_size));
spdylay_frame_nv_del(nv);
spdylay_buffer_free(&buffer);
}
void test_spdylay_frame_unpack_nv_spdy2(void)
@ -173,9 +184,9 @@ void test_spdylay_frame_pack_nv_duplicate_keys(void)
void test_spdylay_frame_count_nv_space(void)
{
size_t len_size = 2;
CU_ASSERT(83 == spdylay_frame_count_nv_space((char**)headers, len_size));
CU_ASSERT(85 == spdylay_frame_count_nv_space((char**)headers, len_size));
len_size = 4;
CU_ASSERT(109 == spdylay_frame_count_nv_space((char**)headers, len_size));
CU_ASSERT(111 == spdylay_frame_count_nv_space((char**)headers, len_size));
}
void test_spdylay_frame_count_unpack_nv_space(void)
@ -186,35 +197,45 @@ void test_spdylay_frame_count_unpack_nv_space(void)
size_t inlen = spdylay_frame_pack_nv(out, (char**)headers, len_size);
uint16_t temp;
size_t expected_buflen;
spdylay_buffer buffer;
uint8_t *chunk;
spdylay_buffer_init(&buffer, 4096);
spdylay_buffer_write(&buffer, out, inlen);
CU_ASSERT(0 == spdylay_frame_count_unpack_nv_space(&nvlen, &buflen,
out, inlen, len_size));
&buffer, len_size));
CU_ASSERT(7 == nvlen);
expected_buflen = 69+(nvlen*2+1)*sizeof(char*);
expected_buflen = 71+(nvlen*2+1)*sizeof(char*);
CU_ASSERT(expected_buflen == buflen);
/* Trailing garbage */
CU_ASSERT(SPDYLAY_ERR_INVALID_FRAME ==
spdylay_frame_count_unpack_nv_space(&nvlen, &buflen,
out, inlen+2, len_size));
chunk = buffer.root.next->data;
/* Change number of nv pair to a bogus value */
temp = spdylay_get_uint16(out);
spdylay_put_uint16be(out, temp+1);
temp = spdylay_get_uint16(chunk);
spdylay_put_uint16be(chunk, temp+1);
CU_ASSERT(SPDYLAY_ERR_INVALID_FRAME ==
spdylay_frame_count_unpack_nv_space(&nvlen, &buflen, out, inlen,
spdylay_frame_count_unpack_nv_space(&nvlen, &buflen, &buffer,
len_size));
spdylay_put_uint16be(out, temp);
spdylay_put_uint16be(chunk, temp);
/* Change the length of name to a bogus value */
temp = spdylay_get_uint16(out+2);
spdylay_put_uint16be(out+2, temp+1);
temp = spdylay_get_uint16(chunk+2);
spdylay_put_uint16be(chunk+2, temp+1);
CU_ASSERT(SPDYLAY_ERR_INVALID_FRAME ==
spdylay_frame_count_unpack_nv_space(&nvlen, &buflen, out, inlen,
spdylay_frame_count_unpack_nv_space(&nvlen, &buflen, &buffer,
len_size));
spdylay_put_uint16be(out+2, 65535);
spdylay_put_uint16be(chunk+2, 65535);
CU_ASSERT(SPDYLAY_ERR_INVALID_FRAME ==
spdylay_frame_count_unpack_nv_space(&nvlen, &buflen, out, inlen,
spdylay_frame_count_unpack_nv_space(&nvlen, &buflen, &buffer,
len_size));
/* Trailing garbage */
spdylay_buffer_advance(&buffer, 2);
CU_ASSERT(SPDYLAY_ERR_INVALID_FRAME ==
spdylay_frame_count_unpack_nv_space(&nvlen, &buflen,
&buffer, len_size));
/* We advanced buffer 2 bytes, so it is not valid any more. */
spdylay_buffer_free(&buffer);
}
void test_spdylay_frame_pack_ping(void)
@ -282,9 +303,8 @@ static void test_spdylay_frame_pack_syn_stream_version(uint16_t version)
spdylay_frame frame, oframe;
uint8_t *buf = NULL, *nvbuf = NULL;
size_t buflen = 0, nvbuflen = 0;
spdylay_buffer inflatebuf;
ssize_t framelen;
spdylay_buffer_init(&inflatebuf, 4096);
spdylay_zlib_deflate_hd_init(&deflater, version);
spdylay_zlib_inflate_hd_init(&inflater, version);
spdylay_frame_syn_stream_init(&frame.syn_stream, version,
@ -293,14 +313,12 @@ static void test_spdylay_frame_pack_syn_stream_version(uint16_t version)
framelen = spdylay_frame_pack_syn_stream(&buf, &buflen,
&nvbuf, &nvbuflen,
&frame.syn_stream, &deflater);
CU_ASSERT(0 == spdylay_frame_unpack_syn_stream
(&oframe.syn_stream,
&inflatebuf,
&nvbuf, &nvbuflen,
&buf[0], SPDYLAY_FRAME_HEAD_LENGTH,
&buf[SPDYLAY_FRAME_HEAD_LENGTH],
framelen-SPDYLAY_FRAME_HEAD_LENGTH,
&inflater));
CU_ASSERT(0 == unpack_frame_with_nv_block(SPDYLAY_SYN_STREAM,
version,
&oframe,
&inflater,
buf, framelen));
CU_ASSERT(65536 == oframe.syn_stream.stream_id);
CU_ASSERT(1000000007 == oframe.syn_stream.assoc_stream_id);
CU_ASSERT(version == oframe.syn_stream.hd.version);
@ -316,7 +334,6 @@ static void test_spdylay_frame_pack_syn_stream_version(uint16_t version)
spdylay_frame_syn_stream_free(&frame.syn_stream);
spdylay_zlib_inflate_free(&inflater);
spdylay_zlib_deflate_free(&deflater);
spdylay_buffer_free(&inflatebuf);
}
void test_spdylay_frame_pack_syn_stream_spdy2(void)
@ -335,9 +352,7 @@ static void test_spdylay_frame_pack_syn_reply_version(uint16_t version)
spdylay_frame frame, oframe;
uint8_t *buf = NULL, *nvbuf = NULL;
size_t buflen = 0, nvbuflen = 0;
spdylay_buffer inflatebuf;
ssize_t framelen;
spdylay_buffer_init(&inflatebuf, 4096);
spdylay_zlib_deflate_hd_init(&deflater, version);
spdylay_zlib_inflate_hd_init(&inflater, version);
spdylay_frame_syn_reply_init(&frame.syn_reply, version,
@ -346,14 +361,11 @@ static void test_spdylay_frame_pack_syn_reply_version(uint16_t version)
framelen = spdylay_frame_pack_syn_reply(&buf, &buflen,
&nvbuf, &nvbuflen,
&frame.syn_reply, &deflater);
CU_ASSERT(0 == spdylay_frame_unpack_syn_reply
(&oframe.syn_reply,
&inflatebuf,
&nvbuf, &nvbuflen,
&buf[0], SPDYLAY_FRAME_HEAD_LENGTH,
&buf[SPDYLAY_FRAME_HEAD_LENGTH],
framelen-SPDYLAY_FRAME_HEAD_LENGTH,
&inflater));
CU_ASSERT(0 == unpack_frame_with_nv_block(SPDYLAY_SYN_REPLY,
version,
&oframe,
&inflater,
buf, framelen));
CU_ASSERT(3 == oframe.syn_reply.stream_id);
CU_ASSERT(version == oframe.syn_reply.hd.version);
CU_ASSERT(SPDYLAY_SYN_REPLY == oframe.syn_reply.hd.type);
@ -368,7 +380,6 @@ static void test_spdylay_frame_pack_syn_reply_version(uint16_t version)
spdylay_frame_syn_reply_free(&frame.syn_reply);
spdylay_zlib_inflate_free(&inflater);
spdylay_zlib_deflate_free(&deflater);
spdylay_buffer_free(&inflatebuf);
}
void test_spdylay_frame_pack_syn_reply_spdy2(void)
@ -398,14 +409,11 @@ static void test_spdylay_frame_pack_headers_version(uint16_t version)
framelen = spdylay_frame_pack_headers(&buf, &buflen,
&nvbuf, &nvbuflen,
&frame.headers, &deflater);
CU_ASSERT(0 == spdylay_frame_unpack_headers
(&oframe.headers,
&inflatebuf,
&nvbuf, &nvbuflen,
&buf[0], SPDYLAY_FRAME_HEAD_LENGTH,
&buf[SPDYLAY_FRAME_HEAD_LENGTH],
framelen-SPDYLAY_FRAME_HEAD_LENGTH,
&inflater));
CU_ASSERT(0 == unpack_frame_with_nv_block(SPDYLAY_HEADERS,
version,
&oframe,
&inflater,
buf, framelen));
CU_ASSERT(3 == oframe.headers.stream_id);
CU_ASSERT(version == oframe.headers.hd.version);
CU_ASSERT(SPDYLAY_HEADERS == oframe.headers.hd.type);
@ -699,25 +707,40 @@ static const char *non_ascii_headers[] = {
static void test_spdylay_frame_unpack_nv_check_name_with(size_t len_size)
{
uint8_t nvbuf[1024], buf[1024];
uint8_t nvbuf[1024];
size_t nvbuflen;
spdylay_buffer buffer;
char **nv;
spdylay_buffer_init(&buffer, 32);
nvbuflen = spdylay_pack_nv(nvbuf, sizeof(nvbuf), headers, len_size);
spdylay_buffer_write(&buffer, nvbuf, nvbuflen);
CU_ASSERT(SPDYLAY_ERR_INVALID_HEADER_BLOCK ==
spdylay_frame_unpack_nv_check_name(buf, sizeof(buf),
nvbuf, nvbuflen, len_size));
spdylay_frame_unpack_nv(&nv, &buffer, len_size));
spdylay_frame_nv_del(nv);
spdylay_buffer_reset(&buffer);
nvbuflen = spdylay_pack_nv(nvbuf, sizeof(nvbuf), empty_name_headers,
len_size);
spdylay_buffer_write(&buffer, nvbuf, nvbuflen);
CU_ASSERT(SPDYLAY_ERR_INVALID_HEADER_BLOCK ==
spdylay_frame_unpack_nv_check_name(buf, sizeof(buf),
nvbuf, nvbuflen, len_size));
spdylay_frame_unpack_nv(&nv, &buffer, len_size));
spdylay_frame_nv_del(nv);
spdylay_buffer_reset(&buffer);
nvbuflen = spdylay_pack_nv(nvbuf, sizeof(nvbuf), non_ascii_headers,
len_size);
spdylay_buffer_write(&buffer, nvbuf, nvbuflen);
CU_ASSERT(SPDYLAY_ERR_INVALID_HEADER_BLOCK ==
spdylay_frame_unpack_nv_check_name(buf, sizeof(buf),
nvbuf, nvbuflen, len_size));
spdylay_frame_unpack_nv(&nv, &buffer, len_size));
spdylay_frame_nv_del(nv);
spdylay_buffer_free(&buffer);
}
void test_spdylay_frame_unpack_nv_check_name_spdy2(void)

View File

@ -32,6 +32,8 @@
#include "spdylay_session.h"
#include "spdylay_stream.h"
#include "spdylay_net.h"
#include "spdylay_helper.h"
#include "spdylay_test_helper.h"
#define OB_CTRL(ITEM) spdylay_outbound_item_get_ctrl_frame(ITEM)
#define OB_CTRL_TYPE(ITEM) spdylay_outbound_item_get_ctrl_frame_type(ITEM)
@ -290,6 +292,26 @@ void test_spdylay_session_recv(void)
item = spdylay_session_get_next_ob_item(session);
CU_ASSERT(SPDYLAY_RST_STREAM == OB_CTRL_TYPE(item));
CU_ASSERT(SPDYLAY_PROTOCOL_ERROR == OB_CTRL(item)->rst_stream.status_code);
CU_ASSERT(0 == spdylay_session_send(session));
/* Received SYN_STREAM without name/value header block */
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE,
5, 0, 3, dup_nv(upcase_nv));
framelen = spdylay_frame_pack_syn_stream(&framedata, &framedatalen,
&nvbuf, &nvbuflen,
&frame.syn_stream,
&session->hd_deflater);
spdylay_frame_syn_stream_free(&frame.syn_stream);
/* Use bytes that come before name/value header block */
spdylay_put_uint32be(&framedata[4],
SPDYLAY_SYN_STREAM_NV_OFFSET - SPDYLAY_HEAD_LEN);
scripted_data_feed_init(&df, framedata, SPDYLAY_SYN_STREAM_NV_OFFSET);
user_data.ctrl_recv_cb_called = 0;
CU_ASSERT(0 == spdylay_session_recv(session));
CU_ASSERT(0 == user_data.ctrl_recv_cb_called);
item = spdylay_session_get_next_ob_item(session);
CU_ASSERT(SPDYLAY_GOAWAY == OB_CTRL_TYPE(item));
spdylay_session_del(session);
@ -730,14 +752,11 @@ void test_spdylay_submit_response_with_null_data_read_callback(void)
CU_ASSERT(OB_CTRL(item)->syn_reply.hd.flags & SPDYLAY_CTRL_FLAG_FIN);
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(0 == spdylay_frame_unpack_syn_reply(&frame.syn_reply,
&session->inflatebuf,
&session->nvbuf,
&session->nvbuflen,
&acc.buf[0], SPDYLAY_HEAD_LEN,
&acc.buf[SPDYLAY_HEAD_LEN],
acc.length-SPDYLAY_HEAD_LEN,
&session->hd_inflater));
CU_ASSERT(0 == unpack_frame_with_nv_block(SPDYLAY_SYN_REPLY,
SPDYLAY_PROTO_SPDY2,
&frame,
&session->hd_inflater,
acc.buf, acc.length));
CU_ASSERT(0 == strcmp("version", frame.syn_reply.nv[0]));
spdylay_frame_syn_reply_free(&frame.syn_reply);
@ -792,14 +811,11 @@ void test_spdylay_submit_request_with_null_data_read_callback(void)
CU_ASSERT(OB_CTRL(item)->syn_stream.hd.flags & SPDYLAY_CTRL_FLAG_FIN);
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(0 == spdylay_frame_unpack_syn_stream(&frame.syn_stream,
&session->inflatebuf,
&session->nvbuf,
&session->nvbuflen,
&acc.buf[0], SPDYLAY_HEAD_LEN,
&acc.buf[SPDYLAY_HEAD_LEN],
acc.length-SPDYLAY_HEAD_LEN,
&session->hd_inflater));
CU_ASSERT(0 == unpack_frame_with_nv_block(SPDYLAY_SYN_STREAM,
SPDYLAY_PROTO_SPDY2,
&frame,
&session->hd_inflater,
acc.buf, acc.length));
CU_ASSERT(0 == strcmp("version", frame.syn_stream.nv[0]));
spdylay_frame_syn_stream_free(&frame.syn_stream);
@ -922,14 +938,11 @@ void test_spdylay_submit_headers(void)
CU_ASSERT(SPDYLAY_HEADERS == ud.sent_frame_type);
CU_ASSERT(stream->shut_flags & SPDYLAY_SHUT_WR);
CU_ASSERT(0 == spdylay_frame_unpack_headers(&frame.headers,
&session->inflatebuf,
&session->nvbuf,
&session->nvbuflen,
&acc.buf[0], SPDYLAY_HEAD_LEN,
&acc.buf[SPDYLAY_HEAD_LEN],
acc.length-SPDYLAY_HEAD_LEN,
&session->hd_inflater));
CU_ASSERT(0 == unpack_frame_with_nv_block(SPDYLAY_HEADERS,
SPDYLAY_PROTO_SPDY2,
&frame,
&session->hd_inflater,
acc.buf, acc.length));
CU_ASSERT(0 == strcmp("version", frame.headers.nv[0]));
spdylay_frame_headers_free(&frame.headers);
@ -2349,6 +2362,7 @@ void test_spdylay_submit_window_update(void)
CU_ASSERT(0 == stream->recv_window_size);
CU_ASSERT(0 == spdylay_submit_window_update(session, stream_id, 4096));
item = spdylay_session_get_next_ob_item(session);
CU_ASSERT(SPDYLAY_WINDOW_UPDATE == OB_CTRL_TYPE(item));
CU_ASSERT(4096 == OB_CTRL(item)->window_update.delta_window_size);
CU_ASSERT(0 == spdylay_session_send(session));

View File

@ -0,0 +1,75 @@
/*
* Spdylay - SPDY Library
*
* Copyright (c) 2012 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 "spdylay_test_helper.h"
#include <assert.h>
#include <CUnit/CUnit.h>
#include "spdylay_session.h"
ssize_t unpack_frame_with_nv_block(spdylay_frame_type type,
uint16_t version,
spdylay_frame *frame,
spdylay_zlib *inflater,
const uint8_t *in, size_t len)
{
spdylay_buffer buffer;
ssize_t rv;
ssize_t pnvlen;
pnvlen = spdylay_frame_nv_offset(type, version) - SPDYLAY_HEAD_LEN;
assert(pnvlen > 0);
spdylay_buffer_init(&buffer, 4096);
rv = spdylay_zlib_inflate_hd(inflater, &buffer,
&in[SPDYLAY_HEAD_LEN + pnvlen],
len - SPDYLAY_HEAD_LEN - pnvlen);
CU_ASSERT(rv >= 0);
switch(type) {
case SPDYLAY_SYN_STREAM:
rv = spdylay_frame_unpack_syn_stream(&frame->syn_stream,
&in[0], SPDYLAY_HEAD_LEN,
&in[SPDYLAY_HEAD_LEN], pnvlen,
&buffer);
break;
case SPDYLAY_SYN_REPLY:
rv = spdylay_frame_unpack_syn_reply(&frame->syn_reply,
&in[0], SPDYLAY_HEAD_LEN,
&in[SPDYLAY_HEAD_LEN], pnvlen,
&buffer);
break;
case SPDYLAY_HEADERS:
rv = spdylay_frame_unpack_headers(&frame->headers,
&in[0], SPDYLAY_HEAD_LEN,
&in[SPDYLAY_HEAD_LEN], pnvlen,
&buffer);
break;
default:
/* Must not be reachable */
assert(0);
}
spdylay_buffer_free(&buffer);
return rv;
}

View File

@ -0,0 +1,41 @@
/*
* Spdylay - SPDY Library
*
* Copyright (c) 2012 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 SPDYLAY_TEST_HELPER_H
#define SPDYLAY_TEST_HELPER_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include "spdylay_frame.h"
#include "spdylay_zlib.h"
ssize_t unpack_frame_with_nv_block(spdylay_frame_type type,
uint16_t version,
spdylay_frame *frame,
spdylay_zlib *inflater,
const uint8_t *in, size_t len);
#endif /* SPDYLAY_TEST_HELPER_H */