Incremental name/value block decompression
This commit is contained in:
parent
a18f04e8c7
commit
a6ae4fc72c
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,33 +228,19 @@ 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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
spdylay_buffer_serialize(inflatebuf, *nvbuf_ptr);
|
||||
r = spdylay_frame_unpack_nv(nv_ptr, *nvbuf_ptr, nvspace, len_size);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
size_t spdylay_frame_count_nv_space(char **nv, size_t len_size)
|
||||
{
|
||||
size_t sum = 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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
if(session->iframe.error_code == 0) {
|
||||
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);
|
||||
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);
|
||||
if(session->iframe.error_code == 0) {
|
||||
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);
|
||||
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);
|
||||
if(session->iframe.error_code == 0) {
|
||||
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);
|
||||
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;
|
||||
|
||||
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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) ||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
Loading…
Reference in New Issue