Class: Vivarium::HttpDecoder
- Inherits:
-
Object
- Object
- Vivarium::HttpDecoder
- Defined in:
- lib/vivarium/http_decoder.rb
Overview
Decodes payloads captured from OpenSSL ‘SSL_write` into a human-readable one-liner. Auto-detects HTTP/1.x request/response lines and HTTP/2 binary frames; HPACK-decompresses HEADERS / CONTINUATION when the `http-2` gem is available, otherwise reports frame types only.
HPACK decompressor state is kept per pid. This is sufficient for the common “one HTTPS connection per process” case; with multiple concurrent TLS connections per pid the HPACK table can diverge and decoding may fail — in that case the decompressor for that pid is reset on the next decode error.
Constant Summary collapse
- HTTP1_METHODS =
%w[GET POST PUT PATCH DELETE HEAD OPTIONS TRACE CONNECT].freeze
- HTTP2_PREFACE =
"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n".b
- H2_FRAME_HEADER_SIZE =
9- H2_FLAG_END_HEADERS =
0x04- H2_FLAG_PADDED =
0x08- H2_FLAG_PRIORITY =
0x20- FRAME_TYPE_NAMES =
{ 0x0 => "DATA", 0x1 => "HEADERS", 0x2 => "PRIORITY", 0x3 => "RST_STREAM", 0x4 => "SETTINGS", 0x5 => "PUSH_PROMISE", 0x6 => "PING", 0x7 => "GOAWAY", 0x8 => "WINDOW_UPDATE", 0x9 => "CONTINUATION" }.freeze
Instance Method Summary collapse
- #hpack_available? ⇒ Boolean
-
#initialize ⇒ HttpDecoder
constructor
A new instance of HttpDecoder.
- #render(pid:, data:, data_len:) ⇒ Object
Constructor Details
#initialize ⇒ HttpDecoder
Returns a new instance of HttpDecoder.
40 41 42 43 44 |
# File 'lib/vivarium/http_decoder.rb', line 40 def initialize @hpack_available = load_http2_gem @decompressors = {} @continuation = {} end |
Instance Method Details
#hpack_available? ⇒ Boolean
46 47 48 |
# File 'lib/vivarium/http_decoder.rb', line 46 def hpack_available? @hpack_available end |
#render(pid:, data:, data_len:) ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/vivarium/http_decoder.rb', line 50 def render(pid:, data:, data_len:) data = data.to_s.b data_len = data_len.to_i return "data_len=0" if data_len <= 0 return "len=#{data_len} <no-capture>" if data.empty? if (summary = http1_summary(data)) kind, line = summary return "http/1.x #{kind}: #{line}#{truncation_note(data, data_len)}" end rest = data preface_note = "" if rest.start_with?(HTTP2_PREFACE) preface_note = "preface " rest = rest.byteslice(HTTP2_PREFACE.bytesize..) || "".b end frames = parse_h2_frames(rest) if frames.empty? if !preface_note.empty? return "h2 preface only#{truncation_note(data, data_len)}" end return "binary len=#{data_len}#{truncation_note(data, data_len)}" end rendered = frames.map { |f| render_h2_frame(pid, f) }.join(" | ") "h2 #{preface_note}#{rendered}#{truncation_note(data, data_len)}" end |