Documentation
¶
Overview ¶
Package h1 implements a zero-copy HTTP/1.1 parser.
This is a low-level parser package consumed by the celeris engine layer (engine/iouring, engine/epoll, engine/std bridge); application code should not import it directly. The parser returns header and body slices that alias the connection's read buffer — callers must materialize (clone) any value they retain past the next [ParseRequest] call on the same connection.
Index ¶
- Constants
- Variables
- func LowerHeaderCopy(raw []byte) string
- func LowerInPlace(b []byte)
- func UnsafeLowerHeader(raw []byte) string
- func UnsafeString(b []byte) string
- type Parser
- func (p *Parser) ConsumeBody(n int)
- func (p *Parser) GetBody(contentLength int64) []byte
- func (p *Parser) ParseChunkedBody() ([]byte, int, error)
- func (p *Parser) ParseRequest(req *Request) (int, error)
- func (p *Parser) Remaining() int
- func (p *Parser) Reset(buf []byte)
- func (p *Parser) SetZeroCopy(enabled bool)
- type Request
Constants ¶
const MaxHeaderCount = 200
MaxHeaderCount caps the number of header fields in a single request. Prevents an attacker from sending thousands of tiny headers that stay under the MaxHeaderSize byte limit while still triggering O(n) slice growth and scan work. 200 sits above typical nginx/apache defaults (100 for client headers, but verbose proxy chains can add more) and well below the thousands-per-request attack threshold.
const MaxHeaderSize = 64 << 10
MaxHeaderSize is the maximum allowed size of HTTP headers in bytes. 64 KiB matches nginx's large_client_header_buffers ceiling and is two orders of magnitude below the previous 16 MiB which was a slow-loris amplifier. Legitimate request headers are always well under a few KiB; 64 KiB accommodates edge cases like verbose proxy chains without exposing the server to per-connection memory exhaustion.
Variables ¶
var ( ErrBufferExhausted = errors.New("buffer exhausted") ErrInvalidRequestLine = errors.New("invalid request line") ErrInvalidHeader = errors.New("invalid header line") ErrMissingHost = errors.New("missing Host header") ErrUnsupportedVersion = errors.New("unsupported HTTP version") ErrHeadersTooLarge = errors.New("headers too large") ErrTooManyHeaders = errors.New("too many headers") ErrInvalidContentLength = errors.New("invalid content-length") ErrDuplicateContentLength = errors.New("duplicate content-length with conflicting values") )
H1 parser sentinel errors.
Functions ¶
func LowerHeaderCopy ¶ added in v1.4.0
LowerHeaderCopy returns a pre-allocated lowercase string for common HTTP header names, falling back to strings.ToLower(string(raw)) for uncommon names. Unlike UnsafeLowerHeader, the returned string never aliases raw — safe to retain after raw's backing buffer is reused.
func LowerInPlace ¶ added in v1.1.0
func LowerInPlace(b []byte)
LowerInPlace lowercases ASCII bytes in-place.
func UnsafeLowerHeader ¶ added in v1.1.0
UnsafeLowerHeader returns an interned string for common HTTP header names, or lowercases the name in-place and returns a zero-copy unsafe string. The caller must ensure the byte slice outlives the returned string.
func UnsafeString ¶ added in v1.1.0
UnsafeString returns a string that shares the underlying byte slice memory. The caller must ensure the byte slice is not modified while the string is in use.
Types ¶
type Parser ¶
type Parser struct {
// contains filtered or unexported fields
}
Parser is a zero-allocation HTTP/1.x request parser.
func (*Parser) ConsumeBody ¶
ConsumeBody advances the parser position by n bytes.
func (*Parser) GetBody ¶
GetBody returns a zero-copy slice of the request body for the given content length.
func (*Parser) ParseChunkedBody ¶
ParseChunkedBody parses a single chunk from chunked transfer encoding. Returns a zero-copy slice into the parser buffer, bytes consumed, or error. Returns (nil, 0, nil) when more data is needed.
func (*Parser) ParseRequest ¶
ParseRequest parses a complete HTTP/1.x request from the buffer into req.
func (*Parser) SetZeroCopy ¶ added in v1.1.0
SetZeroCopy enables zero-copy header parsing. When enabled, the parser only populates RawHeaders (not Headers). The caller must convert RawHeaders to strings — typically via unsafe.String for zero allocation.
type Request ¶
type Request struct {
Method string
Path string
Version string
Headers [][2]string
RawHeaders [][2][]byte
Host string
ContentLength int64
ChunkedEncoding bool
KeepAlive bool
HeadersComplete bool
BodyRead int64
ExpectContinue bool
// UpgradeH2C is true iff this request is a valid h2c upgrade request
// (RFC 7540 §3.2): Upgrade: h2c (single token, exclusively) + HTTP2-Settings
// header present + Connection header listing BOTH "upgrade" and
// "http2-settings" tokens. The single-token Upgrade requirement
// disambiguates from the WebSocket path (Upgrade: websocket).
UpgradeH2C bool
// HTTP2Settings holds the raw base64url-encoded HTTP2-Settings value
// (still encoded; caller decodes). Non-empty only when the header is present.
HTTP2Settings string
}
Request holds the parsed components of an HTTP/1.x request.