proxy

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 25, 2026 License: MIT Imports: 48 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrEmptyRequest    = errors.New("empty request")
	ErrEmptyResponse   = errors.New("empty response")
	ErrInvalidRequest  = errors.New("invalid request line")
	ErrInvalidResponse = errors.New("invalid status line")
)

Functions

func BuildInterceptedH1Response added in v0.1.11

func BuildInterceptedH1Response(intercepted *InterceptedResponse) *types.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 CheckLineEndings

func CheckLineEndings(raw []byte) string

CheckLineEndings detects line ending issues in HTTP headers. Returns a description of the issue, or empty string if OK.

func Compress

func Compress(data []byte, encoding string) ([]byte, error)

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

func ContainsHeader(entries []string, name string) bool

ContainsHeader checks if any "Name: Value" entry matches the given header name (case-insensitive).

func Decompress

func Decompress(data []byte, encoding string) ([]byte, bool)

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 ExtractMethod added in v0.1.6

func ExtractMethod(raw []byte) string

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

func FilterSupportedEncodings(acceptEncoding string) string

FilterSupportedEncodings filters an Accept-Encoding header value to the encodings the proxy can decompress/recompress, preserving quality values and ordering. Any identity token (including identity;q=0) is a client preference and passes through unchanged; unsupported encodings are always dropped so upstream never returns an undecodable body. Returns "identity" when nothing remains (RFC 7231 implicit identity).

func NormalizeEncoding

func NormalizeEncoding(encoding string) (string, bool)

NormalizeEncoding normalizes a Content-Encoding header value. Returns the canonical encoding and whether it's a single supported encoding. Multiple encodings return ("", false) since we can't partially decode.

func ParseRequest added in v0.1.11

func ParseRequest(r io.Reader, unframedBody bool) (*types.RawHTTP1Request, error)

ParseRequest parses an HTTP/1.1 request from the reader. Returns error only for truly unparseable input. unframedBody takes the bytes after the header block as the body when Content-Length/Transfer-Encoding are absent; use it only for a reader holding exactly one message.

func ParseRequestLine

func ParseRequestLine(line []byte) (method, path, query, version string, err error)

ParseRequestLine extracts method, path, query, version from request line. Accepts malformed lines if method and path are extractable.

func ParseResponse added in v0.2.0

func ParseResponse(r io.Reader, requestMethod string) (*types.RawHTTP1Response, error)

ParseResponse parses an HTTP/1.1 response from the reader. The request method is needed to determine body handling for HEAD responses.

func PathWithoutQuery

func PathWithoutQuery(p string) string

PathWithoutQuery returns the path portion before any query string.

Types

type CaptureFilter added in v0.1.6

type CaptureFilter func(flow *types.Flow) bool

CaptureFilter decides whether a flow should be stored. Returns true if the flow 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, spec *types.CertSpec) (*tls.Certificate, error)

GetCertificate returns a certificate for the hostname, whose SANs additionally include any names in spec (nil spec yields a single-SAN leaf). Generates and caches if not already cached.

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 HistoryStore

type HistoryStore struct {
	// contains filtered or unexported fields
}

HistoryStore provides typed access to proxy history backed by store.Storage. Entries are keyed by flow_id; merge ordering uses (Timestamp, FlowID).

func (*HistoryStore) Children added in v0.1.18

func (h *HistoryStore) Children(parentFlowID string) []*types.Flow

Children returns the child flows of parentFlowID in emission order.

func (*HistoryStore) Close

func (h *HistoryStore) Close()

Close closes the underlying storage.

func (*HistoryStore) Complete added in v0.1.18

func (h *HistoryStore) Complete(flowID string, resp *types.Message, completedAt time.Time, annotations map[string]any) bool

Complete attaches a late response and/or completion to an already-stored flow: the two-phase form used for deferred responses and session/stream teardown. resp, when non-nil, populates the response side; a non-zero completedAt sets CompletedAt; annotations merge over existing keys. Returns false when flowID is unknown.

func (*HistoryStore) Count

func (h *HistoryStore) Count() int

Count returns the number of entries currently stored.

func (*HistoryStore) Delete added in v0.1.15

func (h *HistoryStore) Delete(flowIDs ...string) int

Delete removes entries by flow_id, cascading to their child flows. Idempotent; unknown ids are skipped. Returns the number of requested entries removed, not counting cascaded children.

func (*HistoryStore) Get

func (h *HistoryStore) Get(flowID string) (*types.Flow, bool)

Get retrieves a flow by flow_id.

func (*HistoryStore) GetMeta

func (h *HistoryStore) GetMeta(flowID string) (*types.HistoryMeta, bool)

GetMeta retrieves lightweight metadata for an entry by flow_id.

func (*HistoryStore) Page added in v0.1.15

func (h *HistoryStore) Page(count int, afterFlowID string) []*types.Flow

Page returns up to count flows strictly after afterFlowID, ordered oldest-first.

func (*HistoryStore) PageMeta added in v0.1.15

func (h *HistoryStore) PageMeta(count int, afterFlowID string) []types.HistoryMeta

PageMeta returns up to count meta entries strictly after afterFlowID, ordered oldest-first.

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) SetInvokedBy added in v0.1.18

func (h *HistoryStore) SetInvokedBy(flowID, invokedBy string) bool

SetInvokedBy records the originating sidecar on an already-stored flow. Returns false when flowID is unknown.

func (*HistoryStore) ShouldCapture added in v0.1.6

func (h *HistoryStore) ShouldCapture(flow *types.Flow) bool

ShouldCapture returns true if the flow passes the capture filter, or true when no filter is configured.

func (*HistoryStore) Store

func (h *HistoryStore) Store(flow *types.Flow) string

Store mints a flow_id, assigns it to flow, persists, and returns the flow_id. flow.StartedAt must be set by the caller. Child flows (ParentFlowID set) are stored payload-only: no meta key and absent from the listing order.

type InterceptedResponse added in v0.1.11

type InterceptedResponse struct {
	StatusCode int
	Headers    types.Headers
	Body       []byte
}

InterceptedResponse is a canned response to serve for an intercepted 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, fullBuffer bool) (*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. fullBuffer forces whole-body buffering for response body rules instead of streaming.

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) Registry added in v0.1.18

func (s *ProxyServer) Registry() *protocol.Registry

Registry returns the per-connection claim registry.

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 types.RuleApplier)

SetRuleApplier sets the rule applier for all handlers. Call after construction but before Serve().

func (*ProxyServer) Shutdown

func (s *ProxyServer) Shutdown(ctx context.Context) error

Shutdown gracefully stops the server, bounded by ctx.

func (*ProxyServer) WaitReady

func (s *ProxyServer) WaitReady(ctx context.Context) error

WaitReady blocks until Serve() has entered its accept loop.

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 SendOptions

type SendOptions struct {
	RawRequest []byte       // Raw HTTP request bytes
	Target     types.Target // Where to send
	Force      bool         // Bypass validation

	// Protocol specifies the original request's protocol.
	// Values: "http/1.1", "http/2", or "" (defaults to http/1.1)
	// When "http/2", the sender will negotiate HTTP/2 with the server.
	Protocol string
}

SendOptions configures request sending.

type SendResult

type SendResult struct {
	Response *types.RawHTTP1Response
	Duration time.Duration

	// ModifiedRequest holds the first hop's post-rule request bytes, set only when rules
	// changed the request. nil when no RequestRuleApplier ran or it made no change.
	ModifiedRequest []byte
}

type Sender

type Sender struct {
	// 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 *types.RawHTTP1Request) *types.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.

Directories

Path Synopsis
Package types holds the proxy capture data model: the wire-fidelity HTTP/1.1 request/response types, the common Flow/Message envelope, and the rule-applier contract.
Package types holds the proxy capture data model: the wire-fidelity HTTP/1.1 request/response types, the common Flow/Message envelope, and the rule-applier contract.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL