Documentation
¶
Overview ¶
Package conn provides shared HTTP/1.1 and HTTP/2 connection handling.
Index ¶
- Variables
- func CloseH1(state *H1State)
- func CloseH2(state *H2State)
- func DecodeHTTP2Settings(s string) ([]byte, error)
- func ProcessH1(ctx context.Context, data []byte, state *H1State, handler stream.Handler, ...) error
- func ProcessH2(ctx context.Context, data []byte, state *H2State, _ stream.Handler, ...) error
- func ReleaseUpgradeInfo(info *UpgradeInfo)
- type H1State
- type H2Config
- type H2State
- type UpgradeInfo
Constants ¶
This section is empty.
Variables ¶
var ErrHijacked = errors.New("celeris: connection hijacked")
ErrHijacked is returned by ProcessH1 when the connection was hijacked. The engine must not close or reuse the FD after receiving this error.
var ErrUpgradeH2C = errors.New("celeris: h2c upgrade requested")
ErrUpgradeH2C is returned by ProcessH1 after it has written the 101 Switching Protocols response in reply to an RFC 7540 §3.2 h2c upgrade request. The engine must NOT treat this as an error: instead it must read state.UpgradeInfo and switch the connection to H2.
The original handler has NOT been invoked; it will be dispatched on H2 stream 1 by NewH2StateFromUpgrade once the H2 stack is up.
Functions ¶
func CloseH1 ¶ added in v1.1.0
func CloseH1(state *H1State)
CloseH1 releases the cached stream and context (if any) back to their pools.
func CloseH2 ¶
func CloseH2(state *H2State)
CloseH2 cleans up H2 state. Releases all streams still held by the manager to prevent memory leaks on connection close.
func DecodeHTTP2Settings ¶ added in v1.4.0
DecodeHTTP2Settings base64url-decodes the HTTP2-Settings header value. RFC 7540 §3.2.1 specifies base64url without padding, but some clients include padding — accept both.
Validation: the decoded payload length must be a multiple of 6 (one SETTINGS entry = u16 id + u32 value). Any other length indicates a malformed payload.
func ProcessH1 ¶
func ProcessH1(ctx context.Context, data []byte, state *H1State, handler stream.Handler, write func([]byte)) error
ProcessH1 processes incoming H1 data, parsing requests and calling the handler. The write callback is used to send response bytes back to the connection.
func ProcessH2 ¶
func ProcessH2(ctx context.Context, data []byte, state *H2State, _ stream.Handler, write func([]byte), _ H2Config) error
ProcessH2 processes incoming H2 data. On first call, validates the client preface and sends server settings. PING, SETTINGS ACK) and falls back to x/net framer for complex types.
func ReleaseUpgradeInfo ¶ added in v1.4.0
func ReleaseUpgradeInfo(info *UpgradeInfo)
ReleaseUpgradeInfo resets every field and returns the struct to the pool. Aliased slices (Body, Remaining) keep their source buffers alive via their slice references, so we MUST nil them out before returning to the pool or the next acquirer's value will pin stale memory.
Types ¶
type H1State ¶
type H1State struct {
RemoteAddr string
HijackFn func() (net.Conn, error) // set by engine; nil if unsupported
MaxRequestBodySize int64 // 0 = use default (100 MB)
OnExpectContinue func(method, path string, headers [][2]string) bool // nil = always accept
OnDetach func() // set by engine; called on Context.Detach
Detached bool // set by OnDetach; breaks pipelining loop
// WSDataDelivery is set by the WebSocket middleware after upgrade (101 sent).
// When non-nil and Detached, subsequent reads are delivered as raw bytes
// to this callback instead of being parsed as H1 requests. The callback
// is called on the event loop thread — it must not block.
WSDataDelivery func(data []byte)
// RawWriteFn is set after Detach. It writes raw bytes to the engine's
// write buffer, bypassing H1 chunked encoding. Used by WebSocket for
// frame writes.
RawWriteFn func([]byte)
// OnDetachClose is called by the engine when it closes a detached
// connection (timeout, error, shutdown). The WebSocket middleware sets
// this to close the io.Pipe and data channel, unblocking the handler
// goroutine. Called under cs.detachMu — must not block.
//
// Detached-connection API surface — stable. The fields below
// (OnDetachClose, OnError, PauseRecv, ResumeRecv, IdleDeadlineNs) form
// the contract between the engine layer and any long-lived-connection
// middleware (WebSocket, SSE, gRPC streaming, etc). They are part of
// the celeris public API: changes require a major version bump.
OnDetachClose func()
// OnError is called by the engine when an I/O failure occurs on a
// detached connection (read error, write error, EPIPE, ECONNRESET, etc).
// The WebSocket middleware uses this to surface engine-side errors
// from the next user-level Read or Write call. Called under cs.detachMu
// — must not block.
OnError func(err error)
// PauseRecv and ResumeRecv are set by the engine in OnDetach. The
// middleware calls them to apply TCP-level backpressure on the inbound
// data path. They may be called from any goroutine and are no-ops if
// the engine cannot pause reads (e.g. std hijacked path).
PauseRecv func()
ResumeRecv func()
// IdleDeadlineNs holds the absolute deadline (Unix nanoseconds) at
// which a detached connection should be closed by the engine. The
// WebSocket middleware updates this after each successful frame read;
// the engine's idle sweep checks it on detached connections. 0 = no
// deadline.
IdleDeadlineNs atomic.Int64
// EnableH2Upgrade, when true, permits this connection to honor a
// valid RFC 7540 §3.2 h2c upgrade request. Set by the engine at
// initProtocol time from resource.Config.EnableH2Upgrade.
EnableH2Upgrade bool
// UpgradeInfo is populated by ProcessH1 just before returning
// ErrUpgradeH2C. The engine consumes it via switchToH2 and then clears
// it. Always nil on a clean (non-upgrade) connection.
UpgradeInfo *UpgradeInfo
// contains filtered or unexported fields
}
H1State holds per-connection H1 parsing state.
func NewH1State ¶
func NewH1State() *H1State
NewH1State creates a new H1 connection state with zero-copy header parsing.
func (*H1State) UpdateWriteFn ¶ added in v1.2.0
UpdateWriteFn replaces the response adapter's write function. Called by OnDetach to route StreamWriter writes through the mutex-guarded writeFn.
type H2Config ¶
type H2Config struct {
MaxConcurrentStreams uint32
InitialWindowSize uint32
MaxFrameSize uint32
MaxRequestBodySize int64 // 0 = use default (100 MB)
}
H2Config holds H2 connection configuration.
type H2State ¶
type H2State struct {
// contains filtered or unexported fields
}
H2State holds per-connection H2 state.
Sub-structures (outBuf, inBuf, wq, rw, inlineRW) are embedded as VALUES rather than pointer fields so the whole struct is allocated in one heap block instead of 8. Pointer callers take &s.outBuf etc; since heap allocations don't move in Go, the inner pointers stay stable for the lifetime of the H2State.
`processor`, `parser`, and `writer` remain pointer fields — Processor in particular is already large (sync.Mutex, multiple maps, hpack state) and has its own lifecycle hooks, so collapsing it into the parent would invert the existing layering.
func NewH2State ¶
NewH2State creates a new H2 connection state. wakeupFD is an eventfd used to signal the event loop when handler goroutines enqueue responses (-1 to disable, falling back to polling).
func NewH2StateFromUpgrade ¶ added in v1.4.0
func NewH2StateFromUpgrade(handler stream.Handler, cfg H2Config, write func([]byte), wakeupFD int, info *UpgradeInfo) (*H2State, error)
NewH2StateFromUpgrade constructs an H2State that has already absorbed the RFC 7540 §3.2 h2c upgrade: the server preface (SETTINGS + ACK) is written synchronously, the client's HTTP2-Settings are applied, and the original H1 request is injected as stream 1. The engine then feeds info.Remaining — which may contain the expected H2 client preface and initial SETTINGS frame — through ProcessH2 on the same iteration.
Unlike NewH2State, this function writes to the connection directly (before returning) because the 101 response has already been sent and the client is entitled to see the server SETTINGS immediately.
func (*H2State) DrainWriteQueue ¶ added in v1.1.0
DrainWriteQueue drains async handler responses to the write function. Called from the event loop thread (outside H2State.mu).
func (*H2State) SetRemoteAddr ¶ added in v1.1.0
SetRemoteAddr sets the remote address on the H2 stream manager so that all streams created on this connection inherit the peer address.
func (*H2State) WriteQueuePending ¶ added in v1.1.0
WriteQueuePending returns true if the write queue has pending data.
type UpgradeInfo ¶ added in v1.4.0
type UpgradeInfo struct {
// Settings is the base64url-decoded HTTP2-Settings payload. Each entry
// is a 6-byte pair (u16 identifier + u32 value); length is always a
// multiple of 6 (DecodeHTTP2Settings rejects others).
Settings []byte
// Method is the H1 request method (used to build the H2 :method
// pseudo-header).
Method string
// URI is the raw request URI as sent on the request line (used for
// :path).
URI string
// Headers are the request's non-hop-by-hop headers, lowercased,
// excluding Upgrade/Connection/HTTP2-Settings (which are consumed by
// the upgrade mechanism itself and do not belong on H2 stream 1).
Headers [][2]string
// Body holds the request body (may be empty).
Body []byte
// Remaining holds the bytes AFTER the H1 request in the recv buffer.
// May contain 0 bytes, a partial H2 client preface, a full preface, or
// preface + additional frames. The engine feeds this to ProcessH2
// synchronously after switchToH2 so no data is dropped at the seam.
Remaining []byte
}
UpgradeInfo carries the state needed to switch an H1 connection to H2 mid-stream. It is populated by ProcessH1 on an h2c upgrade, then consumed by the engine's switchToH2 path.