Documentation
¶
Overview ¶
Package groxy provides a small forward HTTP proxy with support for plain HTTP forwarding and HTTPS tunneling through CONNECT requests.
Index ¶
- Constants
- func Block(statusCode int, message string) error
- type BlockError
- type BodyTooLargeError
- type BodyTransform
- type CA
- type CAConfig
- type Config
- type ConnectContext
- type ConnectHook
- type HTTPSInspectionConfig
- type HostMatcher
- type Logger
- type Middleware
- func AddRequestHeader(key, value string) Middleware
- func AddResponseHeader(key, value string) Middleware
- func BlockConnectHost(host string, statusCode int, message string) Middleware
- func BlockHost(host string, statusCode int, message string) Middleware
- func OnConnect(fn ConnectHook) Middleware
- func OnRequest(fn RequestHook) Middleware
- func OnResponse(fn ResponseHook) Middleware
- func RemoveRequestHeader(key string) Middleware
- func RemoveResponseHeader(key string) Middleware
- func TransformRequestBody(transform BodyTransform) Middleware
- func TransformResponseBody(transform BodyTransform) Middleware
- type Proxy
- func (p *Proxy) Addr() string
- func (p *Proxy) IsRunning() bool
- func (p *Proxy) OnConnect(fn ConnectHook) error
- func (p *Proxy) OnRequest(fn RequestHook) error
- func (p *Proxy) OnResponse(fn ResponseHook) error
- func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request)
- func (p *Proxy) Shutdown(ctx context.Context) error
- func (p *Proxy) Start() error
- func (p *Proxy) Use(middleware ...Middleware) error
- type RequestContext
- type RequestHook
- type ResponseContext
- type ResponseHook
- type Timeouts
Examples ¶
Constants ¶
const DefaultMaxBodySize int64 = 10 << 20 // 10 MiB
DefaultMaxBodySize is the default maximum body size read by body helpers.
Variables ¶
This section is empty.
Functions ¶
func Block ¶
Block creates an error that tells Groxy to stop processing and return a response with statusCode and message to the client.
Example ¶
package main
import (
"log"
"github.com/SalzDevs/groxy"
)
func main() {
proxy, err := groxy.New(groxy.Config{
Addr: "127.0.0.1:8080",
})
if err != nil {
log.Fatal(err)
}
if err := proxy.OnRequest(func(ctx *groxy.RequestContext) error {
if ctx.Request.URL.Hostname() == "blocked.example" {
return groxy.Block(403, "blocked by policy")
}
return nil
}); err != nil {
log.Fatal(err)
}
}
Output:
Types ¶
type BlockError ¶
BlockError represents an intentional block response returned by a hook.
func (*BlockError) Error ¶
func (e *BlockError) Error() string
type BodyTooLargeError ¶ added in v0.2.0
type BodyTooLargeError struct {
Limit int64
}
BodyTooLargeError is returned when a body helper reads more than the configured maximum body size.
func (*BodyTooLargeError) Error ¶ added in v0.2.0
func (e *BodyTooLargeError) Error() string
type BodyTransform ¶
BodyTransform transforms a request or response body.
type CA ¶ added in v0.3.0
type CA struct {
// contains filtered or unexported fields
}
CA is a certificate authority used to sign per-host certificates for HTTPS inspection.
func LoadCAFiles ¶ added in v0.3.0
LoadCAFiles loads a CA certificate and RSA private key from PEM files.
func (*CA) WriteFiles ¶ added in v0.3.0
WriteFiles writes the CA certificate and private key to PEM files.
type CAConfig ¶ added in v0.3.0
type CAConfig struct {
// CommonName is the certificate common name. If empty, Groxy uses a default.
CommonName string
// ValidFor is how long the generated CA certificate is valid. If zero, Groxy
// uses a default validity period.
ValidFor time.Duration
}
CAConfig configures local CA generation.
type Config ¶
type Config struct {
// Addr is the TCP address the proxy listens on, such as "127.0.0.1:8080".
Addr string
// Timeouts controls network timeout behavior for the proxy.
//
// If nil, Groxy uses DefaultTimeouts. If provided, zero-valued fields are
// filled with their default values.
Timeouts *Timeouts
// MaxBodySize is the maximum number of bytes BodyBytes and body transform
// middleware will read into memory.
//
// If zero, Groxy uses DefaultMaxBodySize.
MaxBodySize int64
// Logger receives log messages from the proxy.
//
// If nil, Groxy discards log messages.
Logger Logger
// HTTPSInspection enables opt-in HTTPS inspection using local TLS
// interception.
//
// If nil, HTTPS requests use normal CONNECT tunneling and encrypted bodies
// cannot be inspected or modified.
HTTPSInspection *HTTPSInspectionConfig
}
Config contains settings used to create a Proxy.
type ConnectContext ¶
type ConnectContext struct {
Host string
}
ConnectContext contains data available to CONNECT hooks.
type ConnectHook ¶
type ConnectHook func(*ConnectContext) error
ConnectHook is called before a CONNECT tunnel is opened.
type HTTPSInspectionConfig ¶ added in v0.3.0
type HTTPSInspectionConfig struct {
// CA signs generated per-host certificates used for inspected HTTPS traffic.
CA *CA
// Intercept decides which CONNECT hosts should be inspected.
//
// This field is required when HTTPS inspection is enabled. Use MatchAllHosts
// in a future release if you explicitly want to inspect every host.
Intercept HostMatcher
// CertificateTTL controls how long generated per-host certificates are valid.
//
// If zero, Groxy uses a safe default. Generated certificates are kept in
// memory only and renewed before they expire.
CertificateTTL time.Duration
// PassthroughOnError controls whether Groxy falls back to a normal CONNECT
// tunnel if HTTPS inspection setup fails.
//
// The default is false, so inspection failures fail closed instead of
// silently bypassing inspection policy.
PassthroughOnError bool
}
HTTPSInspectionConfig configures opt-in HTTPS inspection for CONNECT traffic.
HTTPS inspection uses local TLS interception: Groxy terminates TLS from the client with a certificate signed by CA, then opens its own TLS connection to the upstream server. This allows normal request/response middleware and body transforms to run on selected HTTPS traffic.
If HTTPSInspectionConfig is nil, Groxy keeps the current safe default and tunnels HTTPS traffic without inspecting encrypted request or response bodies.
type HostMatcher ¶ added in v0.3.0
HostMatcher decides whether a host should be selected for HTTPS inspection.
The host may include a port, such as "example.com:443". Matchers should normalize hosts as needed before comparing them.
func MatchAllHosts ¶ added in v0.3.0
func MatchAllHosts() HostMatcher
MatchAllHosts returns a HostMatcher that matches every host.
func MatchHosts ¶ added in v0.3.0
func MatchHosts(patterns ...string) HostMatcher
MatchHosts returns a HostMatcher for exact and wildcard host patterns.
Patterns are case-insensitive. Hosts may include ports. A pattern beginning with "*." matches subdomains only, so "*.example.com" matches "api.example.com" but not "example.com".
type Logger ¶
Logger is used by Groxy to write log messages.
It matches the Printf method provided by the standard library's log.Logger.
type Middleware ¶
type Middleware struct {
// contains filtered or unexported fields
}
Middleware configures proxy behavior.
func AddRequestHeader ¶
func AddRequestHeader(key, value string) Middleware
AddRequestHeader returns middleware that sets a request header before the request is sent upstream.
func AddResponseHeader ¶
func AddResponseHeader(key, value string) Middleware
AddResponseHeader returns middleware that sets a response header before the response is sent back to the client.
func BlockConnectHost ¶
func BlockConnectHost(host string, statusCode int, message string) Middleware
BlockConnectHost returns middleware that blocks CONNECT tunnels to host.
func BlockHost ¶
func BlockHost(host string, statusCode int, message string) Middleware
BlockHost returns middleware that blocks normal HTTP requests to host.
func OnConnect ¶
func OnConnect(fn ConnectHook) Middleware
OnConnect creates middleware that runs fn before CONNECT tunnels are opened.
func OnRequest ¶
func OnRequest(fn RequestHook) Middleware
OnRequest creates middleware that runs fn before HTTP requests are sent upstream.
func OnResponse ¶
func OnResponse(fn ResponseHook) Middleware
OnResponse creates middleware that runs fn before HTTP responses are sent to the client.
func RemoveRequestHeader ¶
func RemoveRequestHeader(key string) Middleware
RemoveRequestHeader returns middleware that deletes a request header before the request is sent upstream.
func RemoveResponseHeader ¶
func RemoveResponseHeader(key string) Middleware
RemoveResponseHeader returns middleware that deletes a response header before the response is sent back to the client.
func TransformRequestBody ¶
func TransformRequestBody(transform BodyTransform) Middleware
TransformRequestBody returns middleware that replaces a request body with the bytes returned by transform.
Example ¶
package main
import (
"bytes"
"log"
"github.com/SalzDevs/groxy"
)
func main() {
proxy, err := groxy.New(groxy.Config{
Addr: "127.0.0.1:8080",
})
if err != nil {
log.Fatal(err)
}
if err := proxy.Use(groxy.TransformRequestBody(func(body []byte) ([]byte, error) {
return bytes.ReplaceAll(body, []byte("secret"), []byte("[redacted]")), nil
})); err != nil {
log.Fatal(err)
}
}
Output:
func TransformResponseBody ¶
func TransformResponseBody(transform BodyTransform) Middleware
TransformResponseBody returns middleware that replaces a response body with the bytes returned by transform.
func (Middleware) Name ¶
func (m Middleware) Name() string
Name returns the middleware name used in logs and error messages.
type Proxy ¶
type Proxy struct {
// contains filtered or unexported fields
}
Proxy represents a forward proxy server.
A Proxy can be started as a standalone server with Start, gracefully stopped with Shutdown, or used directly as an http.Handler through ServeHTTP.
func New ¶
New creates a Proxy from config.
New validates the config and prepares the internal server/client state, but it does not start listening. Call Start to begin accepting proxy requests.
Example ¶
package main
import (
"log"
"github.com/SalzDevs/groxy"
)
func main() {
proxy, err := groxy.New(groxy.Config{
Addr: "127.0.0.1:8080",
})
if err != nil {
log.Fatal(err)
}
_ = proxy
}
Output:
func (*Proxy) OnConnect ¶
func (p *Proxy) OnConnect(fn ConnectHook) error
OnConnect adds a CONNECT hook to the proxy.
func (*Proxy) OnRequest ¶
func (p *Proxy) OnRequest(fn RequestHook) error
OnRequest adds a request hook to the proxy.
Example ¶
package main
import (
"log"
"github.com/SalzDevs/groxy"
)
func main() {
proxy, err := groxy.New(groxy.Config{
Addr: "127.0.0.1:8080",
})
if err != nil {
log.Fatal(err)
}
if err := proxy.OnRequest(func(ctx *groxy.RequestContext) error {
ctx.Request.Header.Set("X-From-Groxy", "true")
return nil
}); err != nil {
log.Fatal(err)
}
}
Output:
func (*Proxy) OnResponse ¶
func (p *Proxy) OnResponse(fn ResponseHook) error
OnResponse adds a response hook to the proxy.
func (*Proxy) ServeHTTP ¶
func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP handles incoming proxy requests.
ServeHTTP allows Proxy to satisfy http.Handler, so it can be mounted on a custom http.Server instead of being started with Start.
func (*Proxy) Shutdown ¶
Shutdown gracefully stops the proxy server.
Shutdown stops accepting new requests and waits for active requests to finish until ctx is canceled or expires.
func (*Proxy) Start ¶
Start starts the proxy server and blocks until the server stops.
Start returns nil when the server is stopped through Shutdown. It returns an error if the server fails to start or stops unexpectedly.
func (*Proxy) Use ¶
func (p *Proxy) Use(middleware ...Middleware) error
Use adds middleware to the proxy.
Middleware must be registered before Start is called or before the proxy is used to serve requests through ServeHTTP. Use returns an error if middleware is added after the proxy has started.
Example ¶
package main
import (
"log"
"github.com/SalzDevs/groxy"
)
func main() {
proxy, err := groxy.New(groxy.Config{
Addr: "127.0.0.1:8080",
})
if err != nil {
log.Fatal(err)
}
if err := proxy.Use(
groxy.AddRequestHeader("X-Groxy-Request", "true"),
groxy.AddResponseHeader("X-Groxy-Response", "true"),
); err != nil {
log.Fatal(err)
}
}
Output:
type RequestContext ¶
RequestContext contains data available to request hooks.
func (*RequestContext) BodyBytes ¶
func (ctx *RequestContext) BodyBytes() ([]byte, error)
BodyBytes reads and restores the request body.
HTTP bodies are streams: reading them consumes them. BodyBytes puts the bytes back with SetBody so later hooks and the proxy forwarding logic can read the body again.
func (*RequestContext) SetBody ¶
func (ctx *RequestContext) SetBody(body []byte)
SetBody replaces the request body with body.
type RequestHook ¶
type RequestHook func(*RequestContext) error
RequestHook is called before a normal HTTP request is sent upstream.
type ResponseContext ¶
type ResponseContext struct {
Request *http.Request
Response *http.Response
// contains filtered or unexported fields
}
ResponseContext contains data available to response hooks.
func (*ResponseContext) BodyBytes ¶
func (ctx *ResponseContext) BodyBytes() ([]byte, error)
BodyBytes reads and restores the response body.
HTTP bodies are streams: reading them consumes them. BodyBytes puts the bytes back with SetBody so later hooks and the response writing logic can read the body again.
func (*ResponseContext) SetBody ¶
func (ctx *ResponseContext) SetBody(body []byte)
SetBody replaces the response body with body.
type ResponseHook ¶
type ResponseHook func(*ResponseContext) error
ResponseHook is called before an upstream HTTP response is sent back to the client.
type Timeouts ¶
type Timeouts struct {
// Dial is the maximum time allowed to connect to an upstream server.
Dial time.Duration
// TLSHandshake is the maximum time allowed for TLS handshakes made by the proxy HTTP client.
TLSHandshake time.Duration
// ResponseHeader is the maximum time allowed to wait for upstream response headers.
ResponseHeader time.Duration
// IdleConn is the maximum time an unused upstream keep-alive connection stays open.
IdleConn time.Duration
// ReadHeader is the maximum time allowed for a client to send request headers to the proxy.
ReadHeader time.Duration
// Idle is the maximum time an idle client connection to the proxy stays open.
Idle time.Duration
}
Timeouts contains timeout settings for client, upstream, and idle proxy connections.
func DefaultTimeouts ¶
func DefaultTimeouts() Timeouts
DefaultTimeouts returns Groxy's default timeout values.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
groxy
command
|
|
|
examples
|
|
|
basic
command
|
|
|
body-transform
command
|
|
|
https-inspection
command
|
|
|
middleware
command
|