38 unsigned char buf[64];
40 size_t consumed = 0, w;
46 memcpy(buf + w,
"hello", 5);
61 buf[5] = (
unsigned char)(buf[5] | 0x80);
68 unsigned char buf[16];
90 unsigned char pay[12];
129 for (i = 0; i < n; i++)
130 if (h[i].name && strcmp(h[i].name, name) == 0)
141 unsigned char buf[1024];
145 memset(big,
'x', 300);
147 in[0].
name = (
char*)
":method";
148 in[0].
value = (
char*)
"GET";
149 in[1].
name = (
char*)
":path";
150 in[1].
value = (
char*)
"/a/b?c=d";
151 in[2].
name = (
char*)
"x-custom";
152 in[2].
value = (
char*)
"hello world";
153 in[3].
name = (
char*)
"x-big";
173 static const unsigned char r1[] = {0x82, 0x86, 0x84, 0x41, 0x0f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d};
175 static const unsigned char r2[] = {0x82, 0x86, 0x84, 0xbe, 0x58, 0x08, 0x6e, 0x6f, 0x2d, 0x63, 0x61, 0x63, 0x68, 0x65};
177 static const unsigned char r3[] = {0x82, 0x87, 0x85, 0xbf, 0x40, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, 0x0c, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65};
185 if (!
find_hdr(out, count,
":authority") || strcmp(
find_hdr(out, count,
":authority"),
"www.example.com") != 0)
failures++;
190 if (!
find_hdr(out, count,
":authority") || strcmp(
find_hdr(out, count,
":authority"),
"www.example.com") != 0)
failures++;
191 if (!
find_hdr(out, count,
"cache-control") || strcmp(
find_hdr(out, count,
"cache-control"),
"no-cache") != 0)
failures++;
197 if (!
find_hdr(out, count,
"custom-key") || strcmp(
find_hdr(out, count,
"custom-key"),
"custom-value") != 0)
failures++;
206 static const unsigned char req[] = {0x82, 0x86, 0x84, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 0xff};
207 static const unsigned char resp[] = {
208 0x48, 0x82, 0x64, 0x02, 0x58, 0x85, 0xae, 0xc3, 0x77, 0x1a, 0x4b, 0x61, 0x96, 0xd0, 0x7a, 0xbe,
209 0x94, 0x10, 0x54, 0xd4, 0x44, 0xa8, 0x20, 0x05, 0x95, 0x04, 0x0b, 0x81, 0x66, 0xe0, 0x82, 0xa6,
210 0x2d, 0x1b, 0xff, 0x6e, 0x91, 0x9d, 0x29, 0xad, 0x17, 0x18, 0x63, 0xc7, 0x8f, 0x0b, 0x97, 0xc8,
211 0xe9, 0xae, 0x82, 0xae, 0x43, 0xd3};
218 if (!
find_hdr(out, count,
":authority") || strcmp(
find_hdr(out, count,
":authority"),
"www.example.com") != 0)
failures++;
224 if (!
find_hdr(out, count,
"cache-control") || strcmp(
find_hdr(out, count,
"cache-control"),
"private") != 0)
failures++;
225 if (!
find_hdr(out, count,
"date") || strcmp(
find_hdr(out, count,
"date"),
"Mon, 21 Oct 2013 20:13:21 GMT") != 0)
failures++;
226 if (!
find_hdr(out, count,
"location") || strcmp(
find_hdr(out, count,
"location"),
"https://www.example.com") != 0)
failures++;
238 static const unsigned char r1[] = {0x82, 0x86, 0x84, 0x41, 0x0f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d};
251 static const unsigned char bad_index[] = {0x80};
252 static const unsigned char truncated[] = {0x40, 0x05, 0x61};
266 while ((opt = getopt(argc, argv,
"hvV:")) != EOF) {
269 if (!strncmp(
"LOG_NULL", optarg, 8))
271 else if (!strncmp(
"LOG_NOTICE", optarg, 10))
273 else if (!strncmp(
"LOG_INFO", optarg, 8))
275 else if (!strncmp(
"LOG_ERR", optarg, 7))
277 else if (!strncmp(
"LOG_DEBUG", optarg, 9))
281 fprintf(stderr,
"ex_http2\n");
289int main(
int argc,
char** argv) {
void process_args(int argc, char **argv)
static void test_hpack_rfc_huffman(void)
static void test_hpack_roundtrip(void)
static void test_roundtrip(void)
static void test_settings(void)
static const char * find_hdr(const N_H2_HEADER *h, size_t n, const char *name)
static void test_preface(void)
static void test_boundaries(void)
static void test_hpack_guards(void)
static void test_hpack_overflow(void)
static void test_hpack_rfc_requests(void)
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_DEBUG
debug-level messages
#define LOG_ERR
error conditions
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
#define LOG_NOTICE
normal but significant condition
#define LOG_NULL
no log output
#define LOG_INFO
informational
int n_http2_hpack_decode(N_H2_HPACK *ctx, const unsigned char *block, size_t len, N_H2_HEADER *out, size_t max_out, size_t *count)
decode an HPACK header block into out[] (owned name/value strings).
size_t n_http2_hpack_encode(const N_H2_HEADER *headers, size_t n, unsigned char *out, size_t out_cap)
encode a header list into a block using literal representations without indexing and without Huffman ...
N_H2_HPACK * n_http2_hpack_new(size_t max_table_size)
create an HPACK codec context with the given dynamic table size limit (0 uses N_H2_HPACK_DEFAULT_TABL...
void n_http2_hpack_free(N_H2_HPACK **pctx)
free an HPACK codec context and NULL the caller's pointer
void n_http2_hpack_headers_free(N_H2_HEADER *headers, size_t n)
free the owned name/value strings of a decoded header array (does not free the array itself)
int n_http2_settings_parse(const unsigned char *payload, size_t len, N_H2_SETTING *out, size_t max, size_t *count)
parse a SETTINGS frame payload (6-byte id/value entries) into out.
int n_http2_frame_parse(const unsigned char *buf, size_t len, N_H2_FRAME *frame, size_t *consumed)
parse one HTTP/2 frame from a byte buffer (stateless).
size_t n_http2_frame_build_header(unsigned char *out, size_t out_cap, uint32_t length, int type, int flags, uint32_t stream_id)
write a 9-byte HTTP/2 frame header into out.
HPACK codec context: the dynamic table (index 0 = most recently added)
HTTP/2 (RFC 7540) wire framing plus HPACK header compression (RFC 7541)
char * value
header field value (owned after decode)
#define N_H2_PREFACE
the client connection preface sent before any HTTP/2 frame (RFC 7540 3.5)
#define N_H2_FLAG_END_HEADERS
HEADERS/PUSH_PROMISE/CONTINUATION: header block complete.
#define N_H2_FRAME_HEADER_LEN
length of the fixed frame header in bytes
char * name
header field name (owned after decode)
#define N_H2_SETTINGS_INITIAL_WINDOW_SIZE
#define N_H2_WINDOW_UPDATE
WINDOW_UPDATE.
uint32_t length
payload length (24-bit)
const unsigned char * payload
pointer into the input buffer (may be NULL when length is 0)
int type
frame type (N_H2_*)
uint32_t stream_id
stream identifier (31-bit; the reserved bit is cleared)
#define N_H2_HEADERS
HEADERS.
#define N_H2_FLAG_END_STREAM
DATA/HEADERS: last frame of the stream.
#define N_H2_SETTINGS_MAX_CONCURRENT_STREAMS
a parsed HTTP/2 frame; payload aliases the input buffer
one HPACK header field; after a decode both strings are owned (heap)
one SETTINGS parameter (identifier and value)