🙌

【C 言語】nghttp2 で HPACK 形式に圧縮された HTTP/2 ヘッダーを復元する

2024/05/02に公開

今度は HPACk 形式に圧縮された HTTP/2 ヘッダーを復元する。執筆時のテスト環境は Debian 12 Bookworm、nghttp2 1.52.0 である。

024年3月にリリースされた nghttp2 1.6.0 で ssize_t の問題を解決するために nghttp2_ssize に対応した新しい API が導入された。後方互換性のために古い API はエイリアスとなっている。

test.c
#include <stdio.h>
#include <string.h>
#include <nghttp2/nghttp2.h>

static int inflate_header_block(
  nghttp2_hd_inflater *inflater,
  uint8_t *in,
  size_t inlen
);

int main(void) {
  ssize_t rv;
  nghttp2_hd_inflater *inflater;

  uint8_t *buf = "\x87\x41\x88\x2f\x91\xd3\x5d\x05\x5c\xf6\x4d\x84\x7a\x87\xa0\xd1\xd5\x34\xe9\x4d\x62\x90";
  size_t outlen = strlen(buf);

  rv = nghttp2_hd_inflate_new(&inflater);
  rv = inflate_header_block(inflater, buf, outlen);
  nghttp2_hd_inflate_del(inflater);

  return 0;
}

int inflate_header_block(
  nghttp2_hd_inflater *inflater,
  uint8_t *in,
  size_t inlen) {

  ssize_t rv;

  for (;;) {
    nghttp2_nv nv;
    int inflate_flags = 0;
    size_t proclen;

    rv = nghttp2_hd_inflate_hd(inflater, &nv, &inflate_flags, in, inlen, 1);
    proclen = (size_t)rv;

    in += proclen;
    inlen -= proclen;

    printf("proclen: %d inlen: %d\n",  proclen, inlen);

    if (inflate_flags & NGHTTP2_HD_INFLATE_EMIT) {
      fwrite(nv.name, 1, nv.namelen, stderr);
      fprintf(stderr, ": ");
      fwrite(nv.value, 1, nv.valuelen, stderr);
      fprintf(stderr, "\n");
    }

    if (inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
      nghttp2_hd_inflate_end_headers(inflater);
      break;
    }


    if ((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && inlen == 0) {
      break;
    }
  }

  return 0;
}

実行結果は次のとおり

zig run test.c -lc -lnghttp2
proclen: 1 inlen: 21
:scheme: https
proclen: 10 inlen: 11
:authority: example.org
proclen: 1 inlen: 10
:path: /
proclen: 9 inlen: 1
user-agent: libnghttp2
proclen: 1 inlen: 0
accept-encoding: gzip, deflate
proclen: 0 inlen: 0

Discussion