src: Compile defaltehd and inflatehd with c++

This commit also fixes defaltehd always reports output length is 0.
This commit is contained in:
Tatsuhiro Tsujikawa 2014-03-30 22:41:02 +09:00
parent 34581d830d
commit f011bda377
3 changed files with 214 additions and 196 deletions

View File

@ -141,8 +141,8 @@ bin_PROGRAMS += inflatehd deflatehd
HPACK_TOOLS_COMMON_SRCS = comp_helper.c comp_helper.h
inflatehd_SOURCES = inflatehd.c $(HPACK_TOOLS_COMMON_SRCS)
inflatehd_SOURCES = inflatehd.cc $(HPACK_TOOLS_COMMON_SRCS)
deflatehd_SOURCES = deflatehd.c $(HPACK_TOOLS_COMMON_SRCS)
deflatehd_SOURCES = deflatehd.cc $(HPACK_TOOLS_COMMON_SRCS)
endif # ENABLE_HPACK_TOOLS

View File

@ -26,21 +26,28 @@
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <cstdio>
#include <cstring>
#include <cassert>
#include <cerrno>
#include <cstdlib>
#include <vector>
#include <iostream>
#include <jansson.h>
extern "C" {
#include "nghttp2_hd.h"
#include "nghttp2_frame.h"
#include "comp_helper.h"
}
typedef struct {
size_t table_size;
size_t deflate_table_size;
@ -73,31 +80,22 @@ static void to_hex(char *dest, const uint8_t *src, size_t len)
static void output_to_json(nghttp2_hd_deflater *deflater,
nghttp2_bufs *bufs, size_t inputlen,
nghttp2_nv *nva, size_t nvlen,
const std::vector<nghttp2_nv> nva,
int seq)
{
json_t *obj;
char *hex = NULL, *hexp;
size_t len;
nghttp2_buf_chain *ci;
nghttp2_buf *buf;
auto len = nghttp2_bufs_len(bufs);
auto hex = std::vector<char>(len * 2);
auto obj = json_object();
len = nghttp2_bufs_len(bufs);
if(len > 0) {
hex = malloc(len * 2);
}
obj = json_object();
json_object_set_new(obj, "seq", json_integer(seq));
json_object_set_new(obj, "input_length", json_integer(inputlen));
json_object_set_new(obj, "output_length", json_integer(len));
json_object_set_new(obj, "percentage_of_original_size",
json_real((double)len / inputlen * 100));
hexp = hex;
for(ci = bufs->head; ci; ci = ci->next) {
buf = &ci->buf;
auto hexp = hex.data();
for(auto ci = bufs->head; ci; ci = ci->next) {
auto buf = &ci->buf;
to_hex(hexp, buf->pos, nghttp2_buf_len(buf));
hexp += nghttp2_buf_len(buf);
}
@ -105,9 +103,9 @@ static void output_to_json(nghttp2_hd_deflater *deflater,
if(len == 0) {
json_object_set_new(obj, "wire", json_string(""));
} else {
json_object_set_new(obj, "wire", json_pack("s#", hex, len * 2));
json_object_set_new(obj, "wire", json_pack("s#", hex.data(), hex.size()));
}
json_object_set_new(obj, "headers", dump_headers(nva, nvlen));
json_object_set_new(obj, "headers", dump_headers(nva.data(), nva.size()));
if(seq == 0) {
/* We only change the header table size only once at the beginning */
json_object_set_new(obj, "header_table_size",
@ -120,40 +118,37 @@ static void output_to_json(nghttp2_hd_deflater *deflater,
json_dumpf(obj, stdout, JSON_PRESERVE_ORDER | JSON_INDENT(2));
printf("\n");
json_decref(obj);
free(hex);
}
static void deflate_hd(nghttp2_hd_deflater *deflater,
nghttp2_nv *nva, size_t nvlen, size_t inputlen, int seq)
const std::vector<nghttp2_nv>& nva,
size_t inputlen, int seq)
{
ssize_t rv;
nghttp2_bufs bufs;
nghttp2_bufs_init2(&bufs, 4096, 16, 0);
rv = nghttp2_hd_deflate_hd(deflater, &bufs, nva, nvlen);
rv = nghttp2_hd_deflate_hd(deflater, &bufs,
(nghttp2_nv*)nva.data(), nva.size());
if(rv < 0) {
fprintf(stderr, "deflate failed with error code %zd at %d\n", rv, seq);
exit(EXIT_FAILURE);
}
input_sum += inputlen;
output_sum += rv;
output_sum += nghttp2_bufs_len(&bufs);
output_to_json(deflater, &bufs, inputlen, nva, nvlen, seq);
output_to_json(deflater, &bufs, inputlen, nva, seq);
nghttp2_bufs_free(&bufs);
}
static int deflate_hd_json(json_t *obj, nghttp2_hd_deflater *deflater, int seq)
{
json_t *js;
nghttp2_nv nva[128];
size_t len;
size_t i;
size_t inputlen = 0;
js = json_object_get(obj, "headers");
if(js == NULL) {
auto js = json_object_get(obj, "headers");
if(js == nullptr) {
fprintf(stderr, "'headers' key is missing at %d\n", seq);
return -1;
}
@ -162,20 +157,20 @@ static int deflate_hd_json(json_t *obj, nghttp2_hd_deflater *deflater, int seq)
"The value of 'headers' key must be an array at %d\n", seq);
return -1;
}
len = json_array_size(js);
if(len > sizeof(nva)/sizeof(nva[0])) {
fprintf(stderr, "Too many headers (> %zu) at %d\n",
sizeof(nva)/sizeof(nva[0]), seq);
return -1;
}
for(i = 0; i < len; ++i) {
json_t *nv_pair = json_array_get(js, i);
auto len = json_array_size(js);
auto nva = std::vector<nghttp2_nv>(len);
for(size_t i = 0; i < len; ++i) {
auto nv_pair = json_array_get(js, i);
const char *name;
json_t *value;
if(!json_is_object(nv_pair) || json_object_size(nv_pair) != 1) {
fprintf(stderr, "bad formatted name/value pair object at %d\n", seq);
return -1;
}
json_object_foreach(nv_pair, name, value) {
nva[i].name = (uint8_t*)name;
nva[i].namelen = strlen(name);
@ -184,12 +179,16 @@ static int deflate_hd_json(json_t *obj, nghttp2_hd_deflater *deflater, int seq)
fprintf(stderr, "value is not string at %d\n", seq);
return -1;
}
nva[i].value = (uint8_t*)json_string_value(value);
nva[i].valuelen = strlen(json_string_value(value));
}
inputlen += nva[i].namelen + nva[i].valuelen;
}
deflate_hd(deflater, nva, len, inputlen, seq);
deflate_hd(deflater, nva, inputlen, seq);
return 0;
}
@ -207,31 +206,34 @@ static void deinit_deflater(nghttp2_hd_deflater *deflater)
static int perform(void)
{
size_t i;
json_t *json, *cases;
json_error_t error;
size_t len;
nghttp2_hd_deflater deflater;
json = json_loadf(stdin, 0, &error);
if(json == NULL) {
auto json = json_loadf(stdin, 0, &error);
if(json == nullptr) {
fprintf(stderr, "JSON loading failed\n");
exit(EXIT_FAILURE);
}
cases = json_object_get(json, "cases");
if(cases == NULL) {
auto cases = json_object_get(json, "cases");
if(cases == nullptr) {
fprintf(stderr, "Missing 'cases' key in root object\n");
exit(EXIT_FAILURE);
}
if(!json_is_array(cases)) {
fprintf(stderr, "'cases' must be JSON array\n");
exit(EXIT_FAILURE);
}
init_deflater(&deflater);
output_json_header();
len = json_array_size(cases);
for(i = 0; i < len; ++i) {
json_t *obj = json_array_get(cases, i);
auto len = json_array_size(cases);
for(size_t i = 0; i < len; ++i) {
auto obj = json_array_get(cases, i);
if(!json_is_object(obj)) {
fprintf(stderr, "Unexpected JSON type at %zu. It should be object.\n",
i);
@ -253,7 +255,7 @@ static int perform(void)
static int perform_from_http1text(void)
{
char line[1 << 14];
nghttp2_nv nva[256];
std::vector<nghttp2_nv> nva;
int seq = 0;
nghttp2_hd_deflater deflater;
init_deflater(&deflater);
@ -267,16 +269,18 @@ static int perform_from_http1text(void)
nghttp2_nv *nv;
char *rv = fgets(line, sizeof(line), stdin);
char *val, *val_end;
if(rv == NULL) {
if(rv == nullptr) {
end = 1;
break;
} else if(line[0] == '\n') {
break;
}
assert(nvlen < sizeof(nva)/sizeof(nva[0]));
nva.resize(nvlen);
nv = &nva[nvlen];
val = strchr(line+1, ':');
if(val == NULL) {
if(val == nullptr) {
fprintf(stderr, "Bad HTTP/1 header field format at %d.\n", seq);
exit(EXIT_FAILURE);
}
@ -299,7 +303,7 @@ static int perform_from_http1text(void)
if(seq > 0) {
printf(",\n");
}
deflate_hd(&deflater, nva, nvlen, inputlen, seq);
deflate_hd(&deflater, nva, inputlen, seq);
}
for(i = 0; i < nvlen; ++i) {
@ -316,81 +320,82 @@ static int perform_from_http1text(void)
static void print_help(void)
{
printf("HPACK HTTP/2 header encoder\n"
"Usage: deflatehd [OPTIONS] < INPUT\n"
"\n"
"Reads JSON data or HTTP/1-style header fields from stdin and\n"
"outputs deflated header block in JSON array.\n"
"\n"
"For the JSON input, the root JSON object must contain \"context\"\n"
"key, which indicates which compression context is used. If it is\n"
"\"request\", request compression context is used. Otherwise,\n"
"response compression context is used. The value of \"cases\" key\n"
"contains the sequence of input header set. They share the same\n"
"compression context and are processed in the order they appear.\n"
"Each item in the sequence is a JSON object and it must have at\n"
"least \"headers\" key. Its value is an array of a JSON object\n"
"containing exactly one name/value pair.\n"
"\n"
"Example:\n"
"{\n"
" \"context\": \"request\",\n"
" \"cases\":\n"
" [\n"
" {\n"
" \"headers\": [\n"
" { \":method\": \"GET\" },\n"
" { \":path\": \"/\" }\n"
" ]\n"
" },\n"
" {\n"
" \"headers\": [\n"
" { \":method\": \"POST\" },\n"
" { \":path\": \"/\" }\n"
" ]\n"
" }\n"
" ]\n"
"}\n"
"\n"
"With -t option, the program can accept more familiar HTTP/1 style\n"
"header field block. Each header set must be followed by one empty\n"
"line:\n"
"\n"
"Example:\n"
":method: GET\n"
":scheme: https\n"
":path: /\n"
"\n"
":method: POST\n"
"user-agent: nghttp2\n"
"\n"
"The output of this program can be used as input for inflatehd.\n"
"\n"
"OPTIONS:\n"
" -t, --http1text Use HTTP/1 style header field text as input.\n"
" Each header set is delimited by single empty\n"
" line.\n"
" -s, --table-size=<N>\n"
" Set dynamic table size. In the HPACK\n"
" specification, this value is denoted by\n"
" SETTINGS_HEADER_TABLE_SIZE.\n"
" Default: 4096\n"
" -S, --deflate-table-size=<N>\n"
" Use first N bytes of dynamic header table\n"
" buffer.\n"
" Default: 4096\n"
" -d, --dump-header-table\n"
" Output dynamic header table.\n"
" -c, --no-refset Don't use reference set.\n");
std::cout << R"(HPACK HTTP/2 header encoder
Usage: deflatehd [OPTIONS] < INPUT
Reads JSON data or HTTP/1-style header fields from stdin and outputs
deflated header block in JSON array.
For the JSON input, the root JSON object must contain "context" key,
which indicates which compression context is used. If it is
"request", request compression context is used. Otherwise, response
compression context is used. The value of "cases" key contains the
sequence of input header set. They share the same compression context
and are processed in the order they appear. Each item in the sequence
is a JSON object and it must have at least "headers" key. Its value
is an array of a JSON object containing exactly one name/value pair.
Example:
{
"context": "request",
"cases":
[
{
"headers": [
{ ":method": "GET" },
{ ":path": "/" }
]
},
{
"headers": [
{ ":method": "POST" },
{ ":path": "/" }
]
}
]
}
With -t option, the program can accept more familiar HTTP/1 style
header field block. Each header set must be followed by one empty
line:
Example:
:method: GET
:scheme: https
:path: /
:method: POST
user-agent: nghttp2
The output of this program can be used as input for inflatehd.
OPTIONS:
-t, --http1text Use HTTP/1 style header field text as input.
Each header set is delimited by single empty
line.
-s, --table-size=<N>
Set dynamic table size. In the HPACK
specification, this value is denoted by
SETTINGS_HEADER_TABLE_SIZE.
Default: 4096
-S, --deflate-table-size=<N>
Use first N bytes of dynamic header table
buffer.
Default: 4096
-d, --dump-header-table
Output dynamic header table.
-c, --no-refset Don't use reference set.)"
<< std::endl;
}
static struct option long_options[] = {
{"http1text", no_argument, NULL, 't'},
{"table-size", required_argument, NULL, 's'},
{"deflate-table-size", required_argument, NULL, 'S'},
{"dump-header-table", no_argument, NULL, 'd'},
{"no-refset", no_argument, NULL, 'c'},
{NULL, 0, NULL, 0 }
{"http1text", no_argument, nullptr, 't'},
{"table-size", required_argument, nullptr, 's'},
{"deflate-table-size", required_argument, nullptr, 'S'},
{"dump-header-table", no_argument, nullptr, 'd'},
{"no-refset", no_argument, nullptr, 'c'},
{nullptr, 0, nullptr, 0 }
};
int main(int argc, char **argv)

View File

@ -26,21 +26,28 @@
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <cstdio>
#include <cstring>
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <cerrno>
#include <cstdlib>
#include <vector>
#include <iostream>
#include <jansson.h>
extern "C" {
#include "nghttp2_hd.h"
#include "nghttp2_frame.h"
#include "comp_helper.h"
}
typedef struct {
int dump_header_table;
} inflate_config;
@ -70,9 +77,7 @@ static void to_json(nghttp2_hd_inflater *inflater,
json_t *headers, json_t *wire, int seq,
size_t old_settings_table_size)
{
json_t *obj;
obj = json_object();
auto obj = json_object();
json_object_set_new(obj, "seq", json_integer(seq));
json_object_set(obj, "wire", wire);
json_object_set(obj, "headers", headers);
@ -91,21 +96,20 @@ static void to_json(nghttp2_hd_inflater *inflater,
static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq)
{
json_t *wire, *table_size, *headers;
size_t inputlen;
uint8_t *buf, *p;
size_t buflen;
ssize_t rv;
nghttp2_nv nv;
int inflate_flags;
size_t old_settings_table_size = inflater->settings_hd_table_bufsize_max;
wire = json_object_get(obj, "wire");
if(wire == NULL) {
auto wire = json_object_get(obj, "wire");
if(wire == nullptr) {
fprintf(stderr, "'wire' key is missing at %d\n", seq);
return -1;
}
table_size = json_object_get(obj, "header_table_size");
auto table_size = json_object_get(obj, "header_table_size");
if(table_size) {
if(!json_is_integer(table_size)) {
fprintf(stderr,
@ -122,18 +126,22 @@ static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq)
return -1;
}
}
inputlen = strlen(json_string_value(wire));
auto inputlen = strlen(json_string_value(wire));
if(inputlen & 1) {
fprintf(stderr, "Badly formatted output value at %d\n", seq);
exit(EXIT_FAILURE);
}
buflen = inputlen / 2;
buf = malloc(buflen);
decode_hex(buf, json_string_value(wire), inputlen);
headers = json_array();
auto buflen = inputlen / 2;
auto buf = std::vector<uint8_t>(buflen);
p = buf;
decode_hex(buf.data(), json_string_value(wire), inputlen);
auto headers = json_array();
auto p = buf.data();
for(;;) {
inflate_flags = 0;
rv = nghttp2_hd_inflate_hd(inflater, &nv, &inflate_flags, p, buflen, 1);
@ -155,37 +163,40 @@ static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq)
nghttp2_hd_inflate_end_headers(inflater);
to_json(inflater, headers, wire, seq, old_settings_table_size);
json_decref(headers);
free(buf);
return 0;
}
static int perform(void)
{
nghttp2_hd_inflater inflater;
size_t i;
json_t *json, *cases;
json_error_t error;
size_t len;
json = json_loadf(stdin, 0, &error);
if(json == NULL) {
auto json = json_loadf(stdin, 0, &error);
if(json == nullptr) {
fprintf(stderr, "JSON loading failed\n");
exit(EXIT_FAILURE);
}
cases = json_object_get(json, "cases");
if(cases == NULL) {
auto cases = json_object_get(json, "cases");
if(cases == nullptr) {
fprintf(stderr, "Missing 'cases' key in root object\n");
exit(EXIT_FAILURE);
}
if(!json_is_array(cases)) {
fprintf(stderr, "'cases' must be JSON array\n");
exit(EXIT_FAILURE);
}
nghttp2_hd_inflate_init(&inflater);
output_json_header();
len = json_array_size(cases);
for(i = 0; i < len; ++i) {
json_t *obj = json_array_get(cases, i);
auto len = json_array_size(cases);
for(size_t i = 0; i < len; ++i) {
auto obj = json_array_get(cases, i);
if(!json_is_object(obj)) {
fprintf(stderr, "Unexpected JSON type at %zu. It should be object.\n",
i);
@ -201,47 +212,49 @@ static int perform(void)
output_json_footer();
nghttp2_hd_inflate_free(&inflater);
json_decref(json);
return 0;
}
static void print_help(void)
{
printf("HPACK HTTP/2 header decoder\n"
"Usage: inflatehd [OPTIONS] < INPUT\n"
"\n"
"Reads JSON data from stdin and outputs inflated name/value pairs\n"
"in JSON.\n"
"\n"
"The root JSON object must contain \"context\" key, which indicates\n"
"which compression context is used. If it is \"request\", request\n"
"compression context is used. Otherwise, response compression\n"
"context is used. The value of \"cases\" key contains the sequence\n"
"of compressed header block. They share the same compression\n"
"context and are processed in the order they appear. Each item in\n"
"the sequence is a JSON object and it must have at least \"wire\"\n"
"key. Its value is a string containing compressed header block in\n"
"hex string.\n"
"\n"
"Example:\n"
"{\n"
" \"context\": \"request\",\n"
" \"cases\":\n"
" [\n"
" { \"wire\": \"0284f77778ff\" },\n"
" { \"wire\": \"0185fafd3c3c7f81\" }\n"
" ]\n"
"}\n"
"\n"
"The output of this program can be used as input for deflatehd.\n"
"\n"
"OPTIONS:\n"
" -d, --dump-header-table\n"
" Output dynamic header table.\n");
std::cout << R"(HPACK HTTP/2 header decoder
Usage: inflatehd [OPTIONS] < INPUT
Reads JSON data from stdin and outputs inflated name/value pairs in
JSON.
The root JSON object must contain "context" key, which indicates which
compression context is used. If it is "request", request compression
context is used. Otherwise, response compression context is used.
The value of "cases" key contains the sequence of compressed header
block. They share the same compression context and are processed in
the order they appear. Each item in the sequence is a JSON object and
it must have at least "wire" key. Its value is a string containing
compressed header block in hex string.
Example:
{
"context": "request",
"cases":
[
{ "wire": "0284f77778ff" },
{ "wire": "0185fafd3c3c7f81" }
]
}
The output of this program can be used as input for deflatehd.
OPTIONS:
-d, --dump-header-table
Output dynamic header table.)"
<< std::endl;;
}
static struct option long_options[] = {
{"dump-header-table", no_argument, NULL, 'd'},
{NULL, 0, NULL, 0 }
{"dump-header-table", no_argument, nullptr, 'd'},
{nullptr, 0, nullptr, 0 }
};
int main(int argc, char **argv)