Documentation
¶
Index ¶
- Variables
- func ApplyRawQueryModifications(query string, remove []string, set []string) string
- func CheckLineEndings(raw []byte) string
- func Compress(data []byte, encoding string) ([]byte, error)
- func ContainsHeader(entries []string, name string) bool
- func Decompress(data []byte, encoding string) ([]byte, bool)
- func EncodeStandardChunkedBody(buf *bytes.Buffer, body, trailers []byte)
- func ExtractMethod(raw []byte) string
- func FilterSupportedEncodings(acceptEncoding string) string
- func NormalizeEncoding(encoding string) (string, bool)
- func ParseAuthority(authority, scheme string) (string, int)
- func ParseRequestLine(line []byte) (method, path, query, version string, err error)
- func PathWithoutQuery(p string) string
- type CaptureFilter
- type CertManager
- type ChunkFrame
- type H2RequestData
- type H2ResponseData
- type Header
- type HeaderGroup
- type Headers
- type HistoryEntry
- func (e *HistoryEntry) FormatRequest(buf *bytes.Buffer) []byte
- func (e *HistoryEntry) FormatResponse(buf *bytes.Buffer) []byte
- func (e *HistoryEntry) GetHost() string
- func (e *HistoryEntry) GetMethod() string
- func (e *HistoryEntry) GetPath() string
- func (e *HistoryEntry) GetRequestHeader(name string) string
- func (e *HistoryEntry) GetResponseHeader(name string) string
- func (e *HistoryEntry) GetStatusCode() int
- type HistoryMeta
- type HistoryStore
- func (h *HistoryStore) Close()
- func (h *HistoryStore) Count() int
- func (h *HistoryStore) Get(offset uint32) (*HistoryEntry, bool)
- func (h *HistoryStore) GetMeta(offset uint32) (*HistoryMeta, bool)
- func (h *HistoryStore) List(count int, startOffset uint32) []*HistoryEntry
- func (h *HistoryStore) ListMeta(count int, startOffset uint32) []HistoryMeta
- func (h *HistoryStore) SetCaptureFilter(f CaptureFilter)
- func (h *HistoryStore) ShouldCapture(entry *HistoryEntry) bool
- func (h *HistoryStore) Store(entry *HistoryEntry) uint32
- func (h *HistoryStore) Update(entry *HistoryEntry)
- type InterceptedResponse
- type JSONModifier
- type LineEnding
- type Modifications
- type ProxyServer
- func (s *ProxyServer) Addr() string
- func (s *ProxyServer) CertManager() *CertManager
- func (s *ProxyServer) History() *HistoryStore
- func (s *ProxyServer) Serve() error
- func (s *ProxyServer) SetCaptureFilter(f CaptureFilter)
- func (s *ProxyServer) SetResponseInterceptor(interceptor ResponseInterceptor)
- func (s *ProxyServer) SetRuleApplier(applier RuleApplier)
- func (s *ProxyServer) Shutdown(ctx context.Context) error
- func (s *ProxyServer) WaitReady(ctx context.Context) error
- type RawHTTP1Request
- type RawHTTP1Response
- func (r *RawHTTP1Response) GetHeader(name string) string
- func (r *RawHTTP1Response) RemoveHeader(name string)
- func (r *RawHTTP1Response) SerializeHeaders(buf *bytes.Buffer) []byte
- func (r *RawHTTP1Response) SerializeRaw(buf *bytes.Buffer) []byte
- func (r *RawHTTP1Response) SetBody(b []byte)
- func (r *RawHTTP1Response) SetHeader(name, value string)
- type ResponseInterceptor
- type RuleApplier
- type SendOptions
- type SendResult
- type Sender
- type Target
- type TimeoutConfig
- type WSFrame
- type WireFormat
Constants ¶
This section is empty.
Variables ¶
Functions ¶
func ApplyRawQueryModifications ¶ added in v0.1.6
ApplyRawQueryModifications applies set and remove operations to a raw query string without parsing/re-encoding, preserving parameter order and percent-encoding.
func CheckLineEndings ¶
CheckLineEndings detects line ending issues in HTTP headers. Returns a description of the issue, or empty string if OK.
func Compress ¶
Compress compresses data with the specified encoding. Returns (compressed data, error). Unknown encodings return the original data unchanged.
Handles the same normalization as Decompress for consistency.
func ContainsHeader ¶ added in v0.1.6
ContainsHeader checks if any "Name: Value" entry matches the given header name (case-insensitive).
func Decompress ¶
Decompress decompresses data based on Content-Encoding. Returns (decompressed data, wasCompressed). If wasCompressed is true but returned data is nil, decompression failed. Unknown encodings return (original data, false).
Handles: - Case variations: "GZIP", "Gzip" normalized to "gzip" - Whitespace: " gzip " trimmed - x-gzip alias: treated as gzip - deflate: tries raw DEFLATE first, then zlib-wrapped - br: Brotli decompression - zstd: Zstandard decompression - Multiple encodings (e.g., "gzip, br"): skipped (can't partially decode)
func EncodeStandardChunkedBody ¶ added in v0.1.13
EncodeStandardChunkedBody writes body + trailers into buf as an HTTP/1.1 chunked body using CRLF terminators. trailers is written verbatim after the 0-chunk.
func ExtractMethod ¶ added in v0.1.6
ExtractMethod extracts the HTTP method from raw request bytes. Returns the first space-delimited token from the request line. Handles both CRLF and bare-LF line endings. Defaults to "GET" for empty input or lines without a space.
func FilterSupportedEncodings ¶ added in v0.1.12
FilterSupportedEncodings filters an Accept-Encoding header value to only include encodings the proxy can decompress/recompress. Preserves quality values and ordering. Falls back to all supported encodings when the input contains no encoding supported by the proxy.
func NormalizeEncoding ¶
NormalizeEncoding normalizes a Content-Encoding header value. Returns the normalized encoding and whether it's a single supported encoding. Multiple encodings (e.g., "gzip, br") return ("", false) since we can't partially decode.
func ParseAuthority ¶ added in v0.1.11
ParseAuthority extracts host and port from an HTTP/2 :authority pseudo-header. Handles forms like "example.com", "example.com:8443", "[::1]:8080". scheme is used to determine default port ("https" -> 443, else 80).
func ParseRequestLine ¶
ParseRequestLine extracts method, path, query, version from request line. Accepts malformed lines if method and path are extractable.
func PathWithoutQuery ¶
PathWithoutQuery returns the path portion before any query string.
Types ¶
type CaptureFilter ¶ added in v0.1.6
type CaptureFilter func(entry *HistoryEntry) bool
CaptureFilter decides whether a history entry should be stored. Returns true if the entry should be captured, false to discard.
type CertManager ¶
type CertManager struct {
// contains filtered or unexported fields
}
CertManager handles CA certificate loading/generation and on-demand certificate generation for HTTPS MITM interception.
func (*CertManager) CACert ¶
func (m *CertManager) CACert() *x509.Certificate
CACert returns the CA certificate for clients to trust.
func (*CertManager) Close ¶
func (m *CertManager) Close() error
Close releases resources held by the cert cache.
func (*CertManager) GetCertificate ¶
func (m *CertManager) GetCertificate(hostname string) (*tls.Certificate, error)
GetCertificate returns a certificate for the hostname. Generates and caches if not already cached.
type ChunkFrame ¶ added in v0.1.13
type ChunkFrame struct {
// SizeLine is the raw size line without terminator, preserving extensions (e.g. "4;foo=bar") and hex casing.
SizeLine []byte `json:"size_line,omitempty" msgpack:"sl,omitempty"`
// SizeEnding is the terminator after the size line.
SizeEnding LineEnding `json:"size_ending,omitempty" msgpack:"se,omitempty"`
// Size is the chunk payload length in bytes (0 for final terminator chunk).
Size int `json:"size,omitempty" msgpack:"sz,omitempty"`
// DataEnding is the terminator after the chunk data. On the final 0-chunk it
// is the trailer block's closing blank-line terminator, or EndingNone if truncated.
DataEnding LineEnding `json:"data_ending,omitempty" msgpack:"de,omitempty"`
// Malformed marks the trailing frame after a bad hex size; SizeLine holds
// the raw bytes verbatim and the parser does not read past it.
Malformed bool `json:"malformed,omitempty" msgpack:"mf,omitempty"`
}
ChunkFrame preserves per-chunk wire framing for chunked messages. Invariant: non-final Size values sum to len(Body); the final frame has Size=0.
type H2RequestData ¶
type H2RequestData struct {
// Pseudo-headers
Method string `json:"method" msgpack:"m"` // from :method
Scheme string `json:"scheme" msgpack:"s"` // from :scheme
Authority string `json:"authority" msgpack:"a"` // from :authority
Path string `json:"path" msgpack:"p"` // from :path
// Regular headers (not pseudo-headers)
Headers Headers `json:"headers" msgpack:"h"`
// Body is the request body
Body []byte `json:"body,omitempty" msgpack:"b,omitempty"`
}
H2RequestData represents an HTTP/2 request for history storage.
func (*H2RequestData) GetHeader ¶
func (r *H2RequestData) GetHeader(name string) string
GetHeader returns the first header value with the given name (case-insensitive).
func (*H2RequestData) SetHeader ¶
func (r *H2RequestData) SetHeader(name, value string)
SetHeader sets or replaces the first header with the given name (case-insensitive).
type H2ResponseData ¶
type H2ResponseData struct {
// StatusCode from :status pseudo-header
StatusCode int `json:"status_code" msgpack:"sc"`
// Regular headers (not pseudo-headers)
Headers Headers `json:"headers" msgpack:"h"`
// Body is the response body
Body []byte `json:"body,omitempty" msgpack:"b,omitempty"`
}
H2ResponseData represents an HTTP/2 response for history storage.
func (*H2ResponseData) GetHeader ¶
func (r *H2ResponseData) GetHeader(name string) string
GetHeader returns the first header value with the given name (case-insensitive).
func (*H2ResponseData) SetHeader ¶
func (r *H2ResponseData) SetHeader(name, value string)
SetHeader sets or replaces the first header with the given name (case-insensitive).
type Header ¶
type Header struct {
// Name preserves original casing and whitespace anomalies
// (e.g., "Content-Type", "content-type", or "Header " with trailing space)
Name string `json:"name" msgpack:"n"`
// Value is the header value with leading/trailing whitespace trimmed
Value string `json:"value" msgpack:"v"`
// RawLine contains the original wire bytes for this header (excluding line ending).
// Used by SerializeRaw() to preserve exact wire format including obs-fold.
// nil when header was programmatically created or Wire format not tracked.
RawLine []byte `json:"raw_line,omitempty" msgpack:"rl,omitempty"`
// LineEnding is the terminator observed for this header's final physical line.
LineEnding LineEnding `json:"line_ending,omitempty" msgpack:"le,omitempty"`
}
Header represents a single HTTP header preserving original formatting.
type HeaderGroup ¶ added in v0.1.6
type HeaderGroup struct {
Key string // lowercase header name
Entries []string // original "Name: Value" strings
}
HeaderGroup represents headers sharing the same name (case-insensitive).
func GroupHeaderEntries ¶ added in v0.1.6
func GroupHeaderEntries(entries []string) []HeaderGroup
GroupHeaderEntries groups "Name: Value" strings by header name (case-insensitive), preserving insertion order.
type Headers ¶
type Headers []Header
Headers is a slice of Header with helper methods for case-insensitive access. JSON serializes as an array, same as []Header.
func (*Headers) Get ¶
Get returns the first header value with the given name (case-insensitive). Returns empty string if not found.
type HistoryEntry ¶
type HistoryEntry struct {
// Offset is the monotonic history index
Offset uint32 `json:"offset" msgpack:"o"`
// Protocol identifies the HTTP version: "http/1.1", "h2", or "websocket"
Protocol string `json:"protocol" msgpack:"pr"`
// HTTP/1.1 request/response (nil for HTTP/2)
Request *RawHTTP1Request `json:"request,omitempty" msgpack:"rq,omitempty"`
Response *RawHTTP1Response `json:"response,omitempty" msgpack:"rs,omitempty"`
// HTTP/2 request/response (nil for HTTP/1.1)
H2Request *H2RequestData `json:"h2_request,omitempty" msgpack:"h2q,omitempty"`
H2Response *H2ResponseData `json:"h2_response,omitempty" msgpack:"h2r,omitempty"`
H2StreamID uint32 `json:"h2_stream_id,omitempty" msgpack:"h2s,omitempty"` // for debugging/correlation
// WSFrames contains WebSocket frames for Protocol="websocket" entries.
// The handshake is stored in Request/Response; frames are appended here.
WSFrames []WSFrame `json:"ws_frames,omitempty" msgpack:"ws,omitempty"`
// Timing metadata
Timestamp time.Time `json:"timestamp" msgpack:"ts"`
Duration time.Duration `json:"duration" msgpack:"d"`
}
HistoryEntry represents a stored request/response pair. Embeds the parsed types directly for memory efficiency. The SerializeRaw() methods on Request/Response reconstruct wire bytes on demand.
func (*HistoryEntry) FormatRequest ¶
func (e *HistoryEntry) FormatRequest(buf *bytes.Buffer) []byte
FormatRequest returns the request in wire-compatible format. For HTTP/1.1, uses SerializeRaw to preserve anomalies like bare-LF. For HTTP/2, builds a similar text format from pseudo-headers and headers.
func (*HistoryEntry) FormatResponse ¶
func (e *HistoryEntry) FormatResponse(buf *bytes.Buffer) []byte
FormatResponse returns the response in wire-compatible format. For HTTP/1.1, uses SerializeRaw to preserve anomalies like bare-LF. For HTTP/2, builds a similar text format from pseudo-headers and headers.
func (*HistoryEntry) GetHost ¶
func (e *HistoryEntry) GetHost() string
GetHost returns the host for any protocol.
func (*HistoryEntry) GetMethod ¶
func (e *HistoryEntry) GetMethod() string
GetMethod returns the request method for any protocol.
func (*HistoryEntry) GetPath ¶
func (e *HistoryEntry) GetPath() string
GetPath returns the URL path without query string for any protocol. For H2, strips the query portion since :path includes it.
func (*HistoryEntry) GetRequestHeader ¶
func (e *HistoryEntry) GetRequestHeader(name string) string
GetRequestHeader returns a request header value (case-insensitive).
func (*HistoryEntry) GetResponseHeader ¶
func (e *HistoryEntry) GetResponseHeader(name string) string
GetResponseHeader returns a response header value (case-insensitive).
func (*HistoryEntry) GetStatusCode ¶
func (e *HistoryEntry) GetStatusCode() int
GetStatusCode returns the response status code for any protocol.
type HistoryMeta ¶
type HistoryMeta struct {
Offset uint32 `msgpack:"o"`
Protocol string `msgpack:"pr"`
Method string `msgpack:"m"`
Host string `msgpack:"h"`
Path string `msgpack:"p"` // includes query string
Status int `msgpack:"s"`
ContentType string `msgpack:"ct"`
RespLen int `msgpack:"rl"`
H2StreamID uint32 `msgpack:"h2,omitempty"`
Timestamp time.Time `msgpack:"ts"`
Duration time.Duration `msgpack:"d"`
}
HistoryMeta holds lightweight metadata extracted at store time. Used by summary/list paths to avoid deserializing full request/response bodies.
type HistoryStore ¶
type HistoryStore struct {
// contains filtered or unexported fields
}
HistoryStore provides typed access to proxy history backed by store.Storage.
func (*HistoryStore) Count ¶
func (h *HistoryStore) Count() int
Count returns total number of entries.
func (*HistoryStore) Get ¶
func (h *HistoryStore) Get(offset uint32) (*HistoryEntry, bool)
Get retrieves an entry by offset.
func (*HistoryStore) GetMeta ¶
func (h *HistoryStore) GetMeta(offset uint32) (*HistoryMeta, bool)
GetMeta retrieves lightweight metadata for an entry by offset.
func (*HistoryStore) List ¶
func (h *HistoryStore) List(count int, startOffset uint32) []*HistoryEntry
List returns entries starting from startOffset, up to count. Returns entries in offset order.
func (*HistoryStore) ListMeta ¶
func (h *HistoryStore) ListMeta(count int, startOffset uint32) []HistoryMeta
ListMeta returns metadata for entries starting from startOffset, up to count. Only deserializes lightweight metadata, skipping full request/response bodies.
func (*HistoryStore) SetCaptureFilter ¶ added in v0.1.6
func (h *HistoryStore) SetCaptureFilter(f CaptureFilter)
SetCaptureFilter sets the filter checked by ShouldCapture. Callers of Store are responsible for checking ShouldCapture first.
func (*HistoryStore) ShouldCapture ¶ added in v0.1.6
func (h *HistoryStore) ShouldCapture(entry *HistoryEntry) bool
ShouldCapture returns true if the entry passes the capture filter, or true when no filter is configured.
func (*HistoryStore) Store ¶
func (h *HistoryStore) Store(entry *HistoryEntry) uint32
Store adds an entry and assigns the next offset. Returns the assigned offset.
func (*HistoryStore) Update ¶
func (h *HistoryStore) Update(entry *HistoryEntry)
Update persists changes to an existing entry. The entry must have been previously stored (Offset must be valid).
type InterceptedResponse ¶ added in v0.1.11
InterceptedResponse is a canned response to serve for an intercepted request.
type JSONModifier ¶
JSONModifier modifies JSON body with set/remove operations. Provided by service layer to avoid circular imports.
type LineEnding ¶ added in v0.1.13
type LineEnding uint8
LineEnding identifies the terminator used on a single HTTP line. Zero value is EndingCRLF so unset fields emit the HTTP default.
const ( EndingCRLF LineEnding = 0 // "\r\n" EndingBareLF LineEnding = 1 // "\n" EndingBareCR LineEnding = 2 // "\r" - HTTP desync vector EndingNone LineEnding = 3 // no terminator observed (EOF / truncation) )
func (LineEnding) Bytes ¶ added in v0.1.13
func (e LineEnding) Bytes() string
Bytes returns the wire terminator for this line ending.
type Modifications ¶
type Modifications struct {
Method string // Override HTTP method
SetHeaders []string // "Name: Value" format; duplicates supported
RemoveHeaders []string // Remove headers by name
Body []byte // Replace entire body (mutually exclusive with JSON mods)
SetJSON map[string]any // Modify JSON fields
RemoveJSON []string // Remove JSON fields
SetParams map[string]string // Set query parameters
RemoveParams []string // Remove query parameters
}
Modifications specifies changes to apply to a request.
type ProxyServer ¶
type ProxyServer struct {
// contains filtered or unexported fields
}
ProxyServer is an HTTP proxy server that captures request/response pairs.
func NewProxyServer ¶
func NewProxyServer(port int, configDir string, maxBodyBytes int, historyStorage store.Storage, timeouts TimeoutConfig) (*ProxyServer, error)
NewProxyServer creates a new proxy server with HTTPS MITM support. configDir is the directory for CA certificates (e.g., ~/.sectool). maxBodyBytes limits request and response body sizes stored in history. historyStorage is the storage backend for proxy history entries.
func (*ProxyServer) Addr ¶
func (s *ProxyServer) Addr() string
Addr returns the proxy listener address (e.g., "127.0.0.1:12345").
func (*ProxyServer) CertManager ¶
func (s *ProxyServer) CertManager() *CertManager
CertManager returns the certificate manager for external access.
func (*ProxyServer) History ¶
func (s *ProxyServer) History() *HistoryStore
History returns the history store for external access.
func (*ProxyServer) Serve ¶
func (s *ProxyServer) Serve() error
Serve starts accepting connections. Blocks until shutdown.
func (*ProxyServer) SetCaptureFilter ¶ added in v0.1.6
func (s *ProxyServer) SetCaptureFilter(f CaptureFilter)
SetCaptureFilter sets the capture filter for the proxy history. Entries rejected by the filter are still proxied but not stored.
func (*ProxyServer) SetResponseInterceptor ¶ added in v0.1.11
func (s *ProxyServer) SetResponseInterceptor(interceptor ResponseInterceptor)
SetResponseInterceptor sets the response interceptor for HTTP handlers. Call after construction but before Serve().
func (*ProxyServer) SetRuleApplier ¶
func (s *ProxyServer) SetRuleApplier(applier RuleApplier)
SetRuleApplier sets the rule applier for all handlers. Call after construction but before Serve().
type RawHTTP1Request ¶
type RawHTTP1Request struct {
// Request line components
Method string `json:"method" msgpack:"m"` // "GET", "POST", etc.
Path string `json:"path" msgpack:"p"` // path without query string, e.g., "/path"
Query string `json:"query,omitempty" msgpack:"q,omitempty"` // query string without leading ?, e.g., "foo=bar"
Version string `json:"version" msgpack:"v"` // "HTTP/1.1" or "HTTP/1.0"
// Headers preserves order and original name casing/whitespace
Headers Headers `json:"headers" msgpack:"h"`
// Body is the request body (decoded if chunked, raw otherwise)
// For chunked encoding, this contains the reassembled body without chunk framing
Body []byte `json:"body,omitempty" msgpack:"b,omitempty"`
// Trailers for chunked encoding (raw bytes, rare but must preserve)
// TODO - FUTURE - Parse trailers into []Header if trailer rules are needed
Trailers []byte `json:"trailers,omitempty" msgpack:"t,omitempty"`
// Chunks preserves per-chunk wire framing for chunked messages.
// When body is mutated, callers must set to nil to avoid stale state being re-emitted.
Chunks []ChunkFrame `json:"chunks,omitempty" msgpack:"ck,omitempty"`
// Protocol metadata for replay fidelity
Protocol string `json:"protocol" msgpack:"pr"` // "http/1.1" - stored for history/replay
// RequestLineEnding is the terminator observed on the request line.
RequestLineEnding LineEnding `json:"request_line_ending,omitempty" msgpack:"rle,omitempty"`
// HeaderBlockEnding is the terminator observed on the blank line that ends the header block.
HeaderBlockEnding LineEnding `json:"header_block_ending,omitempty" msgpack:"hbe,omitempty"`
// Wire contains metadata about the original wire encoding.
// Used by SerializeRaw() to preserve exact wire format.
Wire *WireFormat `json:"wire,omitempty" msgpack:"w,omitempty"`
}
RawHTTP1Request represents a parsed HTTP/1.1 request with wire-level fidelity. The SerializeRaw() method reconstructs wire bytes from the stored components.
func ParseRequest ¶ added in v0.1.11
func ParseRequest(r io.Reader) (*RawHTTP1Request, error)
ParseRequest parses an HTTP/1.1 request from the reader. Returns error only for truly unparseable input.
func (*RawHTTP1Request) GetHeader ¶
func (r *RawHTTP1Request) GetHeader(name string) string
GetHeader returns the first header value with the given name (case-insensitive).
func (*RawHTTP1Request) RemoveHeader ¶
func (r *RawHTTP1Request) RemoveHeader(name string)
RemoveHeader removes all headers with the given name (case-insensitive).
func (*RawHTTP1Request) SerializeRaw ¶
func (r *RawHTTP1Request) SerializeRaw(buf *bytes.Buffer) []byte
SerializeRaw returns wire bytes reconstructed from the parsed request. Emits headers and body exactly as parsed; no auto-cleanup.
func (*RawHTTP1Request) SetBody ¶ added in v0.1.13
func (r *RawHTTP1Request) SetBody(b []byte)
SetBody replaces the body and clears wire state which can't be replicated with a body change.
func (*RawHTTP1Request) SetHeader ¶
func (r *RawHTTP1Request) SetHeader(name, value string)
SetHeader sets or replaces the first header with the given name (case-insensitive).
type RawHTTP1Response ¶
type RawHTTP1Response struct {
// Status line components
Version string `json:"version" msgpack:"v"` // "HTTP/1.1" or "HTTP/1.0"
StatusCode int `json:"status_code" msgpack:"sc"` // 200, 404, etc.
StatusText string `json:"status_text,omitempty" msgpack:"st,omitempty"` // "OK", "Not Found", etc.
// Headers preserves order and original name casing
Headers Headers `json:"headers" msgpack:"h"`
// Body is the response body (decoded if chunked, raw otherwise)
Body []byte `json:"body,omitempty" msgpack:"b,omitempty"`
// Trailers for chunked encoding (raw bytes)
// TODO - FUTURE - Parse trailers into []Header if trailer rules are needed
Trailers []byte `json:"trailers,omitempty" msgpack:"t,omitempty"`
// Chunks preserves per-chunk wire framing for chunked messages.
// When body is mutated, callers must set to nil to avoid stale state being re-emitted.
Chunks []ChunkFrame `json:"chunks,omitempty" msgpack:"ck,omitempty"`
// StatusLineEnding is the terminator observed on the status line.
StatusLineEnding LineEnding `json:"status_line_ending,omitempty" msgpack:"sle,omitempty"`
// HeaderBlockEnding is the terminator observed on the blank line that ends the header block.
HeaderBlockEnding LineEnding `json:"header_block_ending,omitempty" msgpack:"hbe,omitempty"`
// Wire contains metadata about the original wire encoding.
// Used by SerializeRaw() to preserve exact wire format.
Wire *WireFormat `json:"wire,omitempty" msgpack:"w,omitempty"`
}
RawHTTP1Response represents a parsed HTTP/1.1 response with wire-level fidelity.
func BuildInterceptedH1Response ¶ added in v0.1.11
func BuildInterceptedH1Response(intercepted *InterceptedResponse) *RawHTTP1Response
BuildInterceptedH1Response converts an InterceptedResponse to a wire-serializable RawHTTP1Response. Computes Content-Length when the responder set no framing header so keep-alive clients don't hang on connection-close framing.
func (*RawHTTP1Response) GetHeader ¶
func (r *RawHTTP1Response) GetHeader(name string) string
GetHeader returns the first header value with the given name (case-insensitive).
func (*RawHTTP1Response) RemoveHeader ¶
func (r *RawHTTP1Response) RemoveHeader(name string)
RemoveHeader removes all headers with the given name (case-insensitive).
func (*RawHTTP1Response) SerializeHeaders ¶
func (r *RawHTTP1Response) SerializeHeaders(buf *bytes.Buffer) []byte
SerializeHeaders reconstructs the status line and headers only (no body). Useful for SendRequestResult where headers and body are returned separately.
func (*RawHTTP1Response) SerializeRaw ¶
func (r *RawHTTP1Response) SerializeRaw(buf *bytes.Buffer) []byte
SerializeRaw returns wire bytes reconstructed from the parsed response. Emits headers and body exactly as parsed; no auto-cleanup.
func (*RawHTTP1Response) SetBody ¶ added in v0.1.13
func (r *RawHTTP1Response) SetBody(b []byte)
SetBody replaces the body and clears wire state which can't be replicated with a body change.
func (*RawHTTP1Response) SetHeader ¶
func (r *RawHTTP1Response) SetHeader(name, value string)
SetHeader sets or replaces the first header with the given name (case-insensitive).
type ResponseInterceptor ¶ added in v0.1.11
type ResponseInterceptor interface {
// InterceptRequest checks if a request matches a registered responder.
// host is the target hostname (lowercase), port is the target port,
// path is the URL path (query string stripped), method is the HTTP method.
// Returns the response to serve, or nil if no match.
InterceptRequest(host string, port int, path string, method string) *InterceptedResponse
}
ResponseInterceptor checks if a request should be intercepted with a canned response. Implementations must be safe for concurrent use and fast (no I/O on the hot path).
type RuleApplier ¶
type RuleApplier interface {
// ApplyRequestRules applies request header and body rules.
// Returns the modified request (may be same instance if no changes).
ApplyRequestRules(req *RawHTTP1Request) *RawHTTP1Request
// ApplyResponseRules applies response header and body rules.
// Handles decompression/recompression for body rules.
ApplyResponseRules(resp *RawHTTP1Response) *RawHTTP1Response
// ApplyRequestBodyOnlyRules applies only body rules to a request body.
// Used by HTTP/2 where headers are sent separately before body.
// Requires headers for Content-Encoding detection (compression-aware).
// Does not apply header rules.
// Returns error if recompression fails (caller should reset stream).
ApplyRequestBodyOnlyRules(body []byte, headers Headers) ([]byte, error)
// ApplyResponseBodyOnlyRules applies only body rules to a response body.
// Used by HTTP/2 where headers are sent separately before body.
// Requires headers for Content-Encoding detection (compression-aware).
// Does not apply header rules.
ApplyResponseBodyOnlyRules(body []byte, headers Headers) []byte
// ApplyWSRules applies WebSocket rules to frame payload.
// direction is "ws:to-server" or "ws:to-client".
ApplyWSRules(payload []byte, direction string) []byte
// HasBodyRules returns true if there are body rules for request or response.
// Used by HTTP/2 handler to decide whether to buffer full bodies.
// isRequest=true checks for request_body rules, false checks for response_body rules.
HasBodyRules(isRequest bool) bool
}
RuleApplier applies find/replace rules to requests and responses. Implemented by the service layer (NativeProxyBackend). Rules are applied in the order they were added (list order).
type SendOptions ¶
type SendOptions struct {
RawRequest []byte // Raw HTTP request bytes
Target Target // Where to send
Modifications *Modifications // Optional changes
Force bool // Bypass validation
// Protocol specifies the original request's protocol.
// Values: "http/1.1", "h2", or "" (defaults to http/1.1)
// When "h2", the sender will negotiate HTTP/2 with the server.
Protocol string
}
SendOptions configures request sending.
type SendResult ¶
type SendResult struct {
Response *RawHTTP1Response
Duration time.Duration
}
type Sender ¶
type Sender struct {
// JSONModifier is called to apply JSON modifications to request body.
// If nil, SetJSON/RemoveJSON modifications are ignored.
JSONModifier JSONModifier
// RequestRuleApplier applies find/replace rules to each request before sending.
// Called for every request including redirect hops. If nil, no rules are applied.
RequestRuleApplier func(req *RawHTTP1Request) *RawHTTP1Request
// Timeouts holds configurable timeout values for dial, read, and write.
// Zero values mean no timeout.
Timeouts TimeoutConfig
}
Sender sends HTTP requests with wire-level fidelity.
func (*Sender) Send ¶
func (s *Sender) Send(ctx context.Context, opts SendOptions) (*SendResult, error)
Send sends a request and returns the response.
func (*Sender) SendWithRedirects ¶
func (s *Sender) SendWithRedirects(ctx context.Context, opts SendOptions) (*SendResult, error)
SendWithRedirects sends a request and follows redirects.
type TimeoutConfig ¶
type TimeoutConfig struct {
DialTimeout time.Duration
ReadTimeout time.Duration
WriteTimeout time.Duration
}
TimeoutConfig holds configurable timeout values for proxy operations.
type WSFrame ¶
type WSFrame struct {
// Direction is "to-server" or "to-client"
Direction string `json:"direction" msgpack:"dr"`
// Opcode is the WebSocket opcode (1=text, 2=binary, 8=close, 9=ping, 10=pong)
Opcode byte `json:"opcode" msgpack:"op"`
// Payload is the frame payload (unmasked)
Payload []byte `json:"payload,omitempty" msgpack:"pl,omitempty"`
// Timestamp when the frame was captured
Timestamp time.Time `json:"timestamp" msgpack:"ts"`
}
WSFrame represents a single WebSocket frame stored in history.
type WireFormat ¶
type WireFormat struct {
// WasChunked indicates chunked transfer encoding was received.
WasChunked bool `json:"was_chunked,omitempty" msgpack:"wc,omitempty"`
// UsedBareLF is true when any line used bare LF (\n) as terminator.
UsedBareLF bool `json:"used_bare_lf,omitempty" msgpack:"lf,omitempty"`
// UsedBareCR is true when any line used bare CR (\r) as terminator.
UsedBareCR bool `json:"used_bare_cr,omitempty" msgpack:"cr,omitempty"`
}
WireFormat stores summary metadata about the original wire encoding. Per-line terminators are tracked on the LineEnding fields; these flags are informational and drive chunked re-emission (UsedBareCR > UsedBareLF > CRLF).