12c593315Sopenharmony_ci/*
22c593315Sopenharmony_ci * nghttp2 - HTTP/2 C Library
32c593315Sopenharmony_ci *
42c593315Sopenharmony_ci * Copyright (c) 2013 Tatsuhiro Tsujikawa
52c593315Sopenharmony_ci *
62c593315Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining
72c593315Sopenharmony_ci * a copy of this software and associated documentation files (the
82c593315Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
92c593315Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
102c593315Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to
112c593315Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
122c593315Sopenharmony_ci * the following conditions:
132c593315Sopenharmony_ci *
142c593315Sopenharmony_ci * The above copyright notice and this permission notice shall be
152c593315Sopenharmony_ci * included in all copies or substantial portions of the Software.
162c593315Sopenharmony_ci *
172c593315Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
182c593315Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
192c593315Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
202c593315Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
212c593315Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
222c593315Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
232c593315Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
242c593315Sopenharmony_ci */
252c593315Sopenharmony_ci#ifdef HAVE_CONFIG_H
262c593315Sopenharmony_ci#  include <config.h>
272c593315Sopenharmony_ci#endif // HAVE_CONFIG_H
282c593315Sopenharmony_ci
292c593315Sopenharmony_ci#ifdef HAVE_UNISTD_H
302c593315Sopenharmony_ci#  include <unistd.h>
312c593315Sopenharmony_ci#endif // HAVE_UNISTD_H
322c593315Sopenharmony_ci#include <getopt.h>
332c593315Sopenharmony_ci
342c593315Sopenharmony_ci#include <cstdio>
352c593315Sopenharmony_ci#include <cstring>
362c593315Sopenharmony_ci#include <cassert>
372c593315Sopenharmony_ci#include <cerrno>
382c593315Sopenharmony_ci#include <cstdlib>
392c593315Sopenharmony_ci#include <vector>
402c593315Sopenharmony_ci#include <iostream>
412c593315Sopenharmony_ci
422c593315Sopenharmony_ci#include <jansson.h>
432c593315Sopenharmony_ci
442c593315Sopenharmony_ci#include <nghttp2/nghttp2.h>
452c593315Sopenharmony_ci
462c593315Sopenharmony_ci#include "template.h"
472c593315Sopenharmony_ci#include "comp_helper.h"
482c593315Sopenharmony_ci#include "util.h"
492c593315Sopenharmony_ci
502c593315Sopenharmony_cinamespace nghttp2 {
512c593315Sopenharmony_ci
522c593315Sopenharmony_citypedef struct {
532c593315Sopenharmony_ci  size_t table_size;
542c593315Sopenharmony_ci  size_t deflate_table_size;
552c593315Sopenharmony_ci  int http1text;
562c593315Sopenharmony_ci  int dump_header_table;
572c593315Sopenharmony_ci} deflate_config;
582c593315Sopenharmony_ci
592c593315Sopenharmony_cistatic deflate_config config;
602c593315Sopenharmony_ci
612c593315Sopenharmony_cistatic size_t input_sum;
622c593315Sopenharmony_cistatic size_t output_sum;
632c593315Sopenharmony_ci
642c593315Sopenharmony_cistatic char to_hex_digit(uint8_t n) {
652c593315Sopenharmony_ci  if (n > 9) {
662c593315Sopenharmony_ci    return n - 10 + 'a';
672c593315Sopenharmony_ci  }
682c593315Sopenharmony_ci  return n + '0';
692c593315Sopenharmony_ci}
702c593315Sopenharmony_ci
712c593315Sopenharmony_cistatic void to_hex(char *dest, const uint8_t *src, size_t len) {
722c593315Sopenharmony_ci  size_t i;
732c593315Sopenharmony_ci  for (i = 0; i < len; ++i) {
742c593315Sopenharmony_ci    *dest++ = to_hex_digit(src[i] >> 4);
752c593315Sopenharmony_ci    *dest++ = to_hex_digit(src[i] & 0xf);
762c593315Sopenharmony_ci  }
772c593315Sopenharmony_ci}
782c593315Sopenharmony_ci
792c593315Sopenharmony_cistatic void output_to_json(nghttp2_hd_deflater *deflater, const uint8_t *buf,
802c593315Sopenharmony_ci                           size_t buflen, size_t inputlen,
812c593315Sopenharmony_ci                           const std::vector<nghttp2_nv> &nva, int seq) {
822c593315Sopenharmony_ci  auto hex = std::vector<char>(buflen * 2);
832c593315Sopenharmony_ci  auto obj = json_object();
842c593315Sopenharmony_ci  auto comp_ratio = inputlen == 0 ? 0.0 : (double)buflen / inputlen * 100;
852c593315Sopenharmony_ci
862c593315Sopenharmony_ci  json_object_set_new(obj, "seq", json_integer(seq));
872c593315Sopenharmony_ci  json_object_set_new(obj, "input_length", json_integer(inputlen));
882c593315Sopenharmony_ci  json_object_set_new(obj, "output_length", json_integer(buflen));
892c593315Sopenharmony_ci  json_object_set_new(obj, "percentage_of_original_size",
902c593315Sopenharmony_ci                      json_real(comp_ratio));
912c593315Sopenharmony_ci
922c593315Sopenharmony_ci  if (buflen == 0) {
932c593315Sopenharmony_ci    json_object_set_new(obj, "wire", json_string(""));
942c593315Sopenharmony_ci  } else {
952c593315Sopenharmony_ci    to_hex(hex.data(), buf, buflen);
962c593315Sopenharmony_ci    json_object_set_new(obj, "wire", json_pack("s#", hex.data(), hex.size()));
972c593315Sopenharmony_ci  }
982c593315Sopenharmony_ci  json_object_set_new(obj, "headers", dump_headers(nva.data(), nva.size()));
992c593315Sopenharmony_ci  if (seq == 0) {
1002c593315Sopenharmony_ci    // We only change the header table size only once at the beginning
1012c593315Sopenharmony_ci    json_object_set_new(obj, "header_table_size",
1022c593315Sopenharmony_ci                        json_integer(config.table_size));
1032c593315Sopenharmony_ci  }
1042c593315Sopenharmony_ci  if (config.dump_header_table) {
1052c593315Sopenharmony_ci    json_object_set_new(obj, "header_table",
1062c593315Sopenharmony_ci                        dump_deflate_header_table(deflater));
1072c593315Sopenharmony_ci  }
1082c593315Sopenharmony_ci  json_dumpf(obj, stdout, JSON_PRESERVE_ORDER | JSON_INDENT(2));
1092c593315Sopenharmony_ci  printf("\n");
1102c593315Sopenharmony_ci  json_decref(obj);
1112c593315Sopenharmony_ci}
1122c593315Sopenharmony_ci
1132c593315Sopenharmony_cistatic void deflate_hd(nghttp2_hd_deflater *deflater,
1142c593315Sopenharmony_ci                       const std::vector<nghttp2_nv> &nva, size_t inputlen,
1152c593315Sopenharmony_ci                       int seq) {
1162c593315Sopenharmony_ci  ssize_t rv;
1172c593315Sopenharmony_ci  std::array<uint8_t, 64_k> buf;
1182c593315Sopenharmony_ci
1192c593315Sopenharmony_ci  rv = nghttp2_hd_deflate_hd(deflater, buf.data(), buf.size(),
1202c593315Sopenharmony_ci                             (nghttp2_nv *)nva.data(), nva.size());
1212c593315Sopenharmony_ci  if (rv < 0) {
1222c593315Sopenharmony_ci    fprintf(stderr, "deflate failed with error code %zd at %d\n", rv, seq);
1232c593315Sopenharmony_ci    exit(EXIT_FAILURE);
1242c593315Sopenharmony_ci  }
1252c593315Sopenharmony_ci
1262c593315Sopenharmony_ci  input_sum += inputlen;
1272c593315Sopenharmony_ci  output_sum += rv;
1282c593315Sopenharmony_ci
1292c593315Sopenharmony_ci  output_to_json(deflater, buf.data(), rv, inputlen, nva, seq);
1302c593315Sopenharmony_ci}
1312c593315Sopenharmony_ci
1322c593315Sopenharmony_cistatic int deflate_hd_json(json_t *obj, nghttp2_hd_deflater *deflater,
1332c593315Sopenharmony_ci                           int seq) {
1342c593315Sopenharmony_ci  size_t inputlen = 0;
1352c593315Sopenharmony_ci
1362c593315Sopenharmony_ci  auto js = json_object_get(obj, "headers");
1372c593315Sopenharmony_ci  if (js == nullptr) {
1382c593315Sopenharmony_ci    fprintf(stderr, "'headers' key is missing at %d\n", seq);
1392c593315Sopenharmony_ci    return -1;
1402c593315Sopenharmony_ci  }
1412c593315Sopenharmony_ci  if (!json_is_array(js)) {
1422c593315Sopenharmony_ci    fprintf(stderr, "The value of 'headers' key must be an array at %d\n", seq);
1432c593315Sopenharmony_ci    return -1;
1442c593315Sopenharmony_ci  }
1452c593315Sopenharmony_ci
1462c593315Sopenharmony_ci  auto len = json_array_size(js);
1472c593315Sopenharmony_ci  auto nva = std::vector<nghttp2_nv>(len);
1482c593315Sopenharmony_ci
1492c593315Sopenharmony_ci  for (size_t i = 0; i < len; ++i) {
1502c593315Sopenharmony_ci    auto nv_pair = json_array_get(js, i);
1512c593315Sopenharmony_ci    const char *name;
1522c593315Sopenharmony_ci    json_t *value;
1532c593315Sopenharmony_ci
1542c593315Sopenharmony_ci    if (!json_is_object(nv_pair) || json_object_size(nv_pair) != 1) {
1552c593315Sopenharmony_ci      fprintf(stderr, "bad formatted name/value pair object at %d\n", seq);
1562c593315Sopenharmony_ci      return -1;
1572c593315Sopenharmony_ci    }
1582c593315Sopenharmony_ci
1592c593315Sopenharmony_ci    json_object_foreach(nv_pair, name, value) {
1602c593315Sopenharmony_ci      nva[i].name = (uint8_t *)name;
1612c593315Sopenharmony_ci      nva[i].namelen = strlen(name);
1622c593315Sopenharmony_ci
1632c593315Sopenharmony_ci      if (!json_is_string(value)) {
1642c593315Sopenharmony_ci        fprintf(stderr, "value is not string at %d\n", seq);
1652c593315Sopenharmony_ci        return -1;
1662c593315Sopenharmony_ci      }
1672c593315Sopenharmony_ci
1682c593315Sopenharmony_ci      nva[i].value = (uint8_t *)json_string_value(value);
1692c593315Sopenharmony_ci      nva[i].valuelen = strlen(json_string_value(value));
1702c593315Sopenharmony_ci
1712c593315Sopenharmony_ci      nva[i].flags = NGHTTP2_NV_FLAG_NONE;
1722c593315Sopenharmony_ci    }
1732c593315Sopenharmony_ci
1742c593315Sopenharmony_ci    inputlen += nva[i].namelen + nva[i].valuelen;
1752c593315Sopenharmony_ci  }
1762c593315Sopenharmony_ci
1772c593315Sopenharmony_ci  deflate_hd(deflater, nva, inputlen, seq);
1782c593315Sopenharmony_ci
1792c593315Sopenharmony_ci  return 0;
1802c593315Sopenharmony_ci}
1812c593315Sopenharmony_ci
1822c593315Sopenharmony_cistatic nghttp2_hd_deflater *init_deflater() {
1832c593315Sopenharmony_ci  nghttp2_hd_deflater *deflater;
1842c593315Sopenharmony_ci  nghttp2_hd_deflate_new(&deflater, config.deflate_table_size);
1852c593315Sopenharmony_ci  if (config.table_size != NGHTTP2_DEFAULT_HEADER_TABLE_SIZE) {
1862c593315Sopenharmony_ci    nghttp2_hd_deflate_change_table_size(deflater, config.table_size);
1872c593315Sopenharmony_ci  }
1882c593315Sopenharmony_ci  return deflater;
1892c593315Sopenharmony_ci}
1902c593315Sopenharmony_ci
1912c593315Sopenharmony_cistatic void deinit_deflater(nghttp2_hd_deflater *deflater) {
1922c593315Sopenharmony_ci  nghttp2_hd_deflate_del(deflater);
1932c593315Sopenharmony_ci}
1942c593315Sopenharmony_ci
1952c593315Sopenharmony_cistatic int perform(void) {
1962c593315Sopenharmony_ci  json_error_t error;
1972c593315Sopenharmony_ci
1982c593315Sopenharmony_ci  auto json = json_loadf(stdin, 0, &error);
1992c593315Sopenharmony_ci
2002c593315Sopenharmony_ci  if (json == nullptr) {
2012c593315Sopenharmony_ci    fprintf(stderr, "JSON loading failed\n");
2022c593315Sopenharmony_ci    exit(EXIT_FAILURE);
2032c593315Sopenharmony_ci  }
2042c593315Sopenharmony_ci
2052c593315Sopenharmony_ci  auto cases = json_object_get(json, "cases");
2062c593315Sopenharmony_ci
2072c593315Sopenharmony_ci  if (cases == nullptr) {
2082c593315Sopenharmony_ci    fprintf(stderr, "Missing 'cases' key in root object\n");
2092c593315Sopenharmony_ci    exit(EXIT_FAILURE);
2102c593315Sopenharmony_ci  }
2112c593315Sopenharmony_ci
2122c593315Sopenharmony_ci  if (!json_is_array(cases)) {
2132c593315Sopenharmony_ci    fprintf(stderr, "'cases' must be JSON array\n");
2142c593315Sopenharmony_ci    exit(EXIT_FAILURE);
2152c593315Sopenharmony_ci  }
2162c593315Sopenharmony_ci
2172c593315Sopenharmony_ci  auto deflater = init_deflater();
2182c593315Sopenharmony_ci  output_json_header();
2192c593315Sopenharmony_ci  auto len = json_array_size(cases);
2202c593315Sopenharmony_ci
2212c593315Sopenharmony_ci  for (size_t i = 0; i < len; ++i) {
2222c593315Sopenharmony_ci    auto obj = json_array_get(cases, i);
2232c593315Sopenharmony_ci    if (!json_is_object(obj)) {
2242c593315Sopenharmony_ci      fprintf(stderr, "Unexpected JSON type at %zu. It should be object.\n", i);
2252c593315Sopenharmony_ci      continue;
2262c593315Sopenharmony_ci    }
2272c593315Sopenharmony_ci    if (deflate_hd_json(obj, deflater, i) != 0) {
2282c593315Sopenharmony_ci      continue;
2292c593315Sopenharmony_ci    }
2302c593315Sopenharmony_ci    if (i + 1 < len) {
2312c593315Sopenharmony_ci      printf(",\n");
2322c593315Sopenharmony_ci    }
2332c593315Sopenharmony_ci  }
2342c593315Sopenharmony_ci  output_json_footer();
2352c593315Sopenharmony_ci  deinit_deflater(deflater);
2362c593315Sopenharmony_ci  json_decref(json);
2372c593315Sopenharmony_ci  return 0;
2382c593315Sopenharmony_ci}
2392c593315Sopenharmony_ci
2402c593315Sopenharmony_cistatic int perform_from_http1text(void) {
2412c593315Sopenharmony_ci  char line[1 << 14];
2422c593315Sopenharmony_ci  int seq = 0;
2432c593315Sopenharmony_ci
2442c593315Sopenharmony_ci  auto deflater = init_deflater();
2452c593315Sopenharmony_ci  output_json_header();
2462c593315Sopenharmony_ci  for (;;) {
2472c593315Sopenharmony_ci    std::vector<nghttp2_nv> nva;
2482c593315Sopenharmony_ci    int end = 0;
2492c593315Sopenharmony_ci    size_t inputlen = 0;
2502c593315Sopenharmony_ci
2512c593315Sopenharmony_ci    for (;;) {
2522c593315Sopenharmony_ci      char *rv = fgets(line, sizeof(line), stdin);
2532c593315Sopenharmony_ci      char *val, *val_end;
2542c593315Sopenharmony_ci      if (rv == nullptr) {
2552c593315Sopenharmony_ci        end = 1;
2562c593315Sopenharmony_ci        break;
2572c593315Sopenharmony_ci      } else if (line[0] == '\n') {
2582c593315Sopenharmony_ci        break;
2592c593315Sopenharmony_ci      }
2602c593315Sopenharmony_ci
2612c593315Sopenharmony_ci      nva.emplace_back();
2622c593315Sopenharmony_ci      auto &nv = nva.back();
2632c593315Sopenharmony_ci
2642c593315Sopenharmony_ci      val = strchr(line + 1, ':');
2652c593315Sopenharmony_ci      if (val == nullptr) {
2662c593315Sopenharmony_ci        fprintf(stderr, "Bad HTTP/1 header field format at %d.\n", seq);
2672c593315Sopenharmony_ci        exit(EXIT_FAILURE);
2682c593315Sopenharmony_ci      }
2692c593315Sopenharmony_ci      *val = '\0';
2702c593315Sopenharmony_ci      ++val;
2712c593315Sopenharmony_ci      for (; *val && (*val == ' ' || *val == '\t'); ++val)
2722c593315Sopenharmony_ci        ;
2732c593315Sopenharmony_ci      for (val_end = val; *val_end && (*val_end != '\r' && *val_end != '\n');
2742c593315Sopenharmony_ci           ++val_end)
2752c593315Sopenharmony_ci        ;
2762c593315Sopenharmony_ci      *val_end = '\0';
2772c593315Sopenharmony_ci
2782c593315Sopenharmony_ci      nv.namelen = strlen(line);
2792c593315Sopenharmony_ci      nv.valuelen = strlen(val);
2802c593315Sopenharmony_ci      nv.name = (uint8_t *)strdup(line);
2812c593315Sopenharmony_ci      nv.value = (uint8_t *)strdup(val);
2822c593315Sopenharmony_ci      nv.flags = NGHTTP2_NV_FLAG_NONE;
2832c593315Sopenharmony_ci
2842c593315Sopenharmony_ci      inputlen += nv.namelen + nv.valuelen;
2852c593315Sopenharmony_ci    }
2862c593315Sopenharmony_ci
2872c593315Sopenharmony_ci    if (!end) {
2882c593315Sopenharmony_ci      if (seq > 0) {
2892c593315Sopenharmony_ci        printf(",\n");
2902c593315Sopenharmony_ci      }
2912c593315Sopenharmony_ci      deflate_hd(deflater, nva, inputlen, seq);
2922c593315Sopenharmony_ci    }
2932c593315Sopenharmony_ci
2942c593315Sopenharmony_ci    for (auto &nv : nva) {
2952c593315Sopenharmony_ci      free(nv.name);
2962c593315Sopenharmony_ci      free(nv.value);
2972c593315Sopenharmony_ci    }
2982c593315Sopenharmony_ci
2992c593315Sopenharmony_ci    if (end)
3002c593315Sopenharmony_ci      break;
3012c593315Sopenharmony_ci    ++seq;
3022c593315Sopenharmony_ci  }
3032c593315Sopenharmony_ci  output_json_footer();
3042c593315Sopenharmony_ci  deinit_deflater(deflater);
3052c593315Sopenharmony_ci  return 0;
3062c593315Sopenharmony_ci}
3072c593315Sopenharmony_ci
3082c593315Sopenharmony_cistatic void print_help(void) {
3092c593315Sopenharmony_ci  std::cout << R"(HPACK HTTP/2 header encoder
3102c593315Sopenharmony_ciUsage: deflatehd [OPTIONS] < INPUT
3112c593315Sopenharmony_ci
3122c593315Sopenharmony_ciReads JSON data  or HTTP/1-style header fields from  stdin and outputs
3132c593315Sopenharmony_cideflated header block in JSON array.
3142c593315Sopenharmony_ci
3152c593315Sopenharmony_ciFor the JSON  input, the root JSON object must  contain "context" key,
3162c593315Sopenharmony_ciwhich  indicates  which  compression  context   is  used.   If  it  is
3172c593315Sopenharmony_ci"request", request  compression context is used.   Otherwise, response
3182c593315Sopenharmony_cicompression context  is used.  The  value of "cases" key  contains the
3192c593315Sopenharmony_cisequence of input header set.  They share the same compression context
3202c593315Sopenharmony_ciand are processed in the order they appear.  Each item in the sequence
3212c593315Sopenharmony_ciis a JSON object  and it must have at least  "headers" key.  Its value
3222c593315Sopenharmony_ciis an array of a JSON object containing exactly one name/value pair.
3232c593315Sopenharmony_ci
3242c593315Sopenharmony_ciExample:
3252c593315Sopenharmony_ci{
3262c593315Sopenharmony_ci  "context": "request",
3272c593315Sopenharmony_ci  "cases":
3282c593315Sopenharmony_ci  [
3292c593315Sopenharmony_ci    {
3302c593315Sopenharmony_ci      "headers": [
3312c593315Sopenharmony_ci        { ":method": "GET" },
3322c593315Sopenharmony_ci        { ":path": "/" }
3332c593315Sopenharmony_ci      ]
3342c593315Sopenharmony_ci    },
3352c593315Sopenharmony_ci    {
3362c593315Sopenharmony_ci      "headers": [
3372c593315Sopenharmony_ci        { ":method": "POST" },
3382c593315Sopenharmony_ci        { ":path": "/" }
3392c593315Sopenharmony_ci      ]
3402c593315Sopenharmony_ci    }
3412c593315Sopenharmony_ci  ]
3422c593315Sopenharmony_ci}
3432c593315Sopenharmony_ci
3442c593315Sopenharmony_ciWith  -t option,  the program  can accept  more familiar  HTTP/1 style
3452c593315Sopenharmony_ciheader field  block.  Each header  set must  be followed by  one empty
3462c593315Sopenharmony_ciline:
3472c593315Sopenharmony_ci
3482c593315Sopenharmony_ciExample:
3492c593315Sopenharmony_ci
3502c593315Sopenharmony_ci:method: GET
3512c593315Sopenharmony_ci:scheme: https
3522c593315Sopenharmony_ci:path: /
3532c593315Sopenharmony_ci
3542c593315Sopenharmony_ci:method: POST
3552c593315Sopenharmony_ciuser-agent: nghttp2
3562c593315Sopenharmony_ci
3572c593315Sopenharmony_ciThe output of this program can be used as input for inflatehd.
3582c593315Sopenharmony_ci
3592c593315Sopenharmony_ciOPTIONS:
3602c593315Sopenharmony_ci    -t, --http1text   Use  HTTP/1 style  header field  text as  input.
3612c593315Sopenharmony_ci                      Each  header set  is delimited  by single  empty
3622c593315Sopenharmony_ci                      line.
3632c593315Sopenharmony_ci    -s, --table-size=<N>
3642c593315Sopenharmony_ci                      Set   dynamic   table   size.   In   the   HPACK
3652c593315Sopenharmony_ci                      specification,   this   value  is   denoted   by
3662c593315Sopenharmony_ci                      SETTINGS_HEADER_TABLE_SIZE.
3672c593315Sopenharmony_ci                      Default: 4096
3682c593315Sopenharmony_ci    -S, --deflate-table-size=<N>
3692c593315Sopenharmony_ci                      Use  first  N  bytes  of  dynamic  header  table
3702c593315Sopenharmony_ci                      buffer.
3712c593315Sopenharmony_ci                      Default: 4096
3722c593315Sopenharmony_ci    -d, --dump-header-table
3732c593315Sopenharmony_ci                      Output dynamic header table.)"
3742c593315Sopenharmony_ci            << std::endl;
3752c593315Sopenharmony_ci}
3762c593315Sopenharmony_ci
3772c593315Sopenharmony_ciconstexpr static struct option long_options[] = {
3782c593315Sopenharmony_ci    {"http1text", no_argument, nullptr, 't'},
3792c593315Sopenharmony_ci    {"table-size", required_argument, nullptr, 's'},
3802c593315Sopenharmony_ci    {"deflate-table-size", required_argument, nullptr, 'S'},
3812c593315Sopenharmony_ci    {"dump-header-table", no_argument, nullptr, 'd'},
3822c593315Sopenharmony_ci    {nullptr, 0, nullptr, 0}};
3832c593315Sopenharmony_ci
3842c593315Sopenharmony_ciint main(int argc, char **argv) {
3852c593315Sopenharmony_ci  config.table_size = 4_k;
3862c593315Sopenharmony_ci  config.deflate_table_size = 4_k;
3872c593315Sopenharmony_ci  config.http1text = 0;
3882c593315Sopenharmony_ci  config.dump_header_table = 0;
3892c593315Sopenharmony_ci  while (1) {
3902c593315Sopenharmony_ci    int option_index = 0;
3912c593315Sopenharmony_ci    int c = getopt_long(argc, argv, "S:dhs:t", long_options, &option_index);
3922c593315Sopenharmony_ci    if (c == -1) {
3932c593315Sopenharmony_ci      break;
3942c593315Sopenharmony_ci    }
3952c593315Sopenharmony_ci    switch (c) {
3962c593315Sopenharmony_ci    case 'h':
3972c593315Sopenharmony_ci      print_help();
3982c593315Sopenharmony_ci      exit(EXIT_SUCCESS);
3992c593315Sopenharmony_ci    case 't':
4002c593315Sopenharmony_ci      // --http1text
4012c593315Sopenharmony_ci      config.http1text = 1;
4022c593315Sopenharmony_ci      break;
4032c593315Sopenharmony_ci    case 's': {
4042c593315Sopenharmony_ci      // --table-size
4052c593315Sopenharmony_ci      auto n = util::parse_uint(optarg);
4062c593315Sopenharmony_ci      if (n == -1) {
4072c593315Sopenharmony_ci        fprintf(stderr, "-s: Bad option value\n");
4082c593315Sopenharmony_ci        exit(EXIT_FAILURE);
4092c593315Sopenharmony_ci      }
4102c593315Sopenharmony_ci      config.table_size = n;
4112c593315Sopenharmony_ci      break;
4122c593315Sopenharmony_ci    }
4132c593315Sopenharmony_ci    case 'S': {
4142c593315Sopenharmony_ci      // --deflate-table-size
4152c593315Sopenharmony_ci      auto n = util::parse_uint(optarg);
4162c593315Sopenharmony_ci      if (n == -1) {
4172c593315Sopenharmony_ci        fprintf(stderr, "-S: Bad option value\n");
4182c593315Sopenharmony_ci        exit(EXIT_FAILURE);
4192c593315Sopenharmony_ci      }
4202c593315Sopenharmony_ci      config.deflate_table_size = n;
4212c593315Sopenharmony_ci      break;
4222c593315Sopenharmony_ci    }
4232c593315Sopenharmony_ci    case 'd':
4242c593315Sopenharmony_ci      // --dump-header-table
4252c593315Sopenharmony_ci      config.dump_header_table = 1;
4262c593315Sopenharmony_ci      break;
4272c593315Sopenharmony_ci    case '?':
4282c593315Sopenharmony_ci      exit(EXIT_FAILURE);
4292c593315Sopenharmony_ci    default:
4302c593315Sopenharmony_ci      break;
4312c593315Sopenharmony_ci    }
4322c593315Sopenharmony_ci  }
4332c593315Sopenharmony_ci  if (config.http1text) {
4342c593315Sopenharmony_ci    perform_from_http1text();
4352c593315Sopenharmony_ci  } else {
4362c593315Sopenharmony_ci    perform();
4372c593315Sopenharmony_ci  }
4382c593315Sopenharmony_ci
4392c593315Sopenharmony_ci  auto comp_ratio = input_sum == 0 ? 0.0 : (double)output_sum / input_sum;
4402c593315Sopenharmony_ci
4412c593315Sopenharmony_ci  fprintf(stderr, "Overall: input=%zu output=%zu ratio=%.02f\n", input_sum,
4422c593315Sopenharmony_ci          output_sum, comp_ratio);
4432c593315Sopenharmony_ci  return 0;
4442c593315Sopenharmony_ci}
4452c593315Sopenharmony_ci
4462c593315Sopenharmony_ci} // namespace nghttp2
4472c593315Sopenharmony_ci
4482c593315Sopenharmony_ciint main(int argc, char **argv) {
4492c593315Sopenharmony_ci  return nghttp2::run_app(nghttp2::main, argc, argv);
4502c593315Sopenharmony_ci}
451