From 7652d3f4caec27c46cfb0c1063b2bf78230ed20a Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Fri, 24 Feb 2012 23:05:49 +0900 Subject: [PATCH] Added support for 4 bytes length in name/value pair. --- lib/spdylay_frame.c | 94 +++++++++++++++++++++++--------------- lib/spdylay_frame.h | 52 ++++++++++++--------- tests/spdylay_frame_test.c | 27 +++++++---- 3 files changed, 105 insertions(+), 68 deletions(-) diff --git a/lib/spdylay_frame.c b/lib/spdylay_frame.c index 0da8178a..99cfea70 100644 --- a/lib/spdylay_frame.c +++ b/lib/spdylay_frame.c @@ -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; } diff --git a/lib/spdylay_frame.h b/lib/spdylay_frame.h index 7acb312f..25410a36 100644 --- a/lib/spdylay_frame.h +++ b/lib/spdylay_frame.h @@ -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| diff --git a/tests/spdylay_frame_test.c b/tests/spdylay_frame_test.c index 21891e65..7cadf4ee 100644 --- a/tests/spdylay_frame_test.c +++ b/tests/spdylay_frame_test.c @@ -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()