Commit da9bbb58 authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

HPACK tools: Use JSON data format used in hpack-test-case

The input and output data format now use same JSON format used in
hpack-test-case.
parent 331a2f89
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include "comp_helper.h" #include "comp_helper.h"
#include <string.h>
static void dump_val(json_t *jent, const char *key, uint8_t *val, size_t len) static void dump_val(json_t *jent, const char *key, uint8_t *val, size_t len)
{ {
...@@ -55,13 +56,46 @@ json_t* dump_header_table(nghttp2_hd_context *context) ...@@ -55,13 +56,46 @@ json_t* dump_header_table(nghttp2_hd_context *context)
} }
json_object_set_new(obj, "entries", entries); json_object_set_new(obj, "entries", entries);
json_object_set_new(obj, "size", json_integer(context->hd_table_bufsize)); json_object_set_new(obj, "size", json_integer(context->hd_table_bufsize));
json_object_set_new(obj, "maxSize", json_object_set_new(obj, "max_size",
json_integer(context->hd_table_bufsize_max)); json_integer(context->hd_table_bufsize_max));
if(context->role == NGHTTP2_HD_ROLE_DEFLATE) { if(context->role == NGHTTP2_HD_ROLE_DEFLATE) {
json_object_set_new(obj, "deflateSize", json_object_set_new(obj, "deflate_size",
json_integer(context->deflate_hd_table_bufsize)); json_integer(context->deflate_hd_table_bufsize));
json_object_set_new(obj, "maxDeflateSize", json_object_set_new(obj, "max_deflate_size",
json_integer(context->deflate_hd_table_bufsize_max)); json_integer(context->deflate_hd_table_bufsize_max));
} }
return obj; return obj;
} }
json_t* dump_headers(const nghttp2_nv *nva, size_t nvlen)
{
json_t *headers;
size_t i;
headers = json_array();
for(i = 0; i < nvlen; ++i) {
json_t *nv_pair = json_object();
char *name = strndup((const char*)nva[i].name, nva[i].namelen);
name[nva[i].namelen] = '\0';
json_object_set_new(nv_pair, name,
json_pack("s#", nva[i].value, nva[i].valuelen));
free(name);
json_array_append_new(headers, nv_pair);
}
return headers;
}
void output_json_header(int side)
{
printf("{\n"
" \"context\": \"%s\",\n"
" \"cases\":\n"
" [\n",
(side == NGHTTP2_HD_SIDE_REQUEST ? "request" : "response"));
}
void output_json_footer(void)
{
printf(" ]\n"
"}\n");
}
...@@ -35,4 +35,10 @@ ...@@ -35,4 +35,10 @@
json_t* dump_header_table(nghttp2_hd_context *context); json_t* dump_header_table(nghttp2_hd_context *context);
json_t* dump_headers(const nghttp2_nv *nva, size_t nvlen);
void output_json_header(int side);
void output_json_footer();
#endif /* NGHTTP2_COMP_HELPER_H */ #endif /* NGHTTP2_COMP_HELPER_H */
...@@ -55,40 +55,52 @@ static deflate_config config; ...@@ -55,40 +55,52 @@ static deflate_config config;
static size_t input_sum; static size_t input_sum;
static size_t output_sum; static size_t output_sum;
static char to_hex_digit(uint8_t n)
{
if(n > 9) {
return n - 10 + 'a';
}
return n + '0';
}
static void to_hex(char *dest, const uint8_t *src, size_t len) static void to_hex(char *dest, const uint8_t *src, size_t len)
{ {
size_t i; size_t i;
for(i = 0; i < len; ++i) { for(i = 0; i < len; ++i) {
sprintf(dest, "%02x", src[i]); *dest++ = to_hex_digit(src[i] >> 4);
dest += 2; *dest++ = to_hex_digit(src[i] & 0xf);
} }
} }
static void output_to_json(nghttp2_hd_context *deflater, static void output_to_json(nghttp2_hd_context *deflater,
const uint8_t *buf, size_t len, size_t inputlen, const uint8_t *buf, size_t len, size_t inputlen,
nghttp2_nv *nva, size_t nvlen,
int seq) int seq)
{ {
json_t *obj; json_t *obj;
char hex[16*1024]; char *hex = NULL;
if(len * 2 > sizeof(hex)) { if(len > 0) {
fprintf(stderr, "Output too large at %d\n", seq); hex = malloc(len * 2);
exit(EXIT_FAILURE);
} }
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_new(obj, "inputLen", json_integer(inputlen)); json_object_set_new(obj, "input_length", json_integer(inputlen));
json_object_set_new(obj, "outputLength", json_integer(len)); json_object_set_new(obj, "output_length", json_integer(len));
json_object_set_new(obj, "percentageOfOriginalSize", json_object_set_new(obj, "percentage_of_original_size",
json_real((double)len / inputlen * 100)); json_real((double)len / inputlen * 100));
to_hex(hex, buf, len); to_hex(hex, buf, len);
json_object_set_new(obj, "output", json_pack("s#", hex, len * 2)); json_object_set_new(obj, "wire", json_pack("s#", hex, len * 2));
json_object_set_new(obj, "headers", dump_headers(nva, nvlen));
json_object_set_new(obj, "header_table_size",
json_integer(config.table_size));
if(config.dump_header_table) { if(config.dump_header_table) {
json_object_set_new(obj, "headerTable", dump_header_table(deflater)); json_object_set_new(obj, "header_table", dump_header_table(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_context *deflater, static void deflate_hd(nghttp2_hd_context *deflater,
...@@ -104,7 +116,7 @@ static void deflate_hd(nghttp2_hd_context *deflater, ...@@ -104,7 +116,7 @@ static void deflate_hd(nghttp2_hd_context *deflater,
} }
input_sum += inputlen; input_sum += inputlen;
output_sum += rv; output_sum += rv;
output_to_json(deflater, buf, rv, inputlen, seq); output_to_json(deflater, buf, rv, inputlen, nva, nvlen, seq);
nghttp2_hd_end_headers(deflater); nghttp2_hd_end_headers(deflater);
free(buf); free(buf);
} }
...@@ -119,11 +131,12 @@ static int deflate_hd_json(json_t *obj, nghttp2_hd_context *deflater, int seq) ...@@ -119,11 +131,12 @@ static int deflate_hd_json(json_t *obj, nghttp2_hd_context *deflater, int seq)
js = json_object_get(obj, "headers"); js = json_object_get(obj, "headers");
if(js == NULL) { if(js == NULL) {
fprintf(stderr, "headers key is missing at %d\n", seq); fprintf(stderr, "'headers' key is missing at %d\n", seq);
return -1; return -1;
} }
if(!json_is_array(js)) { if(!json_is_array(js)) {
fprintf(stderr, "headers value must be an array at %d\n", seq); fprintf(stderr,
"The value of 'headers' key must be an array at %d\n", seq);
return -1; return -1;
} }
len = json_array_size(js); len = json_array_size(js);
...@@ -134,70 +147,101 @@ static int deflate_hd_json(json_t *obj, nghttp2_hd_context *deflater, int seq) ...@@ -134,70 +147,101 @@ static int deflate_hd_json(json_t *obj, nghttp2_hd_context *deflater, int seq)
} }
for(i = 0; i < len; ++i) { for(i = 0; i < len; ++i) {
json_t *nv_pair = json_array_get(js, i); json_t *nv_pair = json_array_get(js, i);
json_t *s; const char *name;
if(!json_is_array(nv_pair) || json_array_size(nv_pair) != 2) { json_t *value;
fprintf(stderr, "bad formatted name/value pair array at %d\n", seq); if(!json_is_object(nv_pair) || json_object_size(nv_pair) != 1) {
return -1; fprintf(stderr, "bad formatted name/value pair object at %d\n", seq);
}
s = json_array_get(nv_pair, 0);
if(!json_is_string(s)) {
fprintf(stderr, "bad formatted name/value pair array at %d\n", seq);
return -1; return -1;
} }
nva[i].name = (uint8_t*)json_string_value(s); json_object_foreach(nv_pair, name, value) {
nva[i].namelen = strlen(json_string_value(s)); nva[i].name = (uint8_t*)name;
nva[i].namelen = strlen(name);
s = json_array_get(nv_pair, 1); if(!json_is_string(value)) {
if(!json_is_string(s)) { fprintf(stderr, "value is not string at %d\n", seq);
fprintf(stderr, "bad formatted name/value pair array at %d\n", seq);
return -1; return -1;
} }
nva[i].value = (uint8_t*)json_string_value(s); nva[i].value = (uint8_t*)json_string_value(value);
nva[i].valuelen = strlen(json_string_value(s)); 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, len, inputlen, seq);
return 0; return 0;
} }
static int perform(nghttp2_hd_context *deflater) static void init_deflater(nghttp2_hd_context *deflater, nghttp2_hd_side side)
{
nghttp2_hd_deflate_init2(deflater, side, config.deflate_table_size);
nghttp2_hd_deflate_set_no_refset(deflater, config.no_refset);
nghttp2_hd_change_table_size(deflater, config.table_size);
}
static void deinit_deflater(nghttp2_hd_context *deflater)
{
nghttp2_hd_deflate_free(deflater);
}
static int perform(void)
{ {
size_t i; size_t i;
json_t *json; json_t *json, *cases;
json_error_t error; json_error_t error;
size_t len; size_t len;
nghttp2_hd_context deflater;
nghttp2_hd_side side;
json = json_loadf(stdin, 0, &error); json = json_loadf(stdin, 0, &error);
if(json == NULL) { if(json == NULL) {
fprintf(stderr, "JSON loading failed\n"); fprintf(stderr, "JSON loading failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
printf("[\n"); if(strcmp("request", json_string_value(json_object_get(json, "context")))
len = json_array_size(json); == 0) {
side = NGHTTP2_HD_SIDE_REQUEST;
} else {
side = NGHTTP2_HD_SIDE_RESPONSE;
}
cases = json_object_get(json, "cases");
if(cases == NULL) {
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, side);
output_json_header(side);
len = json_array_size(cases);
for(i = 0; i < len; ++i) { for(i = 0; i < len; ++i) {
json_t *obj = json_array_get(json, i); json_t *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);
continue; continue;
} }
if(deflate_hd_json(obj, deflater, i) != 0) { if(deflate_hd_json(obj, &deflater, i) != 0) {
continue; continue;
} }
if(i + 1 < len) { if(i + 1 < len) {
printf(",\n"); printf(",\n");
} }
} }
printf("]\n"); output_json_footer();
deinit_deflater(&deflater);
json_decref(json); json_decref(json);
return 0; return 0;
} }
static int perform_from_http1text(nghttp2_hd_context *deflater) static int perform_from_http1text(void)
{ {
char line[1 << 14]; char line[1 << 14];
nghttp2_nv nva[256]; nghttp2_nv nva[256];
int seq = 0; int seq = 0;
printf("[\n"); nghttp2_hd_context deflater;
init_deflater(&deflater, config.side);
output_json_header(config.side);
for(;;) { for(;;) {
size_t nvlen = 0; size_t nvlen = 0;
int end = 0; int end = 0;
...@@ -239,7 +283,7 @@ static int perform_from_http1text(nghttp2_hd_context *deflater) ...@@ -239,7 +283,7 @@ static int perform_from_http1text(nghttp2_hd_context *deflater)
if(seq > 0) { if(seq > 0) {
printf(",\n"); printf(",\n");
} }
deflate_hd(deflater, nva, nvlen, inputlen, seq); deflate_hd(&deflater, nva, nvlen, inputlen, seq);
} }
for(i = 0; i < nvlen; ++i) { for(i = 0; i < nvlen; ++i) {
...@@ -249,7 +293,8 @@ static int perform_from_http1text(nghttp2_hd_context *deflater) ...@@ -249,7 +293,8 @@ static int perform_from_http1text(nghttp2_hd_context *deflater)
if(end) break; if(end) break;
++seq; ++seq;
} }
printf("]\n"); output_json_footer();
deinit_deflater(&deflater);
return 0; return 0;
} }
...@@ -258,32 +303,38 @@ static void print_help(void) ...@@ -258,32 +303,38 @@ static void print_help(void)
printf("HPACK HTTP/2.0 header encoder\n" printf("HPACK HTTP/2.0 header encoder\n"
"Usage: deflatehd [OPTIONS] < INPUT\n" "Usage: deflatehd [OPTIONS] < INPUT\n"
"\n" "\n"
"Reads JSON array or HTTP/1-style header fields from stdin and\n" "Reads JSON data or HTTP/1-style header fields from stdin and\n"
"outputs deflated header block in JSON array.\n" "outputs deflated header block in JSON array.\n"
"\n" "\n"
"For the JSON input, the element of input array must be a JSON\n" "For the JSON input, the root JSON object must contain \"context\"\n"
"object. Each object must have at least following key:\n" "key, which indicates which compression context is used. If it is\n"
"\n" "\"request\", request compression context is used. Otherwise,\n"
" headers: a JSON array of name/value pairs. The each element is\n" "response compression context is used. The value of \"cases\" key\n"
" a JSON array of 2 strings. The index 0 must\n" "contains the sequence of input header set. They share the same\n"
" contain header name and the index 1 must contain\n" "compression context and are processed in the order they appear.\n"
" header value.\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" "\n"
"Example:\n" "Example:\n"
"[\n" "{\n"
" \"context\": \"request\",\n"
" \"cases\":\n"
" [\n"
" {\n" " {\n"
" \"headers\": [\n" " \"headers\": [\n"
" [ \":method\", \"GET\" ],\n" " { \":method\": \"GET\" },\n"
" [ \":path\", \"/\" ]\n" " { \":path\": \"/\" }\n"
" ]\n" " ]\n"
" },\n" " },\n"
" {\n" " {\n"
" \"headers\": [\n" " \"headers\": [\n"
" [ \":method\", \"POST\" ],\n" " { \":method\": \"POST\" },\n"
" [ \":path\", \"/\" ]\n" " { \":path\": \"/\" }\n"
" ]\n" " ]\n"
" }\n" " }\n"
"]\n" " ]\n"
"}\n"
"\n" "\n"
"With -t option, the program can accept more familiar HTTP/1 style\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" "header field block. Each header set must be followed by one empty\n"
...@@ -301,7 +352,9 @@ static void print_help(void) ...@@ -301,7 +352,9 @@ static void print_help(void)
"\n" "\n"
"OPTIONS:\n" "OPTIONS:\n"
" -r, --response Use response compression context instead of\n" " -r, --response Use response compression context instead of\n"
" request.\n" " request if -t is used. For JSON input, it is\n"
" determined by inspecting \"context\" key in\n"
" root JSON object.\n"
" -t, --http1text Use HTTP/1 style header field text as input.\n" " -t, --http1text Use HTTP/1 style header field text as input.\n"
" Each header set is delimited by single empty\n" " Each header set is delimited by single empty\n"
" line.\n" " line.\n"
...@@ -331,7 +384,6 @@ static struct option long_options[] = { ...@@ -331,7 +384,6 @@ static struct option long_options[] = {
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
nghttp2_hd_context deflater;
char *end; char *end;
config.side = NGHTTP2_HD_SIDE_REQUEST; config.side = NGHTTP2_HD_SIDE_REQUEST;
...@@ -388,16 +440,12 @@ int main(int argc, char **argv) ...@@ -388,16 +440,12 @@ int main(int argc, char **argv)
break; break;
} }
} }
nghttp2_hd_deflate_init2(&deflater, config.side, config.deflate_table_size);
nghttp2_hd_deflate_set_no_refset(&deflater, config.no_refset);
nghttp2_hd_change_table_size(&deflater, config.table_size);
if(config.http1text) { if(config.http1text) {
perform_from_http1text(&deflater); perform_from_http1text();
} else { } else {
perform(&deflater); perform();
} }
fprintf(stderr, "Overall: input=%zu output=%zu ratio=%.02f\n", fprintf(stderr, "Overall: input=%zu output=%zu ratio=%.02f\n",
input_sum, output_sum, (double)output_sum / input_sum); input_sum, output_sum, (double)output_sum / input_sum);
nghttp2_hd_deflate_free(&deflater);
return 0; return 0;
} }
...@@ -43,7 +43,6 @@ ...@@ -43,7 +43,6 @@
typedef struct { typedef struct {
size_t table_size; size_t table_size;
nghttp2_hd_side side;
int dump_header_table; int dump_header_table;
} inflate_config; } inflate_config;
...@@ -69,24 +68,19 @@ static void decode_hex(uint8_t *dest, const char *src, size_t len) ...@@ -69,24 +68,19 @@ static void decode_hex(uint8_t *dest, const char *src, size_t len)
} }
static void nva_to_json(nghttp2_hd_context *inflater, static void nva_to_json(nghttp2_hd_context *inflater,
const nghttp2_nv *nva, size_t nvlen, int seq) const nghttp2_nv *nva, size_t nvlen,
json_t *wire, int seq)
{ {
size_t i;
json_t *obj; json_t *obj;
json_t *headers;
obj = json_object(); obj = json_object();
json_object_set_new(obj, "seq", json_integer(seq)); json_object_set_new(obj, "seq", json_integer(seq));
headers = json_array(); json_object_set(obj, "wire", wire);
json_object_set_new(obj, "headers", headers); json_object_set_new(obj, "headers", dump_headers(nva, nvlen));
for(i = 0; i < nvlen; ++i) { json_object_set_new(obj, "header_table_size",
json_t *nv_pair = json_array(); json_integer(inflater->hd_table_bufsize_max));
const nghttp2_nv *nv = &nva[i];
json_array_append_new(nv_pair, json_pack("s#", nv->name, nv->namelen));
json_array_append_new(nv_pair, json_pack("s#", nv->value, nv->valuelen));
json_array_append_new(headers, nv_pair);
}
if(config.dump_header_table) { if(config.dump_header_table) {
json_object_set_new(obj, "headerTable", dump_header_table(inflater)); json_object_set_new(obj, "header_table", dump_header_table(inflater));
} }
json_dumpf(obj, stdout, JSON_INDENT(2) | JSON_PRESERVE_ORDER); json_dumpf(obj, stdout, JSON_INDENT(2) | JSON_PRESERVE_ORDER);
json_decref(obj); json_decref(obj);
...@@ -95,27 +89,42 @@ static void nva_to_json(nghttp2_hd_context *inflater, ...@@ -95,27 +89,42 @@ static void nva_to_json(nghttp2_hd_context *inflater,
static int inflate_hd(json_t *obj, nghttp2_hd_context *inflater, int seq) static int inflate_hd(json_t *obj, nghttp2_hd_context *inflater, int seq)
{ {
json_t *js; json_t *wire, *table_size;
size_t inputlen; size_t inputlen;
uint8_t buf[16*1024]; uint8_t *buf;
ssize_t resnvlen; ssize_t resnvlen;
nghttp2_nv *resnva; nghttp2_nv *resnva;
int rv;
js = json_object_get(obj, "output"); wire = json_object_get(obj, "wire");
if(js == NULL) { if(wire == NULL) {
fprintf(stderr, "output key is missing at %d\n", seq); fprintf(stderr, "'wire' key is missing at %d\n", seq);
return -1;
}
table_size = json_object_get(obj, "header_table_size");
if(table_size) {
if(!json_is_integer(table_size)) {
fprintf(stderr,
"The value of 'header_table_size key' is not integer at %d\n",
seq);
return -1;
}
rv = nghttp2_hd_change_table_size(inflater,
json_integer_value(table_size));
if(rv != 0) {
fprintf(stderr,
"nghttp2_hd_change_table_size() failed with error %s at %d\n",
nghttp2_strerror(rv), seq);
return -1; return -1;
} }
inputlen = strlen(json_string_value(js)); }
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);
} }
if(inputlen / 2 > sizeof(buf)) { buf = malloc(inputlen / 2);
fprintf(stderr, "Too big input length %zu at %d\n", inputlen / 2, seq); decode_hex(buf, json_string_value(wire), inputlen);
exit(EXIT_FAILURE);
}
decode_hex(buf, json_string_value(js), inputlen);
resnvlen = nghttp2_hd_inflate_hd(inflater, &resnva, buf, inputlen / 2); resnvlen = nghttp2_hd_inflate_hd(inflater, &resnva, buf, inputlen / 2);
if(resnvlen < 0) { if(resnvlen < 0) {
...@@ -123,9 +132,10 @@ static int inflate_hd(json_t *obj, nghttp2_hd_context *inflater, int seq) ...@@ -123,9 +132,10 @@ static int inflate_hd(json_t *obj, nghttp2_hd_context *inflater, int seq)
resnvlen, seq); resnvlen, seq);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
nva_to_json(inflater, resnva, resnvlen, seq); nva_to_json(inflater, resnva, resnvlen, wire, seq);
nghttp2_hd_end_headers(inflater); nghttp2_hd_end_headers(inflater);
nghttp2_nv_array_del(resnva); nghttp2_nv_array_del(resnva);
free(buf);
return 0; return 0;
} }
...@@ -133,21 +143,38 @@ static int perform(void) ...@@ -133,21 +143,38 @@ static int perform(void)
{ {
nghttp2_hd_context inflater; nghttp2_hd_context inflater;
size_t i; size_t i;
json_t *json; json_t *json, *cases;
json_error_t error; json_error_t error;
size_t len; size_t len;
nghttp2_hd_side side;
json = json_loadf(stdin, 0, &error); json = json_loadf(stdin, 0, &error);
if(json == NULL) { if(json == NULL) {
fprintf(stderr, "JSON loading failed\n"); fprintf(stderr, "JSON loading failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
nghttp2_hd_inflate_init(&inflater, config.side); if(strcmp("request", json_string_value(json_object_get(json, "context")))
== 0) {
side = NGHTTP2_HD_SIDE_REQUEST;
} else {
side = NGHTTP2_HD_SIDE_RESPONSE;
}
cases = json_object_get(json, "cases");
if(cases == NULL) {
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, side);
nghttp2_hd_change_table_size(&inflater, config.table_size); nghttp2_hd_change_table_size(&inflater, config.table_size);
printf("[\n");
len = json_array_size(json); output_json_header(side);
len = json_array_size(cases);
for(i = 0; i < len; ++i) { for(i = 0; i < len; ++i) {
json_t *obj = json_array_get(json, i); json_t *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);
...@@ -160,7 +187,7 @@ static int perform(void) ...@@ -160,7 +187,7 @@ static int perform(void)
printf(",\n"); printf(",\n");
} }
} }
printf("]\n"); output_json_footer();
nghttp2_hd_inflate_free(&inflater); nghttp2_hd_inflate_free(&inflater);
json_decref(json); json_decref(json);
return 0; return 0;
...@@ -171,24 +198,32 @@ static void print_help(void) ...@@ -171,24 +198,32 @@ static void print_help(void)
printf("HPACK HTTP/2.0 header decoder\n" printf("HPACK HTTP/2.0 header decoder\n"
"Usage: inflatehd [OPTIONS] < INPUT\n" "Usage: inflatehd [OPTIONS] < INPUT\n"
"\n" "\n"
"Reads JSON array from stdin and outputs inflated name/value pairs\n" "Reads JSON data from stdin and outputs inflated name/value pairs\n"
"in JSON array.\n" "in JSON.\n"
"The element of input array must be a JSON object. Each object must\n"
"have at least following key:\n"
"\n" "\n"
" output: deflated header block in hex-string.\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" "\n"
"Example:\n" "Example:\n"
"[\n" "{\n"
" { \"output\": \"0284f77778ff\" },\n" " \"context\": \"request\",\n"
" { \"output\": \"0185fafd3c3c7f81\" }\n" " \"cases\":\n"
"]\n" " [\n"
" { \"wire\": \"0284f77778ff\" },\n"
" { \"wire\": \"0185fafd3c3c7f81\" }\n"
" ]\n"
"}\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"
"\n" "\n"
"OPTIONS:\n" "OPTIONS:\n"
" -r, --response Use response compression context instead of\n"
" request.\n"
" -s, --table-size=<N>\n" " -s, --table-size=<N>\n"
" Set dynamic table size. In the HPACK\n" " Set dynamic table size. In the HPACK\n"
" specification, this value is denoted by\n" " specification, this value is denoted by\n"
...@@ -199,7 +234,6 @@ static void print_help(void) ...@@ -199,7 +234,6 @@ static void print_help(void)
} }
static struct option long_options[] = { static struct option long_options[] = {
{"response", no_argument, NULL, 'r'},
{"table-size", required_argument, NULL, 's'}, {"table-size", required_argument, NULL, 's'},
{"dump-header-table", no_argument, NULL, 'd'}, {"dump-header-table", no_argument, NULL, 'd'},
{NULL, 0, NULL, 0 } {NULL, 0, NULL, 0 }
...@@ -208,20 +242,15 @@ static struct option long_options[] = { ...@@ -208,20 +242,15 @@ static struct option long_options[] = {
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
char *end; char *end;
config.side = NGHTTP2_HD_SIDE_REQUEST;
config.table_size = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE; config.table_size = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
config.dump_header_table = 0; config.dump_header_table = 0;
while(1) { while(1) {
int option_index = 0; int option_index = 0;
int c = getopt_long(argc, argv, "dhrs:", long_options, &option_index); int c = getopt_long(argc, argv, "dhs:", long_options, &option_index);
if(c == -1) { if(c == -1) {
break; break;
} }
switch(c) { switch(c) {
case 'r':
/* --response */
config.side = NGHTTP2_HD_SIDE_RESPONSE;
break;
case 'h': case 'h':
print_help(); print_help();
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment