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 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 endif # ENABLE_HPACK_TOOLS

View File

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

View File

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