Added support for 4 bytes length in name/value pair.
This commit is contained in:
parent
cf7da38598
commit
7652d3f4ca
|
@ -31,15 +31,23 @@
|
|||
|
||||
#include "spdylay_helper.h"
|
||||
|
||||
#define spdylay_frame_get_nv_len(IN, LEN_SIZE) \
|
||||
(LEN_SIZE == 2 ? spdylay_get_uint16(IN) : spdylay_get_uint32(IN))
|
||||
|
||||
#define spdylay_frame_put_nv_len(OUT, VAL, LEN_SIZE) \
|
||||
(LEN_SIZE == 2 ? \
|
||||
spdylay_put_uint16be(OUT, VAL) : spdylay_put_uint32be(OUT, VAL))
|
||||
|
||||
static uint8_t spdylay_unpack_pri(const uint8_t *data)
|
||||
{
|
||||
return (data[0] >> 6) & 0x3;
|
||||
}
|
||||
|
||||
static uint8_t* spdylay_pack_str(uint8_t *buf, const char *str, size_t len)
|
||||
static uint8_t* spdylay_pack_str(uint8_t *buf, const char *str, size_t len,
|
||||
size_t len_size)
|
||||
{
|
||||
spdylay_put_uint16be(buf, len);
|
||||
buf += 2;
|
||||
spdylay_frame_put_nv_len(buf, len, len_size);
|
||||
buf += len_size;
|
||||
memcpy(buf, str, len);
|
||||
return buf+len;
|
||||
}
|
||||
|
@ -82,13 +90,14 @@ static ssize_t spdylay_frame_alloc_pack_nv(uint8_t **buf_ptr,
|
|||
uint8_t **nvbuf_ptr,
|
||||
size_t *nvbuflen_ptr,
|
||||
char **nv, size_t nv_offset,
|
||||
size_t len_size,
|
||||
spdylay_zlib *deflater)
|
||||
{
|
||||
size_t nvspace;
|
||||
size_t maxframelen;
|
||||
ssize_t framelen;
|
||||
int r;
|
||||
nvspace = spdylay_frame_count_nv_space(nv);
|
||||
nvspace = spdylay_frame_count_nv_space(nv, len_size);
|
||||
r = spdylay_reserve_buffer(nvbuf_ptr, nvbuflen_ptr, nvspace);
|
||||
if(r != 0) {
|
||||
return SPDYLAY_ERR_NOMEM;
|
||||
|
@ -98,7 +107,7 @@ static ssize_t spdylay_frame_alloc_pack_nv(uint8_t **buf_ptr,
|
|||
if(r != 0) {
|
||||
return SPDYLAY_ERR_NOMEM;
|
||||
}
|
||||
spdylay_frame_pack_nv(*nvbuf_ptr, nv);
|
||||
spdylay_frame_pack_nv(*nvbuf_ptr, nv, len_size);
|
||||
framelen = spdylay_zlib_deflate_hd(deflater,
|
||||
(*buf_ptr)+nv_offset,
|
||||
maxframelen-nv_offset,
|
||||
|
@ -111,28 +120,29 @@ static ssize_t spdylay_frame_alloc_pack_nv(uint8_t **buf_ptr,
|
|||
}
|
||||
|
||||
int spdylay_frame_count_unpack_nv_space
|
||||
(size_t *nvlen_ptr, size_t *buflen_ptr, const uint8_t *in, size_t inlen)
|
||||
(size_t *nvlen_ptr, size_t *buflen_ptr, const uint8_t *in, size_t inlen,
|
||||
size_t len_size)
|
||||
{
|
||||
uint16_t n;
|
||||
uint32_t n;
|
||||
size_t buflen = 0;
|
||||
size_t nvlen = 0;
|
||||
size_t off = 0;
|
||||
const size_t len_size = sizeof(uint16_t);
|
||||
int i;
|
||||
if(inlen < len_size) {
|
||||
return SPDYLAY_ERR_INVALID_FRAME;
|
||||
}
|
||||
n = spdylay_get_uint16(in);
|
||||
/* TODO limit n in a reasonable number */
|
||||
n = spdylay_frame_get_nv_len(in, len_size);
|
||||
off += len_size;
|
||||
for(i = 0; i < n; ++i) {
|
||||
uint16_t len;
|
||||
uint32_t len;
|
||||
int j;
|
||||
for(j = 0; j < 2; ++j) {
|
||||
if(inlen-off < len_size) {
|
||||
return SPDYLAY_ERR_INVALID_FRAME;
|
||||
}
|
||||
len = spdylay_get_uint16(in+off);
|
||||
off += 2;
|
||||
len = spdylay_frame_get_nv_len(in+off, len_size);
|
||||
off += len_size;
|
||||
if(inlen-off < len) {
|
||||
return SPDYLAY_ERR_INVALID_FRAME;
|
||||
}
|
||||
|
@ -155,13 +165,14 @@ int spdylay_frame_count_unpack_nv_space
|
|||
}
|
||||
}
|
||||
|
||||
int spdylay_frame_unpack_nv(char ***nv_ptr, const uint8_t *in, size_t inlen)
|
||||
int spdylay_frame_unpack_nv(char ***nv_ptr, const uint8_t *in, size_t inlen,
|
||||
size_t len_size)
|
||||
{
|
||||
size_t nvlen, buflen;
|
||||
int r, i;
|
||||
char *buf, **index, *data;
|
||||
uint16_t n;
|
||||
r = spdylay_frame_count_unpack_nv_space(&nvlen, &buflen, in, inlen);
|
||||
uint32_t n;
|
||||
r = spdylay_frame_count_unpack_nv_space(&nvlen, &buflen, in, inlen, len_size);
|
||||
if(r != 0) {
|
||||
return r;
|
||||
}
|
||||
|
@ -171,14 +182,14 @@ int spdylay_frame_unpack_nv(char ***nv_ptr, const uint8_t *in, size_t inlen)
|
|||
}
|
||||
index = (char**)buf;
|
||||
data = buf+(nvlen*2+1)*sizeof(char*);
|
||||
n = spdylay_get_uint16(in);
|
||||
in += 2;
|
||||
n = spdylay_frame_get_nv_len(in, len_size);
|
||||
in += len_size;
|
||||
for(i = 0; i < n; ++i) {
|
||||
uint16_t len;
|
||||
uint32_t len;
|
||||
char *name, *val;
|
||||
char *stop;
|
||||
len = spdylay_get_uint16(in);
|
||||
in += 2;
|
||||
len = spdylay_frame_get_nv_len(in, len_size);
|
||||
in += len_size;
|
||||
name = data;
|
||||
memcpy(data, in, len);
|
||||
data += len;
|
||||
|
@ -186,8 +197,8 @@ int spdylay_frame_unpack_nv(char ***nv_ptr, const uint8_t *in, size_t inlen)
|
|||
++data;
|
||||
in += len;
|
||||
|
||||
len = spdylay_get_uint16(in);
|
||||
in += 2;
|
||||
len = spdylay_frame_get_nv_len(in, len_size);
|
||||
in += len_size;
|
||||
val = data;
|
||||
memcpy(data, in, len);
|
||||
|
||||
|
@ -217,6 +228,8 @@ int spdylay_frame_unpack_nv(char ***nv_ptr, const uint8_t *in, size_t inlen)
|
|||
* 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 returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
|
@ -231,6 +244,7 @@ static int spdylay_frame_alloc_unpack_nv(char ***nv_ptr,
|
|||
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;
|
||||
|
@ -244,14 +258,14 @@ static int spdylay_frame_alloc_unpack_nv(char ***nv_ptr,
|
|||
return SPDYLAY_ERR_NOMEM;
|
||||
}
|
||||
spdylay_buffer_serialize(inflatebuf, *nvbuf_ptr);
|
||||
r = spdylay_frame_unpack_nv(nv_ptr, *nvbuf_ptr, nvspace);
|
||||
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 spdylay_frame_count_nv_space(char **nv, size_t len_size)
|
||||
{
|
||||
size_t sum = 2;
|
||||
size_t sum = len_size;
|
||||
int i;
|
||||
const char *prev = "";
|
||||
size_t prevlen = 0;
|
||||
|
@ -267,21 +281,21 @@ size_t spdylay_frame_count_nv_space(char **nv)
|
|||
prev = key;
|
||||
prevlen = keylen;
|
||||
/* SPDY NV header does not include terminating NULL byte */
|
||||
sum += keylen+vallen+4;
|
||||
sum += keylen+vallen+len_size*2;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
ssize_t spdylay_frame_pack_nv(uint8_t *buf, char **nv)
|
||||
ssize_t spdylay_frame_pack_nv(uint8_t *buf, char **nv, size_t len_size)
|
||||
{
|
||||
int i;
|
||||
uint8_t *bufp = buf+2;
|
||||
uint16_t num_nv = 0;
|
||||
uint8_t *bufp = buf+len_size;
|
||||
uint32_t num_nv = 0;
|
||||
/* TODO Join values with same keys, using '\0' as a delimiter */
|
||||
const char *prev = "";
|
||||
uint8_t *prev_vallen_buf = NULL;
|
||||
uint16_t prev_vallen = 0;
|
||||
uint32_t prev_vallen = 0;
|
||||
for(i = 0; nv[i]; i += 2) {
|
||||
const char *key = nv[i];
|
||||
const char *val = nv[i+1];
|
||||
|
@ -289,21 +303,21 @@ ssize_t spdylay_frame_pack_nv(uint8_t *buf, char **nv)
|
|||
size_t vallen = strlen(val);
|
||||
if(strcmp(prev, key) == 0) {
|
||||
prev_vallen += vallen+1;
|
||||
spdylay_put_uint16be(prev_vallen_buf, prev_vallen);
|
||||
spdylay_frame_put_nv_len(prev_vallen_buf, prev_vallen, len_size);
|
||||
*bufp = '\0';
|
||||
++bufp;
|
||||
memcpy(bufp, val, vallen);
|
||||
bufp += vallen;
|
||||
} else {
|
||||
++num_nv;
|
||||
bufp = spdylay_pack_str(bufp, key, keylen);
|
||||
bufp = spdylay_pack_str(bufp, key, keylen, len_size);
|
||||
prev = key;
|
||||
prev_vallen_buf = bufp;
|
||||
prev_vallen = vallen;
|
||||
bufp = spdylay_pack_str(bufp, val, vallen);
|
||||
bufp = spdylay_pack_str(bufp, val, vallen, len_size);
|
||||
}
|
||||
}
|
||||
spdylay_put_uint16be(buf, num_nv);
|
||||
spdylay_frame_put_nv_len(buf, num_nv, len_size);
|
||||
return bufp-buf;
|
||||
}
|
||||
|
||||
|
@ -504,6 +518,7 @@ ssize_t spdylay_frame_pack_syn_stream(uint8_t **buf_ptr,
|
|||
nvbuf_ptr, nvbuflen_ptr,
|
||||
frame->nv,
|
||||
SPDYLAY_SYN_STREAM_NV_OFFSET,
|
||||
2,
|
||||
deflater);
|
||||
if(framelen < 0) {
|
||||
return framelen;
|
||||
|
@ -538,6 +553,7 @@ int spdylay_frame_unpack_syn_stream(spdylay_syn_stream *frame,
|
|||
r = spdylay_frame_alloc_unpack_nv(&frame->nv, inflatebuf,
|
||||
nvbuf_ptr, nvbuflen_ptr,
|
||||
payload+10, payloadlen-10,
|
||||
2,
|
||||
inflater);
|
||||
return r;
|
||||
}
|
||||
|
@ -555,7 +571,9 @@ ssize_t spdylay_frame_pack_syn_reply(uint8_t **buf_ptr,
|
|||
framelen = spdylay_frame_alloc_pack_nv(buf_ptr, buflen_ptr,
|
||||
nvbuf_ptr, nvbuflen_ptr,
|
||||
frame->nv,
|
||||
SPDYLAY_SYN_REPLY_NV_OFFSET, deflater);
|
||||
SPDYLAY_SYN_REPLY_NV_OFFSET,
|
||||
2,
|
||||
deflater);
|
||||
if(framelen < 0) {
|
||||
return framelen;
|
||||
}
|
||||
|
@ -583,6 +601,7 @@ int spdylay_frame_unpack_syn_reply(spdylay_syn_reply *frame,
|
|||
r = spdylay_frame_alloc_unpack_nv(&frame->nv, inflatebuf,
|
||||
nvbuf_ptr, nvbuflen_ptr,
|
||||
payload+6, payloadlen-6,
|
||||
2,
|
||||
inflater);
|
||||
return r;
|
||||
}
|
||||
|
@ -653,7 +672,9 @@ ssize_t spdylay_frame_pack_headers(uint8_t **buf_ptr, size_t *buflen_ptr,
|
|||
framelen = spdylay_frame_alloc_pack_nv(buf_ptr, buflen_ptr,
|
||||
nvbuf_ptr, nvbuflen_ptr,
|
||||
frame->nv,
|
||||
SPDYLAY_HEADERS_NV_OFFSET, deflater);
|
||||
SPDYLAY_HEADERS_NV_OFFSET,
|
||||
2,
|
||||
deflater);
|
||||
if(framelen < 0) {
|
||||
return framelen;
|
||||
}
|
||||
|
@ -681,6 +702,7 @@ int spdylay_frame_unpack_headers(spdylay_headers *frame,
|
|||
r = spdylay_frame_alloc_unpack_nv(&frame->nv, inflatebuf,
|
||||
nvbuf_ptr, nvbuflen_ptr,
|
||||
payload+6, payloadlen-6,
|
||||
2,
|
||||
inflater);
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -328,35 +328,40 @@ int spdylay_frame_unpack_settings(spdylay_settings *frame,
|
|||
|
||||
/*
|
||||
* Returns number of bytes to pack name/value pairs |nv|. This
|
||||
* function expects |nv| is sorted in ascending order of key. This
|
||||
* function can handles duplicate keys and concatenation of thier
|
||||
* function expects |nv| is sorted in ascending order of key.
|
||||
* |len_size| is the number of bytes in length of name/value pair and
|
||||
* it must be 2 or 4.
|
||||
*
|
||||
* This function can handles duplicate keys and concatenation of thier
|
||||
* values with '\0'.
|
||||
*/
|
||||
size_t spdylay_frame_count_nv_space(char **nv);
|
||||
size_t spdylay_frame_count_nv_space(char **nv, size_t len_size);
|
||||
|
||||
/*
|
||||
* Packs name/value pairs in |nv| in |buf|. |buf| must have at least
|
||||
* spdylay_frame_count_nv_space(nv) bytes.
|
||||
* spdylay_frame_count_nv_space(nv) bytes. |len_size| is the number
|
||||
* of bytes in length of name/value pair and it must be 2 or 4.
|
||||
*/
|
||||
ssize_t spdylay_frame_pack_nv(uint8_t *buf, char **nv);
|
||||
ssize_t spdylay_frame_pack_nv(uint8_t *buf, char **nv, size_t len_size);
|
||||
|
||||
/*
|
||||
* 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. 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 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 each name/value pair, the
|
||||
* name is copied to the remaining data with terminating NULL
|
||||
* character. The value is also copied to the position after the data
|
||||
* with terminating NULL character. The corresponding index is
|
||||
* assigned to these pointers. If the value contains multiple values
|
||||
* (delimited by single NULL), for each such data, corresponding index
|
||||
* is assigned to name/value pointers. In this case, the name string
|
||||
* is reused.
|
||||
* |*num_nv_ptr| and |*buf_size_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
|
||||
* 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
|
||||
* each name/value pair, the name is copied to the remaining data with
|
||||
* terminating NULL character. The value is also copied to the
|
||||
* position after the data with terminating NULL character. The
|
||||
* corresponding index is assigned to these pointers. If the value
|
||||
* contains multiple values (delimited by single NULL), for each such
|
||||
* 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
|
||||
* (N*2+1)*sizeof(char*)+sum(strlen(name)+1+strlen(value)+1){for each
|
||||
|
@ -369,12 +374,14 @@ ssize_t spdylay_frame_pack_nv(uint8_t *buf, char **nv);
|
|||
* 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 *num_nv_ptr, size_t *buf_size_ptr, 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|.
|
||||
* 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 returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
|
@ -382,7 +389,8 @@ int spdylay_frame_count_unpack_nv_space
|
|||
* 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, const uint8_t *in, size_t inlen,
|
||||
size_t len_size);
|
||||
|
||||
/*
|
||||
* Initializes SYN_STREAM frame |frame| with given values. |frame|
|
||||
|
|
|
@ -43,8 +43,9 @@ void test_spdylay_frame_unpack_nv()
|
|||
{
|
||||
uint8_t out[1024];
|
||||
char **nv;
|
||||
size_t inlen = spdylay_frame_pack_nv(out, (char**)headers);
|
||||
CU_ASSERT(0 == spdylay_frame_unpack_nv(&nv, out, inlen));
|
||||
size_t len_size = 2;
|
||||
size_t inlen = spdylay_frame_pack_nv(out, (char**)headers, len_size);
|
||||
CU_ASSERT(0 == spdylay_frame_unpack_nv(&nv, out, inlen, len_size));
|
||||
CU_ASSERT(strcmp("method", nv[0]) == 0);
|
||||
CU_ASSERT(strcmp("GET", nv[1]) == 0);
|
||||
CU_ASSERT(strcmp("scheme", nv[2]) == 0);
|
||||
|
@ -63,6 +64,7 @@ void test_spdylay_frame_unpack_nv()
|
|||
void test_spdylay_frame_pack_nv_duplicate_keys()
|
||||
{
|
||||
uint8_t out[1024];
|
||||
size_t len_size = 2;
|
||||
const char *nv_src[] = {
|
||||
"method", "GET",
|
||||
"scheme", "https",
|
||||
|
@ -75,7 +77,7 @@ void test_spdylay_frame_pack_nv_duplicate_keys()
|
|||
char **nv = spdylay_frame_nv_copy(nv_src);
|
||||
spdylay_frame_nv_downcase(nv);
|
||||
spdylay_frame_nv_sort(nv);
|
||||
/* size_t inlen = */ spdylay_frame_pack_nv(out, nv);
|
||||
/* size_t inlen = */ spdylay_frame_pack_nv(out, nv, len_size);
|
||||
const uint8_t *outptr = out;
|
||||
int pairs = spdylay_get_uint16(outptr);
|
||||
CU_ASSERT(pairs == 5);
|
||||
|
@ -147,40 +149,45 @@ void test_spdylay_frame_pack_nv_duplicate_keys()
|
|||
|
||||
void test_spdylay_frame_count_nv_space()
|
||||
{
|
||||
CU_ASSERT(74 == spdylay_frame_count_nv_space((char**)headers));
|
||||
size_t len_size = 2;
|
||||
CU_ASSERT(74 == spdylay_frame_count_nv_space((char**)headers, len_size));
|
||||
}
|
||||
|
||||
void test_spdylay_frame_count_unpack_nv_space()
|
||||
{
|
||||
size_t nvlen, buflen;
|
||||
uint8_t out[1024];
|
||||
size_t inlen = spdylay_frame_pack_nv(out, (char**)headers);
|
||||
size_t len_size = 2;
|
||||
size_t inlen = spdylay_frame_pack_nv(out, (char**)headers, len_size);
|
||||
uint16_t temp;
|
||||
CU_ASSERT(0 == spdylay_frame_count_unpack_nv_space(&nvlen, &buflen,
|
||||
out, inlen));
|
||||
out, inlen, len_size));
|
||||
CU_ASSERT(6 == nvlen);
|
||||
CU_ASSERT(166 == buflen);
|
||||
|
||||
/* Trailing garbage */
|
||||
CU_ASSERT(SPDYLAY_ERR_INVALID_FRAME ==
|
||||
spdylay_frame_count_unpack_nv_space(&nvlen, &buflen,
|
||||
out, inlen+2));
|
||||
out, inlen+2, len_size));
|
||||
|
||||
/* Change number of nv pair to a bogus value */
|
||||
temp = spdylay_get_uint16(out);
|
||||
spdylay_put_uint16be(out, 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, out, inlen,
|
||||
len_size));
|
||||
spdylay_put_uint16be(out, temp);
|
||||
|
||||
/* Change the length of name to a bogus value */
|
||||
temp = spdylay_get_uint16(out+2);
|
||||
spdylay_put_uint16be(out+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, out, inlen,
|
||||
len_size));
|
||||
spdylay_put_uint16be(out+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, out, inlen,
|
||||
len_size));
|
||||
}
|
||||
|
||||
void test_spdylay_frame_pack_ping()
|
||||
|
|
Loading…
Reference in New Issue