Implement header compression draft 01

This commit is contained in:
Tatsuhiro Tsujikawa 2013-07-19 16:50:31 +09:00
parent 257bc1c924
commit 45c2245bfb
12 changed files with 1743 additions and 4 deletions

View File

@ -36,14 +36,16 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \
nghttp2_stream.c nghttp2_outbound_item.c \
nghttp2_session.c nghttp2_submit.c \
nghttp2_helper.c \
nghttp2_npn.c nghttp2_gzip.c
nghttp2_npn.c nghttp2_gzip.c \
nghttp2_hd.c
HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
nghttp2_buffer.h nghttp2_frame.h nghttp2_zlib.h \
nghttp2_session.h nghttp2_helper.h nghttp2_stream.h nghttp2_int.h \
nghttp2_npn.h nghttp2_gzip.h \
nghttp2_submit.h nghttp2_outbound_item.h \
nghttp2_net.h
nghttp2_net.h \
nghttp2_hd.h
libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS)
libnghttp2_la_LDFLAGS = -no-undefined \

View File

@ -155,6 +155,10 @@ typedef enum {
* The length of the frame is too large.
*/
NGHTTP2_ERR_FRAME_TOO_LARGE = -522,
/**
* Header block inflate/deflate error.
*/
NGHTTP2_ERR_HEADER_COMP = -523,
/**
* The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is
* under unexpected condition and cannot process any further data
@ -175,6 +179,31 @@ typedef enum {
NGHTTP2_MSG_MORE
} nghttp2_io_flag;
/**
* @struct
*
* The name/value pair, which mainly used to represent header fields.
*/
typedef struct {
/**
* The |name| byte string, which is not necessarily NULL terminated.
*/
uint8_t *name;
/**
* The |value| byte string, which is not necessarily NULL
* terminated.
*/
uint8_t *value;
/**
* The length of the |name|.
*/
uint16_t namelen;
/**
* The length of the |value|.
*/
uint16_t valuelen;
} nghttp2_nv;
/**
* @enum
* The control frame types in HTTP/2.0.

View File

@ -839,3 +839,15 @@ int nghttp2_frame_nv_check_null(const char **nv)
}
return 1;
}
int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b)
{
return a->namelen == b->namelen && a->valuelen == b->valuelen &&
memcmp(a->name, b->name, a->namelen) == 0 &&
memcmp(a->value, b->value, a->valuelen) == 0;
}
void nghttp2_nv_array_free(nghttp2_nv *nva)
{
free(nva);
}

View File

@ -40,6 +40,8 @@
#define NGHTTP2_PRI_DEFAULT (1 << 30)
#define NGHTTP2_PRI_LOWEST ((1U << 31) - 1)
#define NGHTTP2_MAX_FRAME_SIZE ((1 << 16) - 1)
#define NGHTTP2_STREAM_ID_MASK 0x7fffffff
#define NGHTTP2_PRIORITY_MASK 0x7fffffff
#define NGHTTP2_WINDOW_SIZE_INCREMENT_MASK 0x7fffffff
@ -571,4 +573,13 @@ ssize_t nghttp2_frame_nv_offset(const uint8_t *head);
*/
int nghttp2_frame_nv_check_null(const char **nv);
/*
* Returns nonzero if the name/value pair |a| equals to |b|. The name
* is compared in case-sensitive, because we ensure that this function
* is called after the name is lower-cased.
*/
int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b);
void nghttp2_nv_array_free(nghttp2_nv *nva);
#endif /* NGHTTP2_FRAME_H */

1088
lib/nghttp2_hd.c Normal file

File diff suppressed because it is too large Load Diff

236
lib/nghttp2_hd.h Normal file
View File

@ -0,0 +1,236 @@
/*
* nghttp2 - HTTP/2.0 C Library
*
* Copyright (c) 2013 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_HD_COMP_H
#define NGHTTP2_HD_COMP_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
#define NGHTTP2_INITIAL_HD_TABLE_SIZE 128
#define NGHTTP2_INITIAL_REFSET_SIZE 128
#define NGHTTP2_INITIAL_WS_SIZE 128
#define NGHTTP2_MAX_HD_TABLE_CAPACITY 4096
#define NGHTTP2_HD_ENTRY_OVERHEAD 32
typedef enum {
NGHTTP2_HD_SIDE_CLIENT = 0,
NGHTTP2_HD_SIDE_SERVER = 1
} nghttp2_hd_side;
typedef enum {
NGHTTP2_HD_FLAG_NONE = 0,
/* Indicates name was dynamically allocated and must be freed */
NGHTTP2_HD_FLAG_NAME_ALLOC = 1,
/* Indicates value was dynamically allocated and must be freed */
NGHTTP2_HD_FLAG_VALUE_ALLOC = 1 << 1,
} nghttp2_hd_flags;
typedef struct {
nghttp2_nv nv;
/* Reference count in workingset */
uint8_t ref;
uint8_t index;
uint8_t flags;
} nghttp2_hd_entry;
typedef enum {
NGHTTP2_HD_CAT_NONE,
NGHTTP2_HD_CAT_INDEXED,
NGHTTP2_HD_CAT_LITERAL_IDXNAME,
NGHTTP2_HD_CAT_LITERAL
} nghttp2_hd_entry_cat;
typedef struct nghttp2_hd_ws_entry {
nghttp2_hd_entry_cat cat;
union {
/* For NGHTTP2_HD_CAT_INDEXED */
nghttp2_hd_entry *entry;
/* For NGHTTP2_HD_CAT_LITERAL */
nghttp2_nv nv;
/* For NGHTTP2_HD_CAT_LITERAL_IDXNAME */
struct {
/* The entry in header table the name stored */
nghttp2_hd_entry *entry;
uint8_t *value;
uint16_t valuelen;
} entv;
};
/* TODO Only usable with NGHTTP2_HD_CAT_INDEXED */
uint8_t index;
uint8_t checked;
} nghttp2_hd_ws_entry;
typedef struct {
/* Header table */
nghttp2_hd_entry **hd_table;
/* Reference set */
nghttp2_hd_entry **refset;
/* Working set */
nghttp2_hd_ws_entry *ws;
/* The capacity of the |hd_table| */
uint16_t hd_table_capacity;
/* the number of entry the |hd_table| contains */
uint16_t hd_tablelen;
/* The capacity of the |refset| */
uint16_t refset_capacity;
/* The number of entry the |refset| contains */
uint16_t refsetlen;
/* The capacity of the |ws| */
uint16_t ws_capacity;
/* The number of entry the |ws| contains */
uint16_t wslen;
/* Abstract capacity of hd_table as described in the spec. This is
the sum of length of name/value in hd_table +
NGHTTP2_HD_ENTRY_OVERHEAD bytes overhead per each entry. */
uint16_t capacity;
} nghttp2_hd_context;
/*
* Initializes the |ent| members. If NGHTTP2_HD_FLAG_NAME_ALLOC bit
* set in the |flags|, the content pointed by the |name| with length
* |namelen| is copied. Likewise, if NGHTTP2_HD_FLAG_VALUE_ALLOC bit
* set in the |flags|, the content pointed by the |value| with length
* |valuelen| is copied.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t index, uint8_t flags,
uint8_t *name, uint16_t namelen,
uint8_t *value, uint16_t valuelen);
void nghttp2_hd_entry_free(nghttp2_hd_entry *ent);
/*
* Initializes |deflater| for deflating name/values pairs.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_hd_deflate_init(nghttp2_hd_context *deflater,
nghttp2_hd_side side);
/*
* Initializes |inflater| for inflating name/values pairs.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_hd_inflate_init(nghttp2_hd_context *inflater,
nghttp2_hd_side side);
/*
* Deallocates any resources allocated for |deflater|.
*/
void nghttp2_hd_deflate_free(nghttp2_hd_context *deflater);
/*
* Deallocates any resources allocated for |inflater|.
*/
void nghttp2_hd_inflate_free(nghttp2_hd_context *inflater);
/*
* Deflates the |nv|, which has the |nvlen| name/value pairs, into the
* buffer pointed by the |*buf_ptr| with the length |*buflen_ptr|.
*
* This function expands |*buf_ptr| as necessary to store the
* result. When expansion occurred, memory previously pointed by
* |*buf_ptr| is freed. |*buf_ptr| and |*buflen_ptr| are updated
* accordingly.
*
* This function returns the number of bytes outputted if it succeeds,
* or one of the following negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_context *deflater,
uint8_t **buf_ptr, size_t *buflen_ptr,
size_t nv_offset,
nghttp2_nv *nv, size_t nvlen);
/*
* Inflates name/value block stored in |in| with length |inlen|. This
* function performs decompression. The |*nv_ptr| points to the final
* result on succesful decompression. The caller must free |*nv_ptr|
* using nghttp2_nv_free().
*
* This function returns the number of bytes outputted if it succeeds,
* or one of the following negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_context *inflater,
nghttp2_nv **nva_ptr,
uint8_t *in, size_t inlen);
/*
* Signals the end of processing one header block. This function
* creates new reference set from working set.
*
* This function returns 0 if it succeeds. Currently this function
* always succeeds.
*/
int nghttp2_hd_end_headers(nghttp2_hd_context *deflater_or_inflater);
/* For unittesting purpose */
int nghttp2_hd_emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, nghttp2_hd_entry *ent,
const uint8_t *value, size_t valuelen,
int inc_indexing);
/* For unittesting purpose */
int nghttp2_hd_emit_literal_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, nghttp2_nv *nv,
int inc_indexing);
/* For unittesting purpose */
int nghttp2_hd_emit_subst_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr,
nghttp2_hd_entry *ent,
const uint8_t *value, size_t valuelen,
size_t index);
/* For unittesting purpose */
int nghttp2_hd_emit_subst_literal_block(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t *offset_ptr, nghttp2_nv *nv,
size_t index);
#endif /* NGHTTP2_HD_COMP_H */

View File

@ -71,6 +71,16 @@ int nghttp2_reserve_buffer(uint8_t **buf_ptr, size_t *buflen_ptr,
return 0;
}
void* nghttp2_memdup(const void* src, size_t n)
{
void* dest = malloc(n);
if(dest == NULL) {
return NULL;
}
memcpy(dest, src, n);
return dest;
}
const char* nghttp2_strerror(int error_code)
{
switch(error_code) {

View File

@ -77,4 +77,16 @@ uint32_t nghttp2_get_uint32(const uint8_t *data);
int nghttp2_reserve_buffer(uint8_t **buf_ptr, size_t *buflen_ptr,
size_t min_length);
/*
* Allocates |n| bytes of memory and copy the meory region pointed by
* |src| with the length |n| bytes into it. Returns the allocated memory.
*
* This function returns pointer to allocated memory, or one of the
* following negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
void* nghttp2_memdup(const void* src, size_t n);
#endif /* NGHTTP2_HELPER_H */

View File

@ -33,13 +33,14 @@ OBJECTS = main.c nghttp2_pq_test.c nghttp2_map_test.c nghttp2_queue_test.c \
nghttp2_frame_test.c \
nghttp2_stream_test.c \
nghttp2_session_test.c \
nghttp2_hd_test.c \
nghttp2_npn_test.c \
nghttp2_gzip_test.c
HFILES = nghttp2_pq_test.h nghttp2_map_test.h nghttp2_queue_test.h \
nghttp2_buffer_test.h nghttp2_zlib_test.h nghttp2_session_test.h \
nghttp2_frame_test.h nghttp2_stream_test.h nghttp2_npn_test.h \
nghttp2_gzip_test.h nghttp2_test_helper.h
nghttp2_frame_test.h nghttp2_stream_test.h nghttp2_hd_test.h \
nghttp2_npn_test.h nghttp2_gzip_test.h nghttp2_test_helper.h
main_SOURCES = $(HFILES) $(OBJECTS)

View File

@ -34,6 +34,7 @@
#include "nghttp2_session_test.h"
#include "nghttp2_frame_test.h"
#include "nghttp2_stream_test.h"
#include "nghttp2_hd_test.h"
#include "nghttp2_npn_test.h"
#include "nghttp2_gzip_test.h"
@ -199,6 +200,21 @@ int main(int argc, char* argv[])
/* !CU_add_test(pSuite, "stream_add_pushed_stream", */
/* test_nghttp2_stream_add_pushed_stream) || */
!CU_add_test(pSuite, "hd_deflate", test_nghttp2_hd_deflate) ||
!CU_add_test(pSuite, "hd_inflate_indname_inc",
test_nghttp2_hd_inflate_indname_inc) ||
!CU_add_test(pSuite, "hd_inflate_indname_inc_eviction",
test_nghttp2_hd_inflate_indname_inc_eviction) ||
!CU_add_test(pSuite, "hd_inflate_newname_inc",
test_nghttp2_hd_inflate_newname_inc) ||
!CU_add_test(pSuite, "hd_inflate_indname_subst",
test_nghttp2_hd_inflate_newname_inc) ||
!CU_add_test(pSuite, "hd_inflate_indname_subst_eviction",
test_nghttp2_hd_inflate_indname_subst_eviction) ||
!CU_add_test(pSuite, "hd_inflate_indname_subst_eviction_neg",
test_nghttp2_hd_inflate_indname_subst_eviction_neg) ||
!CU_add_test(pSuite, "hd_inflate_newname_subst",
test_nghttp2_hd_inflate_newname_subst) ||
!CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate)
) {
CU_cleanup_registry();

285
tests/nghttp2_hd_test.c Normal file
View File

@ -0,0 +1,285 @@
/*
* nghttp2 - HTTP/2.0 C Library
*
* Copyright (c) 2013 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "nghttp2_hd_test.h"
#include <stdio.h>
#include <assert.h>
#include <CUnit/CUnit.h>
#include "nghttp2_hd.h"
#include "nghttp2_frame.h"
#define MAKE_NV(NAME, VALUE) \
{ (uint8_t*)NAME, (uint8_t*)VALUE, strlen(NAME), strlen(VALUE) }
static void assert_nv_equal(nghttp2_nv *a, nghttp2_nv *b, size_t len)
{
size_t i;
for(i = 0; i < len; ++i, ++a, ++b) {
CU_ASSERT(nghttp2_nv_equal(a, b));
}
}
void test_nghttp2_hd_deflate(void)
{
nghttp2_hd_context deflater, inflater;
nghttp2_nv nva1[] = {MAKE_NV(":path", "/my-example/index.html"),
MAKE_NV(":scheme", "https"),
MAKE_NV("hello", "world")};
nghttp2_nv nva2[] = {MAKE_NV(":path", "/script.js"),
MAKE_NV(":scheme", "https")};
nghttp2_nv nvtemp;
size_t nv_offset = 12;
uint8_t *buf = NULL;
size_t buflen = 0;
nghttp2_nv *resnva;
ssize_t blocklen;
CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_CLIENT));
CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER));
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, nv_offset, nva1,
sizeof(nva1)/sizeof(nghttp2_nv));
CU_ASSERT((1+1+22)+(1)+(1+1+5+1+5) == blocklen);
nghttp2_hd_end_headers(&deflater);
CU_ASSERT(3 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf + nv_offset,
blocklen));
assert_nv_equal(nva1, resnva, 3);
nghttp2_nv_array_free(resnva);
nghttp2_hd_end_headers(&inflater);
CU_ASSERT(1 == inflater.refsetlen);
/* Second headers */
blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, nv_offset, nva2,
sizeof(nva2)/sizeof(nghttp2_nv));
CU_ASSERT((1+1+10) == blocklen);
nghttp2_hd_end_headers(&deflater);
CU_ASSERT(2 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf + nv_offset,
blocklen));
/* First and second header fields are interchanged their positions. */
nvtemp = nva2[0];
nva2[0] = nva2[1];
nva2[1] = nvtemp;
assert_nv_equal(nva2, resnva, 2);
nghttp2_nv_array_free(resnva);
nghttp2_hd_end_headers(&inflater);
free(buf);
nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater);
}
void test_nghttp2_hd_inflate_indname_inc(void)
{
nghttp2_hd_context inflater;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t offset = 0;
nghttp2_nv nv = MAKE_NV("user-agent", "nghttp2");
nghttp2_nv *resnva;
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER);
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset,
inflater.hd_table[12],
nv.value, nv.valuelen,
1));
CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset));
assert_nv_equal(&nv, resnva, 1);
CU_ASSERT(39 == inflater.hd_tablelen);
assert_nv_equal(&nv, &inflater.hd_table[inflater.hd_tablelen-1]->nv, 1);
nghttp2_nv_array_free(resnva);
free(buf);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_indname_inc_eviction(void)
{
nghttp2_hd_context inflater;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t offset = 0;
/* Default header table capacity is 1592. Adding 2547 bytes,
including overhead, to the table evicts first entry.
use name ":host" which index 2 and value length 2510. */
uint8_t value[2510];
nghttp2_nv *resnva;
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER);
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset,
inflater.hd_table[2],
value, sizeof(value), 1));
CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset));
CU_ASSERT(5 == resnva[0].namelen);
CU_ASSERT(0 == memcmp(":host", resnva[0].name, resnva[0].namelen));
CU_ASSERT(sizeof(value) == resnva[0].valuelen);
nghttp2_nv_array_free(resnva);
nghttp2_hd_end_headers(&inflater);
CU_ASSERT(38 == inflater.hd_tablelen);
CU_ASSERT(37 == inflater.refset[0]->index);
free(buf);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_newname_inc(void)
{
nghttp2_hd_context inflater;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t offset = 0;
nghttp2_nv nv = MAKE_NV("x-rel", "nghttp2");
nghttp2_nv *resnva;
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER);
CU_ASSERT(0 == nghttp2_hd_emit_literal_block(&buf, &buflen, &offset,
&nv, 1));
CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset));
assert_nv_equal(&nv, resnva, 1);
CU_ASSERT(39 == inflater.hd_tablelen);
assert_nv_equal(&nv, &inflater.hd_table[inflater.hd_tablelen-1]->nv, 1);
nghttp2_nv_array_free(resnva);
free(buf);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_indname_subst(void)
{
nghttp2_hd_context inflater;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t offset = 0;
nghttp2_nv nv = MAKE_NV("user-agent", "nghttp2");
nghttp2_nv *resnva;
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER);
CU_ASSERT(0 == nghttp2_hd_emit_subst_indname_block(&buf, &buflen, &offset,
inflater.hd_table[12],
nv.value, nv.valuelen,
12));
CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset));
assert_nv_equal(&nv, resnva, 1);
CU_ASSERT(38 == inflater.hd_tablelen);
assert_nv_equal(&nv, &inflater.hd_table[12]->nv, 1);
nghttp2_nv_array_free(resnva);
free(buf);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_indname_subst_eviction(void)
{
nghttp2_hd_context inflater;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t offset = 0;
/* Default header table capacity is 1592. Adding 2547 bytes,
including overhead, to the table evicts first entry.
use name ":host" which index 2 and value length 2510. */
uint8_t value[2510];
nghttp2_nv *resnva;
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER);
CU_ASSERT(0 == nghttp2_hd_emit_subst_indname_block(&buf, &buflen, &offset,
inflater.hd_table[2],
value, sizeof(value), 2));
CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset));
CU_ASSERT(5 == resnva[0].namelen);
CU_ASSERT(0 == memcmp(":host", resnva[0].name, resnva[0].namelen));
CU_ASSERT(sizeof(value) == resnva[0].valuelen);
nghttp2_nv_array_free(resnva);
nghttp2_hd_end_headers(&inflater);
CU_ASSERT(37 == inflater.hd_tablelen);
CU_ASSERT(1 == inflater.refset[0]->index);
free(buf);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_indname_subst_eviction_neg(void)
{
nghttp2_hd_context inflater;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t offset = 0;
/* Default header table capacity is 1592. Adding 2548 bytes,
including overhead, to the table evicts first entry.
use name ":host" which index 2 and value length 2511. */
uint8_t value[2511];
nghttp2_nv *resnva;
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER);
/* Try to substitute index 0, but it will be evicted */
CU_ASSERT(0 == nghttp2_hd_emit_subst_indname_block(&buf, &buflen, &offset,
inflater.hd_table[2],
value, sizeof(value), 0));
CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset));
CU_ASSERT(5 == resnva[0].namelen);
CU_ASSERT(0 == memcmp(":host", resnva[0].name, resnva[0].namelen));
CU_ASSERT(sizeof(value) == resnva[0].valuelen);
nghttp2_nv_array_free(resnva);
nghttp2_hd_end_headers(&inflater);
CU_ASSERT(37 == inflater.hd_tablelen);
CU_ASSERT(0 == inflater.refset[0]->index);
free(buf);
nghttp2_hd_inflate_free(&inflater);
}
void test_nghttp2_hd_inflate_newname_subst(void)
{
nghttp2_hd_context inflater;
uint8_t *buf = NULL;
size_t buflen = 0;
size_t offset = 0;
nghttp2_nv nv = MAKE_NV("x-rel", "nghttp2");
nghttp2_nv *resnva;
nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_SERVER);
CU_ASSERT(0 == nghttp2_hd_emit_subst_literal_block(&buf, &buflen, &offset,
&nv, 1));
CU_ASSERT(1 == nghttp2_hd_inflate_hd(&inflater, &resnva, buf, offset));
assert_nv_equal(&nv, resnva, 1);
CU_ASSERT(38 == inflater.hd_tablelen);
assert_nv_equal(&nv, &inflater.hd_table[1]->nv, 1);
nghttp2_nv_array_free(resnva);
free(buf);
nghttp2_hd_inflate_free(&inflater);
}

37
tests/nghttp2_hd_test.h Normal file
View File

@ -0,0 +1,37 @@
/*
* nghttp2 - HTTP/2.0 C Library
*
* Copyright (c) 2013 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_HD_TEST_H
#define NGHTTP2_HD_TEST_H
void test_nghttp2_hd_deflate(void);
void test_nghttp2_hd_inflate_indname_inc(void);
void test_nghttp2_hd_inflate_indname_inc_eviction(void);
void test_nghttp2_hd_inflate_newname_inc(void);
void test_nghttp2_hd_inflate_indname_subst(void);
void test_nghttp2_hd_inflate_indname_subst_eviction(void);
void test_nghttp2_hd_inflate_indname_subst_eviction_neg(void);
void test_nghttp2_hd_inflate_newname_subst(void);
#endif /* NGHTTP2_HD_TEST_H */