// File: kztomita[P]http-dump/./http2_socket.h
// Function: void send_http2_headers<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0>>, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0>>, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0>>, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0>>, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0>>>>>>(boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0>>, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0>>, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0>>, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0>>, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0>>>>>&, unsigned int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, std::__cxx11::list<std::unique_ptr<http_header, std::default_delete<http_header>>, std::allocator<std::unique_ptr<http_header, std::default_delete<http_header>>>> const&, unsigned long)
void send_http2_headers(SyncWriteStream& stream,
                        uint32_t stream_id,
                        const std::string& host,
                        const std::string& path,
                        const http_header_list& req_headers,
                        std::size_t max_payload_len = 16384) {
  std::vector<hpack::header_type> header_array{
    {":method", "GET"},
    {":scheme", "https"},
    {":path", path},
    {":authority", host},
  };
  // XXX ヘッダーが多くても現状フラグメントは行っていない
  for (const auto& h : req_headers) {
    header_array.emplace_back(hpack::header_type{
        string_util::tolower(h->key),
        h->value});
  }

  // HPACK(rfc7541)形式でヘッダーを作成
  hpack::hpack_encoder encoder;
  auto header_block = encoder.encode<http2_frame::payload_type>(header_array);

  if (header_block.size() <= max_payload_len) {
    http2_frame headers;
    auto& header = headers.header();
    header.type = http2_frame_header::TYPE_HEADERS;
    header.flags = 0x05;         // END_HEADERS | END_STREAM
    header.set_stream_id(stream_id);

    headers.header().set_length(header_block.size());
    using std::swap;
    swap(headers.payload(), header_block);

    write_http2_frame(stream, headers);
  } else {
    // HEADERS AND CONTINUATION
    // nginx相手だとENHANCE YOUR CALMが返される
    {
      http2_frame headers;
      auto& header = headers.header();
      header.type = http2_frame_header::TYPE_HEADERS;
      header.flags = 0x01;         // END_STREAM
      header.set_stream_id(stream_id);

      headers.header().set_length(max_payload_len);
      std::copy(header_block.begin(),
                header_block.begin() + max_payload_len,
                std::back_inserter(headers.payload()));

      write_http2_frame(stream, headers);
    }

    std::size_t offset = max_payload_len;
    while (offset < header_block.size()) {
      auto left_bytes = header_block.size() - offset;
      auto len = std::min(left_bytes, max_payload_len);

      http2_frame continuation;
      auto& header = continuation.header();
      header.type = http2_frame_header::TYPE_CONTINUATION;
      header.flags = 0x00;
      if (len <= max_payload_len) {
        header.flags |= 0x04;       // END_HEADERS
      }
      header.set_stream_id(stream_id);

      continuation.header().set_length(len);
      auto start = header_block.begin() + offset;
      std::copy(start,
                start + len,
                std::back_inserter(continuation.payload()));

      write_http2_frame(stream, continuation);

      offset += len;
    }
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x3b0, %rsp            # imm = 0x3B0
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
movq %r9, -0x30(%rbp)
leaq -0x158(%rbp), %rdi
movq %rdi, -0x160(%rbp)
leaq 0x1b93e(%rip), %rsi     # 0x755d5
leaq 0x1b93f(%rip), %rdx     # 0x755dd
callq 0x5d4f0
jmp 0x59ca5
leaq -0x118(%rbp), %rdi
movq %rdi, -0x160(%rbp)
leaq 0x1b927(%rip), %rsi     # 0x755e1
leaq 0x194c1(%rip), %rdx     # 0x73182
callq 0x5d5d0
jmp 0x59cc8
leaq -0xd8(%rbp), %rdi
movq %rdi, -0x160(%rbp)
movq -0x20(%rbp), %rdx
leaq 0x1b908(%rip), %rsi     # 0x755e9
callq 0x5d6b0
jmp 0x59ce8
leaq -0x98(%rbp), %rdi
movq %rdi, -0x160(%rbp)
movq -0x18(%rbp), %rdx
leaq 0x1b8ee(%rip), %rsi     # 0x755ef
callq 0x5d750
jmp 0x59d08
leaq -0x158(%rbp), %rax
movq %rax, -0x58(%rbp)
movq $0x4, -0x50(%rbp)
leaq -0x16d(%rbp), %rdi
movq %rdi, -0x318(%rbp)
callq 0x38de0
movq -0x318(%rbp), %rcx
movq -0x58(%rbp), %rsi
movq -0x50(%rbp), %rdx
leaq -0x48(%rbp), %rdi
callq 0x5d7f0
jmp 0x59d48
leaq -0x16d(%rbp), %rdi
callq 0x3a3c0
leaq -0x158(%rbp), %rax
movq %rax, -0x328(%rbp)
addq $0x100, %rax            # imm = 0x100
movq %rax, -0x320(%rbp)
movq -0x320(%rbp), %rdi
addq $-0x40, %rdi
movq %rdi, -0x330(%rbp)
callq 0x38f50
movq -0x328(%rbp), %rcx
movq -0x330(%rbp), %rax
cmpq %rcx, %rax
movq %rax, -0x320(%rbp)
jne 0x59d6f
movq -0x28(%rbp), %rax
movq %rax, -0x178(%rbp)
movq -0x178(%rbp), %rdi
callq 0x4ed60
movq %rax, -0x180(%rbp)
movq -0x178(%rbp), %rdi
callq 0x4ed90
movq %rax, -0x188(%rbp)
leaq -0x180(%rbp), %rdi
leaq -0x188(%rbp), %rsi
callq 0x4edc0
testb $0x1, %al
jne 0x59ded
jmp 0x59fab
leaq -0x180(%rbp), %rdi
callq 0x4edf0
movq %rax, -0x190(%rbp)
movq -0x190(%rbp), %rdi
callq 0x4ee20
movq %rax, %rsi
leaq -0x1f0(%rbp), %rdi
callq 0x531c0
jmp 0x59e1d
movq -0x190(%rbp), %rdi
callq 0x4ee20
movq %rax, %rdx
addq $0x20, %rdx
leaq -0x1d0(%rbp), %rdi
leaq -0x1f0(%rbp), %rsi
callq 0x5d870
jmp 0x59e45
leaq -0x48(%rbp), %rdi
leaq -0x1d0(%rbp), %rsi
callq 0x3fb30
jmp 0x59e57
leaq -0x1d0(%rbp), %rdi
callq 0x38f50
leaq -0x1f0(%rbp), %rdi
callq 0xdac0
leaq -0x180(%rbp), %rdi
callq 0x4ee40
jmp 0x59dd1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x168(%rbp)
movl %eax, -0x16c(%rbp)
movq -0x160(%rbp), %rax
leaq -0x158(%rbp), %rcx
cmpq %rax, %rcx
movq %rax, -0x338(%rbp)
je 0x59edd
movq -0x338(%rbp), %rdi
addq $-0x40, %rdi
movq %rdi, -0x340(%rbp)
callq 0x38f50
movq -0x340(%rbp), %rax
leaq -0x158(%rbp), %rcx
cmpq %rcx, %rax
movq %rax, -0x338(%rbp)
jne 0x59eac
jmp 0x5a431
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x168(%rbp)
movl %eax, -0x16c(%rbp)
leaq -0x16d(%rbp), %rdi
callq 0x3a3c0
leaq -0x158(%rbp), %rax
movq %rax, -0x350(%rbp)
addq $0x100, %rax            # imm = 0x100
movq %rax, -0x348(%rbp)
movq -0x348(%rbp), %rdi
addq $-0x40, %rdi
movq %rdi, -0x358(%rbp)
callq 0x38f50
movq -0x350(%rbp), %rcx
movq -0x358(%rbp), %rax
cmpq %rcx, %rax
movq %rax, -0x348(%rbp)
jne 0x59f1b
jmp 0x5a431
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x168(%rbp)
movl %eax, -0x16c(%rbp)
jmp 0x5a428
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x168(%rbp)
movl %eax, -0x16c(%rbp)
jmp 0x59f9a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x168(%rbp)
movl %eax, -0x16c(%rbp)
leaq -0x1d0(%rbp), %rdi
callq 0x38f50
leaq -0x1f0(%rbp), %rdi
callq 0xdac0
jmp 0x5a428
leaq -0x210(%rbp), %rdi
leaq -0x1f1(%rbp), %rsi
leaq -0x48(%rbp), %rdx
callq 0x5d8d0
jmp 0x59fc4
leaq -0x210(%rbp), %rdi
callq 0x4e6b0
cmpq -0x30(%rbp), %rax
ja 0x5a0be
leaq -0x238(%rbp), %rdi
movq %rdi, -0x360(%rbp)
callq 0x5c510
movq -0x360(%rbp), %rdi
callq 0x5c530
movq %rax, -0x240(%rbp)
movq -0x240(%rbp), %rax
movb $0x1, 0x3(%rax)
movq -0x240(%rbp), %rax
movb $0x5, 0x4(%rax)
movq -0x240(%rbp), %rdi
movl -0xc(%rbp), %esi
callq 0x5c540
jmp 0x5a027
leaq -0x238(%rbp), %rdi
callq 0x5c530
movq %rax, -0x368(%rbp)
leaq -0x210(%rbp), %rdi
callq 0x4e6b0
movq -0x368(%rbp), %rdi
movl %eax, %esi
callq 0x5c6c0
jmp 0x5a056
leaq -0x238(%rbp), %rdi
movq %rdi, -0x370(%rbp)
callq 0x5a440
movq %rax, %rdi
leaq -0x210(%rbp), %rsi
callq 0x536d0
movq -0x370(%rbp), %rsi
movq -0x8(%rbp), %rdi
callq 0x5c770
jmp 0x5a08a
leaq -0x238(%rbp), %rdi
callq 0x59c40
jmp 0x5a3fe
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x168(%rbp)
movl %eax, -0x16c(%rbp)
leaq -0x238(%rbp), %rdi
callq 0x59c40
jmp 0x5a41c
leaq -0x268(%rbp), %rdi
movq %rdi, -0x378(%rbp)
callq 0x5c510
movq -0x378(%rbp), %rdi
callq 0x5c530
movq %rax, -0x270(%rbp)
movq -0x270(%rbp), %rax
movb $0x1, 0x3(%rax)
movq -0x270(%rbp), %rax
movb $0x1, 0x4(%rax)
movq -0x270(%rbp), %rdi
movl -0xc(%rbp), %esi
callq 0x5c540
jmp 0x5a10b
leaq -0x268(%rbp), %rdi
callq 0x5c530
movq %rax, %rdi
movl -0x30(%rbp), %esi
callq 0x5c6c0
jmp 0x5a124
leaq -0x210(%rbp), %rdi
movq %rdi, -0x388(%rbp)
callq 0x5a570
movq -0x388(%rbp), %rdi
movq %rax, -0x278(%rbp)
callq 0x5a570
movq %rax, -0x288(%rbp)
movq -0x30(%rbp), %rsi
leaq -0x288(%rbp), %rdi
callq 0x57db0
movq %rax, -0x280(%rbp)
leaq -0x268(%rbp), %rdi
callq 0x5a440
movq %rax, %rdi
callq 0x5db40
movq %rax, -0x380(%rbp)
jmp 0x5a185
movq -0x380(%rbp), %rax
movq %rax, -0x290(%rbp)
movq -0x278(%rbp), %rdi
movq -0x280(%rbp), %rsi
movq -0x290(%rbp), %rdx
callq 0x5dad0
movq %rax, -0x390(%rbp)
jmp 0x5a1b6
movq -0x390(%rbp), %rax
movq %rax, -0x298(%rbp)
movq -0x8(%rbp), %rdi
leaq -0x268(%rbp), %rsi
callq 0x5c770
jmp 0x5a1d6
leaq -0x268(%rbp), %rdi
callq 0x59c40
movq -0x30(%rbp), %rax
movq %rax, -0x2a0(%rbp)
movq -0x2a0(%rbp), %rax
movq %rax, -0x398(%rbp)
leaq -0x210(%rbp), %rdi
callq 0x4e6b0
movq %rax, %rcx
movq -0x398(%rbp), %rax
cmpq %rcx, %rax
jae 0x5a3fc
leaq -0x210(%rbp), %rdi
callq 0x4e6b0
subq -0x2a0(%rbp), %rax
movq %rax, -0x2a8(%rbp)
leaq -0x2a8(%rbp), %rdi
leaq -0x30(%rbp), %rsi
callq 0x23c50
movq (%rax), %rax
movq %rax, -0x2b0(%rbp)
leaq -0x2d8(%rbp), %rdi
callq 0x5c510
leaq -0x2d8(%rbp), %rdi
callq 0x5c530
movq %rax, -0x2e0(%rbp)
movq -0x2e0(%rbp), %rax
movb $0x9, 0x3(%rax)
movq -0x2e0(%rbp), %rax
movb $0x0, 0x4(%rax)
movq -0x2b0(%rbp), %rax
cmpq -0x30(%rbp), %rax
ja 0x5a2c6
movq -0x2e0(%rbp), %rax
movzbl 0x4(%rax), %ecx
orl $0x4, %ecx
movb %cl, 0x4(%rax)
jmp 0x5a2c6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x168(%rbp)
movl %eax, -0x16c(%rbp)
leaq -0x268(%rbp), %rdi
callq 0x59c40
jmp 0x5a41c
movq -0x2e0(%rbp), %rdi
movl -0xc(%rbp), %esi
callq 0x5c540
jmp 0x5a2d7
leaq -0x2d8(%rbp), %rdi
callq 0x5c530
movq %rax, %rdi
movl -0x2b0(%rbp), %esi
callq 0x5c6c0
jmp 0x5a2f3
leaq -0x210(%rbp), %rdi
callq 0x5a570
movq %rax, -0x2f0(%rbp)
movq -0x2a0(%rbp), %rsi
leaq -0x2f0(%rbp), %rdi
callq 0x57db0
movq %rax, -0x2e8(%rbp)
movq -0x2e8(%rbp), %rax
movq %rax, -0x2f8(%rbp)
movq -0x2b0(%rbp), %rsi
leaq -0x2e8(%rbp), %rdi
callq 0x57db0
movq %rax, -0x300(%rbp)
leaq -0x2d8(%rbp), %rdi
callq 0x5a440
movq %rax, %rdi
callq 0x5db40
movq %rax, -0x3a0(%rbp)
jmp 0x5a365
movq -0x3a0(%rbp), %rax
movq %rax, -0x308(%rbp)
movq -0x2f8(%rbp), %rdi
movq -0x300(%rbp), %rsi
movq -0x308(%rbp), %rdx
callq 0x5dad0
movq %rax, -0x3a8(%rbp)
jmp 0x5a396
movq -0x3a8(%rbp), %rax
movq %rax, -0x310(%rbp)
movq -0x8(%rbp), %rdi
leaq -0x2d8(%rbp), %rsi
callq 0x5c770
jmp 0x5a3b6
movq -0x2b0(%rbp), %rax
addq -0x2a0(%rbp), %rax
movq %rax, -0x2a0(%rbp)
leaq -0x2d8(%rbp), %rdi
callq 0x59c40
jmp 0x5a1ed
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x168(%rbp)
movl %eax, -0x16c(%rbp)
leaq -0x2d8(%rbp), %rdi
callq 0x59c40
jmp 0x5a41c
jmp 0x5a3fe
leaq -0x210(%rbp), %rdi
callq 0x18ac0
leaq -0x48(%rbp), %rdi
callq 0x38d30
addq $0x3b0, %rsp            # imm = 0x3B0
popq %rbp
retq
leaq -0x210(%rbp), %rdi
callq 0x18ac0
leaq -0x48(%rbp), %rdi
callq 0x38d30
movq -0x168(%rbp), %rdi
callq 0xd990
nopl (%rax)