PcapFileEx.HTTP2 (pcap_file_ex v0.5.5)
View SourceHTTP/2 cleartext (h2c) stream reconstruction.
Parses HTTP/2 frames from TCP payloads and reconstructs complete request/response exchanges. Supports prior-knowledge h2c only (no HTTP/1.1 Upgrade flow).
Example
{:ok, complete, incomplete} = PcapFileEx.HTTP2.analyze("capture.pcap")
IO.puts("Complete: #{length(complete)}, Incomplete: #{length(incomplete)}")
Enum.each(complete, fn ex ->
IO.puts("#{ex.request.method} #{ex.request.path} -> #{ex.response.status}")
end)Limitations
- Cleartext only: No TLS-encrypted HTTP/2 (h2)
- Prior-knowledge h2c only: No HTTP/1.1 Upgrade flow support
- No server push: PUSH_PROMISE frames are ignored
- Analysis only: No playback server implementation
Mid-Connection Capture
When capturing starts after the HTTP/2 connection is established:
- Client identification falls back to stream ID semantics
- Some HPACK dynamic table entries may be missing (static table works)
- SETTINGS frames are deferred until client is identified
Summary
Functions
Analyzes a PCAP file and returns HTTP/2 exchanges.
Analyzes directional TCP segments directly.
Returns the HTTP/2 connection preface string.
Check if binary data starts with HTTP/2 connection preface.
Functions
@spec analyze( Path.t(), keyword() ) :: {:ok, [PcapFileEx.HTTP2.Exchange.t()], [PcapFileEx.HTTP2.IncompleteExchange.t()]} | {:error, term()}
Analyzes a PCAP file and returns HTTP/2 exchanges.
Returns {:ok, complete, incomplete} where:
complete- List of fully completed request/response exchangesincomplete- List of partial exchanges (RST, GOAWAY, truncated)
Options
:port- Filter to specific TCP port (default: nil, all ports):decode_content- Whentrue(default), automatically decodes request/response bodies based on Content-Type header. Multipart bodies are recursively decoded, JSON is parsed, and text is validated as UTF-8. Whenfalse, bodies remain as raw binaries anddecoded_bodyisnil.:hosts_map- Map of IP address strings to hostname strings for endpoint resolution.:decoders- List of custom decoder specs (seePcapFileEx.Flows.Decoder):keep_binary- Whentrue, preserve original binary in multipart parts'body_binaryfield when custom decoders are invoked (default:false)
Example
{:ok, complete, incomplete} = PcapFileEx.HTTP2.analyze("capture.pcap")
Enum.each(complete, fn ex ->
IO.puts("#{ex.request.method} #{ex.request.path} -> #{ex.response.status}")
end)
Enum.each(incomplete, fn ex ->
IO.puts("Incomplete: #{PcapFileEx.HTTP2.IncompleteExchange.to_string(ex)}")
end)
# With hosts mapping
hosts = %{"192.168.1.1" => "client", "10.0.0.1" => "server"}
{:ok, complete, _incomplete} = PcapFileEx.HTTP2.analyze("capture.pcap", hosts_map: hosts)
%{client: client, server: server} = hd(complete)
IO.puts("Request from #{client} to #{server}")
@spec analyze_segments( [PcapFileEx.HTTP2.Analyzer.directional_segment()], keyword() ) :: {:ok, [PcapFileEx.HTTP2.Exchange.t()], [PcapFileEx.HTTP2.IncompleteExchange.t()]}
Analyzes directional TCP segments directly.
Use this when you already have TCP-reassembled segments with direction information, skipping the PCAP parsing step.
Options
:decode_content- Whentrue(default), automatically decodes request/response bodies based on Content-Type header. Whenfalse, bodies remain as raw binaries.:hosts_map- Map of IP address strings to hostname strings for endpoint resolution.
Example
segments = [
%{flow_key: {client, server}, direction: :a_to_b, data: preface_bytes, timestamp: ts1},
%{flow_key: {client, server}, direction: :a_to_b, data: settings_frame, timestamp: ts2},
...
]
{:ok, complete, incomplete} = PcapFileEx.HTTP2.analyze_segments(segments)
# With hosts mapping
hosts = %{"192.168.1.1" => "client"}
{:ok, complete, _incomplete} = PcapFileEx.HTTP2.analyze_segments(segments, hosts_map: hosts)
@spec connection_preface() :: binary()
Returns the HTTP/2 connection preface string.
Check if binary data starts with HTTP/2 connection preface.
The connection preface is "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" (24 bytes).