Documentation
¶
Index ¶
- Constants
- Variables
- func AppendJSONString(dst []byte, s string) []byte
- func AppendRecord(dst []byte, ct byte, payload []byte) []byte
- func BuildALPNExtension(proto string) []byte
- func BuildCertificate(chain [][]byte) []byte
- func BuildCertificateVerify(sig []byte) []byte
- func BuildEncryptedExtensions(alpn string) []byte
- func BuildFinished(verifyData []byte) []byte
- func BuildH1Response(resp *Response) ([]byte, *[]byte)
- func BuildServerHello(random, sessionID []byte, suiteID uint16, pubKey []byte) []byte
- func CoarseNanotime() int64
- func ComputeFinished(h func() hash.Hash, hashLen int, baseSecret, transcriptHash []byte) []byte
- func Dbg(format string, v ...interface{})
- func DbgHex(label string, data []byte)
- func DialTCP4(addr string, timeout time.Duration) (net.Conn, error)
- func EmptyTranscriptHash(h func() hash.Hash) []byte
- func EqualFoldASCII(a, b string) bool
- func Filename(path string) string
- func GenerateCert() ([]byte, *ecdsa.PrivateKey, error)
- func GenerateSelfSignedForDomain(domain string) ([]byte, *ecdsa.PrivateKey, error)
- func H2WriteContinuation(dst []byte, flags byte, streamID uint32, headerBlock []byte) []byte
- func H2WriteFrame(dst []byte, typ, flags byte, streamID uint32, payload []byte) []byte
- func H2WriteGoAway(dst []byte, lastStream, errCode uint32) []byte
- func H2WritePing(dst []byte, ack bool, data [8]byte) []byte
- func H2WriteRSTStream(dst []byte, streamID, errCode uint32) []byte
- func H2WriteSettings(dst []byte, settings [][2]uint32) []byte
- func H2WriteSettingsAck(dst []byte) []byte
- func H2WriteWindowUpdate(dst []byte, streamID, increment uint32) []byte
- func HSWrap(msgType byte, body []byte) []byte
- func HexDigit(b byte) byte
- func HpackDecodeInt(data []byte, prefixBits uint8) (uint64, int)
- func HpackDecodeString(data []byte) (string, int)
- func IOUringStartupProbeReport() string
- func LoadOrGenerateCert(certFile, keyFile string) ([]byte, *ecdsa.PrivateKey, error)
- func MonotonicNanotime() int64
- func NegotiateALPN(clientProtos []string, allowH2 bool) string
- func ParseClientHello(data []byte, result *ParsedClientHello) error
- func ParseH1Request(data []byte, req *Request) int
- func ParseH1RequestHead(data []byte, req *Request) (headerEnd int, contentLength int, hasContentLength bool, closeConn bool, ...)
- func ReadRecord(conn net.Conn, hdrScratch []byte) (byte, []byte, *[]byte, error)
- func ReadRecordSkipCCS(conn net.Conn, hdr []byte) (byte, []byte, *[]byte, error)
- func ReleaseRecordBuf(bp *[]byte)
- func SendCCS(conn net.Conn) error
- func SendCloseNotify(conn net.Conn, writer *TrafficAEAD)
- func SetDebugFlag(on bool)
- func SignCertificateVerify(priv *ecdsa.PrivateKey, transcriptHash []byte) ([]byte, error)
- func StatusText(code int) string
- func StringHash(s string) uint64
- func StripInnerPlaintext(data []byte) (content []byte, contentType byte, err error)
- func TLSDeriveSecret(h func() hash.Hash, hashLen int, secret []byte, label string, ...) []byte
- func TLSExpandLabel(h func() hash.Hash, secret []byte, label string, ctx []byte, length int) []byte
- func TLSExtract(h func() hash.Hash, salt, ikm []byte) []byte
- func TLSExtractTo(h func() hash.Hash, salt, ikm, dst []byte) []byte
- func ToLowerASCII(s string) string
- func Uint32Hash(v uint32) uint64
- func Uint32Hash64(v uint64) uint64
- func UnsafeBytes(s string) []byte
- func UnsafeString(b []byte) string
- func ValidateHost(host string) bool
- func WriteAppData(conn net.Conn, writer *TrafficAEAD, data []byte) error
- func WriteH1Response(conn net.Conn, writer *TrafficAEAD, resp *Response) error
- func WriteRecord(conn net.Conn, ct byte, payload []byte) error
- type ACMEConfig
- type BackendConfig
- type BandwidthConfig
- type BasicAuthConfig
- type BufConn
- type CORSConfig
- type CORSEngine
- type CacheOption
- type CacheRule
- type CertConfig
- type CertEntry
- type CertInfo
- type CertSource
- type CertStore
- type CipherSuiteConfig
- type CompressConfig
- type Config
- type ConnectionLimiter
- type DomainConfig
- type FineTuneOptions
- type FineTuneReport
- type FineTuneResult
- type FineTuneScenario
- type GlobalLimiter
- type H1StreamWriter
- type H2Conn
- type H2Frame
- type H2Stream
- type H2StreamWriter
- type HTTPRoute
- type HTTPRouter
- type HandlerFunc
- type HealthCheckConfig
- type HpackDecoder
- func (d *HpackDecoder) Decode(data []byte) ([][2]string, error)
- func (d *HpackDecoder) DecodeInto(headers [][2]string, data []byte) ([][2]string, error)
- func (d *HpackDecoder) DecodeIntoRequest(headers [][2]string, data []byte) ([][2]string, hpackRequestMeta, error)
- func (d *HpackDecoder) DecodeRequestMeta(data []byte) (hpackRequestMeta, error)
- type HpackEncoder
- func (e *HpackEncoder) EncodeHeader(name, value string)
- func (e *HpackEncoder) EncodeIndexed(idx uint64)
- func (e *HpackEncoder) EncodeInt(prefix byte, prefixBits uint8, val uint64)
- func (e *HpackEncoder) EncodeStatus(code int)
- func (e *HpackEncoder) EncodeString(s string)
- func (e *HpackEncoder) Reset(dst []byte)
- type JSON
- type LoadBalancerType
- type MiddlewareFunc
- func AllowMethods(methods ...string) MiddlewareFunc
- func BasicAuth(cfg BasicAuthConfig) MiddlewareFunc
- func BodyLimit(maxBytes int64) MiddlewareFunc
- func CORS(config CORSConfig) MiddlewareFunc
- func Compress(cfg CompressConfig) MiddlewareFunc
- func Header(name, value string) MiddlewareFunc
- func If(predicate func(*Request) bool, inner MiddlewareFunc) MiddlewareFunc
- func Logger() MiddlewareFunc
- func RealIP(trustedProxies ...string) MiddlewareFunc
- func Recovery() MiddlewareFunc
- func RequestID() MiddlewareFunc
- func SecurityHeaders(cfg SecurityHeadersConfig) MiddlewareFunc
- func Timeout(d time.Duration) MiddlewareFunc
- type Param
- type ParsedClientHello
- type PlainH1StreamWriter
- type ProxyCache
- func (pc *ProxyCache) Get(method, host, path, acceptEncoding string) (*cacheEntry, bool)
- func (pc *ProxyCache) Purge(method, host, path string) bool
- func (pc *ProxyCache) PurgeAll()
- func (pc *ProxyCache) PurgeDomain(domain string) int64
- func (pc *ProxyCache) Put(method, host, path string, statusCode int, headers [][2]string, ...)
- func (pc *ProxyCache) PutManual(method, host, path string, statusCode int, headers [][2]string, ...)
- func (pc *ProxyCache) ServeCached(entry *cacheEntry, req *Request, resp *Response)
- func (pc *ProxyCache) Stats() (entries int64, totalBytes int64, hits uint64, misses uint64)
- func (pc *ProxyCache) Stop()
- func (pc *ProxyCache) UpdateConfig(cfg ProxyCacheConfig)
- type ProxyCacheConfig
- type ProxyEngine
- type ProxyError
- type ProxyErrorFunc
- type ProxyInterceptFunc
- type ProxyRequest
- type ProxyResponse
- type ProxyResponseFunc
- type RateLimitEngine
- type RateLimitEvent
- type RateLimitFunc
- type RateLimitRule
- type Request
- type Response
- func (r *Response) BodyLen() int
- func (r *Response) Bytes(b []byte) *Response
- func (r *Response) GetBody() []byte
- func (r *Response) HTML(s string) *Response
- func (r *Response) IsStreamed() bool
- func (r *Response) JSON(jsonBytes []byte) *Response
- func (r *Response) JSONMarshal(v any) error
- func (r *Response) JSONString(s string) *Response
- func (r *Response) Reset()
- func (r *Response) SendFile(path string, opts ...SendFileOption) error
- func (r *Response) SetBody(b []byte)
- func (r *Response) SetHeader(name, value string) *Response
- func (r *Response) SetHeaderUnsafe(name, value string) *Response
- func (r *Response) SetSW(sw StreamWriter)
- func (r *Response) SetStreamer(sw StreamWriter)
- func (r *Response) Status(code int) *Response
- func (r *Response) Streamer() StreamWriter
- func (r *Response) String(s string) *Response
- type RouteGroup
- func (g *RouteGroup) ANY(path string, handler HandlerFunc)
- func (g *RouteGroup) DELETE(path string, handler HandlerFunc)
- func (g *RouteGroup) GET(path string, handler HandlerFunc)
- func (g *RouteGroup) Group(prefix string, middleware ...MiddlewareFunc) *RouteGroup
- func (g *RouteGroup) HEAD(path string, handler HandlerFunc)
- func (g *RouteGroup) OPTIONS(path string, handler HandlerFunc)
- func (g *RouteGroup) PATCH(path string, handler HandlerFunc)
- func (g *RouteGroup) POST(path string, handler HandlerFunc)
- func (g *RouteGroup) PUT(path string, handler HandlerFunc)
- func (g *RouteGroup) Use(middleware ...MiddlewareFunc)
- type Router
- func (r *Router) ANY(path string, handler HandlerFunc)
- func (r *Router) Build()
- func (r *Router) DELETE(path string, handler HandlerFunc)
- func (r *Router) GET(path string, handler HandlerFunc)
- func (r *Router) Group(prefix string, middleware ...MiddlewareFunc) *RouteGroup
- func (r *Router) HEAD(path string, handler HandlerFunc)
- func (r *Router) Handle(method, path string, handler HandlerFunc)
- func (r *Router) Lookup(method, path string, req *Request) HandlerFunc
- func (r *Router) Match(method, path string) bool
- func (r *Router) MethodNotAllowed(handler HandlerFunc)
- func (r *Router) NotFound(handler HandlerFunc)
- func (r *Router) OPTIONS(path string, handler HandlerFunc)
- func (r *Router) PATCH(path string, handler HandlerFunc)
- func (r *Router) POST(path string, handler HandlerFunc)
- func (r *Router) PUT(path string, handler HandlerFunc)
- func (r *Router) Use(middleware ...MiddlewareFunc)
- type SecurityHeadersConfig
- type SendFileOption
- type Server
- func (s *Server) AddACMEDomain(domain string, email ...string)
- func (s *Server) AddCert(domain string, certPEM, keyPEM []byte) error
- func (s *Server) AddCertFromFiles(domain, certFile, keyFile string) error
- func (s *Server) AddCerts(domain string, certPEM, keyPEM []byte) error
- func (s *Server) AddDomainCert(domain string, certPEM, keyPEM []byte) error
- func (s *Server) AddHTTPRoute(route HTTPRoute)
- func (s *Server) AddProxyDomain(cfg DomainConfig)
- func (s *Server) AddRateLimitRule(rule RateLimitRule)
- func (s *Server) AddSelfSignedCert(domain string) error
- func (s *Server) EnableACME(cfg ACMEConfig)
- func (s *Server) FineTune() error
- func (s *Server) FineTuneWithOptions(options FineTuneOptions) (*FineTuneReport, error)
- func (s *Server) IsDebug() bool
- func (s *Server) ListCerts() []CertInfo
- func (s *Server) ListenAndServe() error
- func (s *Server) ListenAndServeTLS() error
- func (s *Server) LocalIPs() []net.IP
- func (s *Server) NewH1StreamWriter(conn net.Conn, writer *TrafficAEAD) *H1StreamWriter
- func (s *Server) NewH2StreamWriter(streamID uint32, hc *H2Conn, streamWindow *atomic.Int64) *H2StreamWriter
- func (s *Server) NewPlainH1StreamWriter(conn net.Conn) *PlainH1StreamWriter
- func (s *Server) OnProxyError(fn ProxyErrorFunc)
- func (s *Server) OnProxyRequest(fn ProxyInterceptFunc)
- func (s *Server) OnProxyResponse(fn ProxyResponseFunc)
- func (s *Server) OnRateLimit(fn RateLimitFunc)
- func (s *Server) Proxy() *ProxyEngine
- func (s *Server) ProxyCacheStats() (entries int64, totalBytes int64, hits uint64, misses uint64)
- func (s *Server) PurgeAllProxyCache()
- func (s *Server) PurgeDomainCache(domain string) int64
- func (s *Server) PurgeProxyCache(method, host, path string) bool
- func (s *Server) ReloadCert(domain, certFile, keyFile string) error
- func (s *Server) RemoveCert(domain string)
- func (s *Server) RemoveHTTPRoute(pathPrefix string)
- func (s *Server) RemoveProxyDomain(domain string)
- func (s *Server) RemoveRateLimitRule(path string)
- func (s *Server) ServeH1(conn net.Conn, reader, writer *TrafficAEAD, hdrBuf []byte)
- func (s *Server) ServeH1Plain(conn net.Conn)
- func (s *Server) ServeH2(conn net.Conn, reader, writer *TrafficAEAD, hdrBuf []byte)
- func (s *Server) ServeH2Plain(conn net.Conn)
- func (s *Server) SetCORS(cfg CORSConfig)
- func (s *Server) SetDebug(on bool)
- func (s *Server) SetDefaultCert(domain string)
- func (s *Server) SetHTTPRoutes(routes []HTTPRoute)
- func (s *Server) SetLogRequests(on bool)
- func (s *Server) SetProxy(pe *ProxyEngine)
- func (s *Server) SetProxyCache(cfg ProxyCacheConfig)
- func (s *Server) SetRateLimitRules(rules []RateLimitRule)
- func (s *Server) Shutdown(ctx context.Context) error
- func (s *Server) UpdateCORS(cfg CORSConfig)
- func (s *Server) UpdateCert(domain string, certPEM, keyPEM []byte) error
- type ServerStats
- type ShardedMap
- type StreamWriter
- type TLSConn
- type TokenBucket
- type TrafficAEAD
- type WSConn
- func (ws *WSConn) Close() error
- func (ws *WSConn) Ping() error
- func (ws *WSConn) ReadMessage() (byte, []byte, error)
- func (ws *WSConn) SetDeadline(t time.Time) error
- func (ws *WSConn) WriteBinary(data []byte) error
- func (ws *WSConn) WriteMessage(opcode byte, data []byte) error
- func (ws *WSConn) WriteText(msg string) error
- type WriteRequest
Constants ¶
const ( MaxRecordPayload = 16384 MaxRecordOverhead = 256 MaxRecordSize = MaxRecordPayload + MaxRecordOverhead CacheLineSize = 64 H2PrefaceLen = 24 H2DefaultWindowSize = 65535 H2DefaultMaxFrameSize = 16384 H2MaxFrameSize = 16777215 H2HeaderTableSize = 4096 H2MaxConcurrentStream = 256 H2MaxHeaderListSize = 8192 H2ConnectionWindowSize = 4194304 H2StreamWindowSize = 4194304 H2FrameData byte = 0x0 H2FrameHeaders byte = 0x1 H2FramePriority byte = 0x2 H2FrameRSTStream byte = 0x3 H2FrameSettings byte = 0x4 H2FramePushPromise byte = 0x5 H2FramePing byte = 0x6 H2FrameGoAway byte = 0x7 H2FrameWindowUpdate byte = 0x8 H2FrameContinuation byte = 0x9 H2FlagEndStream byte = 0x1 H2FlagEndHeaders byte = 0x4 H2FlagPadded byte = 0x8 H2FlagPriority byte = 0x20 H2FlagAck byte = 0x1 H2ErrNoError uint32 = 0x0 H2ErrProtocol uint32 = 0x1 H2ErrInternal uint32 = 0x2 H2ErrFlowControl uint32 = 0x3 H2ErrSettingsTimeout uint32 = 0x4 H2ErrStreamClosed uint32 = 0x5 H2ErrFrameSize uint32 = 0x6 H2ErrRefusedStream uint32 = 0x7 H2ErrCancel uint32 = 0x8 H2ErrCompression uint32 = 0x9 H2ErrConnect uint32 = 0xa H2ErrEnhanceYourCalm uint32 = 0xb H2ErrInadequateSec uint32 = 0xc H2ErrHTTP11Required uint32 = 0xd H2SettingHeaderTableSize uint16 = 0x1 H2SettingEnablePush uint16 = 0x2 H2SettingMaxConcurrentStreams uint16 = 0x3 H2SettingInitialWindowSize uint16 = 0x4 H2SettingMaxFrameSize uint16 = 0x5 H2SettingMaxHeaderListSize uint16 = 0x6 )
const ( StreamIdle uint32 = 0 StreamOpen uint32 = 1 StreamHalfClosed uint32 = 2 StreamClosed uint32 = 3 )
Variables ¶
var ( ErrRecordTooLarge = &staticError{"record too large"} ErrNotClientHello = &staticError{"not a ClientHello"} ErrTruncated = &staticError{"message truncated"} ErrBodyTooShort = &staticError{"body too short"} ErrNoSessionID = &staticError{"no session_id"} ErrSessionIDTruncated = &staticError{"session_id truncated"} ErrNoCipherSuites = &staticError{"no cipher_suites"} ErrBadCSLen = &staticError{"cipher_suites bad length"} ErrNoCompression = &staticError{"no compression"} ErrNoExtensions = &staticError{"no extensions"} ErrExtsTruncated = &staticError{"extensions truncated"} ErrNoX25519 = &staticError{"no x25519 key_share"} ErrAllZeroInner = &staticError{"all-zero inner plaintext"} ErrSigVerifyFailed = &staticError{"signature self-verification failed"} ErrH2BadPreface = &staticError{"invalid h2 preface"} ErrH2FrameTooLarge = &staticError{"h2 frame too large"} ErrH2StreamClosed = &staticError{"h2 stream closed"} ErrH2FlowControl = &staticError{"h2 flow control violation"} ErrH2BadHeader = &staticError{"h2 bad header"} ErrH2GoAway = &staticError{"h2 goaway received"} ErrConnectionClosed = &staticError{"connection closed"} ErrBodyTooLarge = &staticError{"body too large"} ErrRateLimited = &staticError{"rate limited"} ErrStreamClosed = &staticError{"stream closed"} ErrWindowExhausted = &staticError{"flow control window exhausted"} ErrNoCertForSNI = &staticError{"no certificate for server name"} ErrProxyBadResponse = &staticError{"proxy: bad upstream response"} ErrProxyNoBackend = &staticError{"proxy: no healthy backend"} ErrProxyTimeout = &staticError{"proxy: upstream timeout"} ErrProxyConnFailed = &staticError{"proxy: connection failed"} ErrIOUringRequired = &staticError{"io_uring worker backend required"} ErrInternal = &staticError{"internal error"} ErrRateLimit = &staticError{"rate limit exceeded"} ErrTooManyHeaders = &staticError{"too many headers"} ErrHpackTableSizeExceeded = &staticError{"hpack: dynamic table size exceeds protocol limit"} ErrWebSocketProtocol = &staticError{"websocket protocol error"} )
var BufReaderPool = sync.Pool{ New: func() any { return bufio.NewReaderSize(nil, 65536) }, }
var FileReadBufPool = sync.Pool{ New: func() any { b := make([]byte, 65536); return &b }, }
var H1StreamWriterPool = sync.Pool{ New: func() any { return &H1StreamWriter{} }, }
var H2ClientPreface = [24]byte{'P', 'R', 'I', ' ', '*', ' ', 'H', 'T', 'T', 'P', '/', '2', '.', '0', '\r', '\n', '\r', '\n', 'S', 'M', '\r', '\n', '\r', '\n'}
var H2FrameBufPool = sync.Pool{ New: func() any { b := make([]byte, 0, H2DefaultMaxFrameSize+9); return &b }, }
var H2FramePool = sync.Pool{ New: func() any { return &H2Frame{ Payload: make([]byte, 0, 1024), } }, }
var H2StreamWriterPool = sync.Pool{ New: func() any { return &H2StreamWriter{} }, }
var HpackStaticTable = [62][2]string{
{},
{":authority", ""},
{":method", "GET"},
{":method", "POST"},
{":path", "/"},
{":path", "/index.html"},
{":scheme", "http"},
{":scheme", "https"},
{":status", "200"},
{":status", "204"},
{":status", "206"},
{":status", "304"},
{":status", "400"},
{":status", "404"},
{":status", "500"},
{"accept-charset", ""},
{"accept-encoding", "gzip, deflate"},
{"accept-language", ""},
{"accept-ranges", ""},
{"accept", ""},
{"access-control-allow-origin", ""},
{"age", ""},
{"allow", ""},
{"authorization", ""},
{"cache-control", ""},
{"content-disposition", ""},
{"content-encoding", ""},
{"content-language", ""},
{"content-length", ""},
{"content-location", ""},
{"content-range", ""},
{"content-type", ""},
{"cookie", ""},
{"date", ""},
{"etag", ""},
{"expect", ""},
{"expires", ""},
{"from", ""},
{"host", ""},
{"if-match", ""},
{"if-modified-since", ""},
{"if-none-match", ""},
{"if-range", ""},
{"if-unmodified-since", ""},
{"last-modified", ""},
{"link", ""},
{"location", ""},
{"max-forwards", ""},
{"proxy-authenticate", ""},
{"proxy-authorization", ""},
{"range", ""},
{"referer", ""},
{"refresh", ""},
{"retry-after", ""},
{"server", ""},
{"set-cookie", ""},
{"strict-transport-security", ""},
{"transfer-encoding", ""},
{"user-agent", ""},
{"vary", ""},
{"via", ""},
{"www-authenticate", ""},
}
var LargeBufPool = sync.Pool{ New: func() any { b := make([]byte, 0, 32768); return &b }, }
var MediumBufPool = sync.Pool{ New: func() any { b := make([]byte, 0, 4096); return &b }, }
var PlainH1StreamWriterPool = sync.Pool{ New: func() any { return &PlainH1StreamWriter{} }, }
var RecordBufPool = sync.Pool{ New: func() any { b := make([]byte, 0, MaxRecordSize+5); return &b }, }
var RequestPool = sync.Pool{ New: func() any { return &Request{ Headers: make([][2]string, 0, 16), Body: make([]byte, 0, 1024), } }, }
var ResponsePool = sync.Pool{ New: func() any { return &Response{ Headers: make([][2]string, 0, 8), body: make([]byte, 0, 4096), } }, }
var SmallBufPool = sync.Pool{ New: func() any { b := make([]byte, 0, 512); return &b }, }
var StreamPool = sync.Pool{ New: func() any { return &H2Stream{ Headers: make([][2]string, 0, 16), Body: make([]byte, 0, 4096), } }, }
var SupportedSuites = [3]CipherSuiteConfig{ { ID: 0x1301, KeyLen: 16, IVLen: 12, HashFn: sha256.New, HashLen: 32, MakeAEAD: func(key []byte) (cipher.AEAD, error) { b, err := aes.NewCipher(key) if err != nil { return nil, err } return cipher.NewGCM(b) }, }, { ID: 0x1302, KeyLen: 32, IVLen: 12, HashFn: sha512.New384, HashLen: 48, MakeAEAD: func(key []byte) (cipher.AEAD, error) { b, err := aes.NewCipher(key) if err != nil { return nil, err } return cipher.NewGCM(b) }, }, { ID: 0x1303, KeyLen: 32, IVLen: 12, HashFn: sha256.New, HashLen: 32, MakeAEAD: func(key []byte) (cipher.AEAD, error) { return chacha20poly1305.New(key) }, }, }
var WriteBufPool = sync.Pool{ New: func() any { b := make([]byte, 0, MaxRecordSize); return &b }, }
Functions ¶
func AppendJSONString ¶
func BuildALPNExtension ¶
func BuildCertificate ¶
func BuildCertificateVerify ¶
func BuildFinished ¶
func BuildH1Response ¶
func BuildServerHello ¶
func CoarseNanotime ¶
func CoarseNanotime() int64
func ComputeFinished ¶
func EmptyTranscriptHash ¶
func EqualFoldASCII ¶
func Filename ¶
Filename extracts the filename component from a file path, stripping any directory prefix.
core.Filename("/var/data/report.csv") // "report.csv"
core.Filename("report.csv") // "report.csv"
func GenerateCert ¶
func GenerateCert() ([]byte, *ecdsa.PrivateKey, error)
func GenerateSelfSignedForDomain ¶
func GenerateSelfSignedForDomain(domain string) ([]byte, *ecdsa.PrivateKey, error)
func H2WriteContinuation ¶
func H2WriteFrame ¶
func H2WriteGoAway ¶
func H2WriteRSTStream ¶
func H2WriteSettings ¶
func H2WriteSettingsAck ¶
func H2WriteWindowUpdate ¶
func HpackDecodeString ¶
func IOUringStartupProbeReport ¶
func IOUringStartupProbeReport() string
func LoadOrGenerateCert ¶
func LoadOrGenerateCert(certFile, keyFile string) ([]byte, *ecdsa.PrivateKey, error)
func MonotonicNanotime ¶
func MonotonicNanotime() int64
MonotonicNanotime returns the runtime's monotonic nanosecond clock. It is appropriate for timeout and elapsed-time bookkeeping in hot paths.
func NegotiateALPN ¶
NegotiateALPN picks the best supported application protocol from the client's ALPN list. When allowH2 is false, "h2" is skipped and only HTTP/1.1 may be selected.
func ParseClientHello ¶
func ParseClientHello(data []byte, result *ParsedClientHello) error
func ParseH1Request ¶
func ParseH1RequestHead ¶
func ReadRecordSkipCCS ¶
func ReleaseRecordBuf ¶
func ReleaseRecordBuf(bp *[]byte)
func SendCloseNotify ¶
func SendCloseNotify(conn net.Conn, writer *TrafficAEAD)
func SetDebugFlag ¶
func SetDebugFlag(on bool)
func SignCertificateVerify ¶
func SignCertificateVerify(priv *ecdsa.PrivateKey, transcriptHash []byte) ([]byte, error)
func StatusText ¶
func StringHash ¶
func StripInnerPlaintext ¶
func TLSDeriveSecret ¶
func TLSExpandLabel ¶
func ToLowerASCII ¶
func Uint32Hash ¶
func Uint32Hash64 ¶
func UnsafeBytes ¶
func UnsafeString ¶
func ValidateHost ¶
func WriteAppData ¶
func WriteAppData(conn net.Conn, writer *TrafficAEAD, data []byte) error
func WriteH1Response ¶
func WriteH1Response(conn net.Conn, writer *TrafficAEAD, resp *Response) error
Types ¶
type ACMEConfig ¶
ACMEConfig configures automatic TLS certificate provisioning through Let's Encrypt (or any ACME-compatible CA). Pass this in the server Config to enable automatic certificate management.
cfg := core.Config{
ACME: &core.ACMEConfig{
Email: "[email protected]",
CacheDir: "/var/certs",
Domains: []string{"example.com", "www.example.com"},
},
}
type BackendConfig ¶
BackendConfig defines a single upstream backend server that the reverse proxy will forward traffic to. Addr accepts bare host:port, or full URLs with http:// or https:// schemes. When an https:// URL is given, TLS is enabled automatically and defaults to port 443 if no port is specified. Weight controls the proportion of traffic this backend receives when using LBWeightedRR. If you need to connect to backends with self-signed certs (e.g. in development), set TLSSkipVerify to true.
// Plain HTTP backend on port 8080
core.BackendConfig{Addr: "10.0.0.10:8080", Weight: 1}
// HTTPS backend with auto-detected TLS
core.BackendConfig{Addr: "https://api-internal.example.com"}
// Dev backend with self-signed cert
core.BackendConfig{Addr: "https://localhost:9090", TLSSkipVerify: true}
type BandwidthConfig ¶
type BasicAuthConfig ¶
BasicAuthConfig holds username/password pairs and the HTTP Basic Auth realm string.
cfg := core.BasicAuthConfig{
Users: map[string]string{"admin": "secret"},
Realm: "Admin Panel",
}
type BufConn ¶
func NewBufConn ¶
type CORSConfig ¶
type CORSConfig struct {
AllowOrigins []string
AllowMethods []string
AllowHeaders []string
ExposeHeaders []string
AllowCredentials bool
MaxAge int
}
CORSConfig controls Cross-Origin Resource Sharing headers.
cfg := core.CORSConfig{
AllowOrigins: []string{"https://example.com", "https://app.example.com"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowHeaders: []string{"Content-Type", "Authorization"},
ExposeHeaders: []string{"X-Request-ID"},
AllowCredentials: true,
MaxAge: 86400,
}
Set AllowOrigins to []string{"*"} to allow all origins. When AllowCredentials is true and the origin is "*", the actual Origin header value is reflected back (per the CORS spec).
type CORSEngine ¶
type CORSEngine struct {
// contains filtered or unexported fields
}
CORSEngine holds a snapshot of the CORS config and can be updated at runtime without restarting the server. Access to the snapshot is lock-free via atomic.Pointer.
func NewCORSEngine ¶
func NewCORSEngine(cfg CORSConfig) *CORSEngine
NewCORSEngine creates a CORSEngine with the given config.
func (*CORSEngine) Config ¶
func (ce *CORSEngine) Config() CORSConfig
func (*CORSEngine) Middleware ¶
func (ce *CORSEngine) Middleware() MiddlewareFunc
func (*CORSEngine) Update ¶
func (ce *CORSEngine) Update(cfg CORSConfig)
type CacheOption ¶
type CacheOption func(*cacheOpts)
func WithCompressMinLen ¶
func WithCompressMinLen(n int) CacheOption
WithCompressMinLen sets the minimum response body size in bytes before pre-compression kicks in. Responses smaller than this threshold are stored uncompressed even when WithPreCompress is true, since gzip overhead can make small payloads larger. Defaults to the value from ProxyCacheConfig.CompressMinLen (512 bytes with DefaultProxyCacheConfig).
pr.CacheThis(5*time.Minute, 0, core.WithCompressMinLen(1024))
func WithPreCompress ¶
func WithPreCompress(on bool) CacheOption
WithPreCompress controls whether a pre-compressed gzip copy of the response body is stored in the cache alongside the original. When enabled, clients that send Accept-Encoding: gzip receive the pre-compressed copy without any runtime compression overhead. Defaults to true.
pr.CacheThis(5*time.Minute, 0, core.WithPreCompress(false))
type CacheRule ¶
type CacheRule struct {
PathPrefix string
MaxAge time.Duration
Methods []string
MaxBytes int64
StatusOnly []int
}
CacheRule configures caching for a specific path prefix. If PathPrefix is empty it acts as a default rule. Methods defaults to ["GET"] if empty.
core.CacheRule{
PathPrefix: "/api/",
MaxAge: 10 * time.Minute,
Methods: []string{"GET"},
MaxBytes: 1 << 20, // 1 MB max per entry
StatusOnly: []int{200, 301}, // only cache these status codes
}
type CertConfig ¶
type CertConfig struct {
Domain string
CertFile string
KeyFile string
Source CertSource
}
CertConfig specifies a TLS certificate to load for a domain. Used with manual certificate management instead of ACME.
cfg := core.Config{
Certs: []core.CertConfig{
{
Domain: "example.com",
CertFile: "/etc/ssl/example.com.pem",
KeyFile: "/etc/ssl/example.com-key.pem",
Source: core.CertManual,
},
},
}
type CertEntry ¶
type CertEntry struct {
Domain string
ChainDER [][]byte
PrivKey *ecdsa.PrivateKey
TLSCert tls.Certificate
Source CertSource
// contains filtered or unexported fields
}
func NewCertEntryFromDER ¶
func NewCertEntryFromDER(domain string, certDER []byte, privKey *ecdsa.PrivateKey, source CertSource) *CertEntry
func NewCertEntryFromPEM ¶
func NewCertEntryFromPEM(domain string, certPEM, keyPEM []byte, source CertSource) (*CertEntry, error)
func (*CertEntry) CachedEECert ¶
type CertInfo ¶
type CertInfo struct {
Domain string
Source CertSource
}
type CertSource ¶
type CertSource uint8
const ( CertSelfSigned CertSource = iota CertManual CertACME )
type CertStore ¶
type CertStore struct {
// contains filtered or unexported fields
}
func NewCertStore ¶
func NewCertStore() *CertStore
func (*CertStore) RemoveCert ¶
func (*CertStore) SetDefault ¶
type CipherSuiteConfig ¶
type CipherSuiteConfig struct {
ID uint16
KeyLen int
IVLen int
HashFn func() hash.Hash
HashLen int
MakeAEAD func(key []byte) (cipher.AEAD, error)
// contains filtered or unexported fields
}
func NegotiateSuite ¶
func NegotiateSuite(clientIDs []uint16) *CipherSuiteConfig
func (*CipherSuiteConfig) ComputeFinishedTo ¶
func (cs *CipherSuiteConfig) ComputeFinishedTo(baseSecret, transcriptHash, dst []byte) []byte
func (*CipherSuiteConfig) DeriveSecretTo ¶
func (cs *CipherSuiteConfig) DeriveSecretTo(tmpl *hkdfLabelTemplate, secret, transcriptHash, dst []byte) []byte
type CompressConfig ¶
CompressConfig controls response compression.
cfg := core.CompressConfig{
Level: 6, // gzip/deflate level (1-9)
MinSize: 512, // skip compression below this body size
}
type Config ¶
type Config struct {
Addr string
HTTPAddr string
ReadTimeout time.Duration
WriteTimeout time.Duration
IdleTimeout time.Duration
HandshakeTimeout time.Duration
MaxBodySize int64
MaxReadSize int64
MaxWriteSize int64
MaxHeaderSize int
MaxRequestsPerIP int64
MaxConcurrentReqs int64
TLSCertFile string
TLSKeyFile string
Certs []CertConfig
DefaultDomain string
ACME *ACMEConfig
WorkerCount int
ConnBandwidth BandwidthConfig
GlobalBandwidth BandwidthConfig
Listeners int
ServerName string
TrustedProxies []string
EnableCompress bool
CompressLevel int
CompressMinSize int
Debug bool
LogRequests bool
ShutdownTimeout time.Duration
PlainHTTP bool
DisableHTTP2 bool
}
Config controls every aspect of the ALOS server. Pass it to New to create a Server. Zero values use sane defaults (see DefaultConfig).
s := core.New(core.Config{
Addr: ":443",
IdleTimeout: 120 * time.Second,
Listeners: 4,
PlainHTTP: false,
ServerName: "ALOS",
ACME: &core.ACMEConfig{
Email: "[email protected]",
Domains: []string{"example.com"},
},
})
Fields:
- Addr: listen address (":443", ":8443", "0.0.0.0:443", etc.)
- HTTPAddr: listen address for the HTTP-to-HTTPS redirect listener. Defaults to ":80" when Addr uses port 443, otherwise disabled.
- PlainHTTP: when true the server speaks plain HTTP/1.1 on Addr, skipping TLS entirely.
- DisableHTTP2: when true the server never negotiates HTTP/2 and only serves HTTP/1.1 over TLS.
- IdleTimeout: how long an idle keep-alive connection stays open.
- HandshakeTimeout: deadline for the TLS handshake.
- MaxBodySize: reject request bodies larger than this (0 = unlimited).
- MaxReadSize / MaxWriteSize: per-connection I/O caps.
- MaxHeaderSize: maximum header block in bytes.
- MaxConcurrentReqs: server-wide concurrency cap (0 = unlimited).
- Listeners: number of SO_REUSEPORT listeners (Linux only, 1 elsewhere).
- Certs: per-domain certificate configs (manual, self-signed, or ACME).
- ACME: automatic Let's Encrypt certificates.
- ConnBandwidth / GlobalBandwidth: per-connection and global rate limits.
- Debug: enable verbose internal logging.
- LogRequests: log every accepted and closed connection.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns a Config with sensible defaults. It listens on :8443 with a 120s idle timeout, 30s handshake timeout, 8 KiB header limit, gzip level 6, and request logging enabled.
type ConnectionLimiter ¶
type ConnectionLimiter struct {
Upload *TokenBucket
Download *TokenBucket
}
func NewConnectionLimiter ¶
func NewConnectionLimiter(config BandwidthConfig) *ConnectionLimiter
func (*ConnectionLimiter) ThrottleDownload ¶
func (cl *ConnectionLimiter) ThrottleDownload(n int64)
func (*ConnectionLimiter) ThrottleUpload ¶
func (cl *ConnectionLimiter) ThrottleUpload(n int64)
type DomainConfig ¶
type DomainConfig struct {
Domain string
Backends []BackendConfig
LoadBalancer LoadBalancerType
ConnectTimeout time.Duration
ReadTimeout time.Duration
WriteTimeout time.Duration
MaxRetries int
MaxIdleConns int
IdleTimeout time.Duration
HealthCheck HealthCheckConfig
HostHeader string
PreserveHost bool
}
DomainConfig holds the full configuration for a proxied domain, including its backends, load balancer strategy, timeouts, connection pooling, and health checks. Pass this to Server.AddProxyDomain to register a domain.
Timeouts and pool sizes default to sensible values when left at zero:
ConnectTimeout: 10s
ReadTimeout: 30s
WriteTimeout: 10s
MaxRetries: 2
MaxIdleConns: 32
IdleTimeout: 90s
Backend weights: 1
srv.AddProxyDomain(core.DomainConfig{ Domain: "api.example.com", Backends: []core.BackendConfig{ {Addr: "10.0.0.10:8080", Weight: 3}, {Addr: "10.0.0.11:8080", Weight: 1}, }, LoadBalancer: core.LBWeightedRR, ConnectTimeout: 5 * time.Second, ReadTimeout: 15 * time.Second, MaxRetries: 3, MaxIdleConns: 64, HealthCheck: core.HealthCheckConfig{ Enabled: true, Path: "/healthz", Interval: 5 * time.Second, FailThreshold: 3, }, })
type FineTuneOptions ¶
type FineTuneOptions struct {
WorkerCandidates []int
ListenerCandidates []int
Scenarios []FineTuneScenario
AutoInstallWrk bool
StartupTimeout time.Duration
RequestTimeout time.Duration
BindHost string
}
func DefaultFineTuneOptions ¶
func DefaultFineTuneOptions() FineTuneOptions
type FineTuneReport ¶
type FineTuneReport struct {
WrkPath string
AutoInstalledWrk bool
WorkerCandidates []int
ListenerCandidates []int
BestWorkerCount int
BestListenerCount int
BestAcceptShards int
BestByScenario []FineTuneResult
Results []FineTuneResult
}
func (*FineTuneReport) String ¶
func (report *FineTuneReport) String() string
type FineTuneResult ¶
type FineTuneScenario ¶
type GlobalLimiter ¶
type GlobalLimiter struct {
Upload *TokenBucket
Download *TokenBucket
}
func NewGlobalLimiter ¶
func NewGlobalLimiter(config BandwidthConfig) *GlobalLimiter
type H1StreamWriter ¶
type H1StreamWriter struct {
// contains filtered or unexported fields
}
func (*H1StreamWriter) Close ¶
func (w *H1StreamWriter) Close() error
func (*H1StreamWriter) Flush ¶
func (w *H1StreamWriter) Flush() error
func (*H1StreamWriter) WriteChunk ¶
func (w *H1StreamWriter) WriteChunk(data []byte) error
func (*H1StreamWriter) WriteHeader ¶
func (w *H1StreamWriter) WriteHeader(statusCode int, headers [][2]string, contentType string) error
type H2Stream ¶
type H2StreamWriter ¶
type H2StreamWriter struct {
// contains filtered or unexported fields
}
func (*H2StreamWriter) Close ¶
func (w *H2StreamWriter) Close() error
func (*H2StreamWriter) Flush ¶
func (w *H2StreamWriter) Flush() error
func (*H2StreamWriter) WriteChunk ¶
func (w *H2StreamWriter) WriteChunk(data []byte) error
func (*H2StreamWriter) WriteHeader ¶
func (w *H2StreamWriter) WriteHeader(statusCode int, headers [][2]string, contentType string) error
type HTTPRoute ¶
HTTPRoute defines an HTTP (non-TLS) routing rule for the server. When the server receives a plain HTTP request, it matches the path against PathPrefix and forwards to Backend. This is used with Server.SetHTTPRoutes.
srv.SetHTTPRoutes([]core.HTTPRoute{
{PathPrefix: "/.well-known/acme-challenge/", Backend: "127.0.0.1:8080"},
{PathPrefix: "/", Backend: "https://example.com"},
})
type HTTPRouter ¶
type HTTPRouter struct {
// contains filtered or unexported fields
}
func (*HTTPRouter) AddRoute ¶
func (hr *HTTPRouter) AddRoute(route HTTPRoute)
func (*HTTPRouter) RemoveRoute ¶
func (hr *HTTPRouter) RemoveRoute(pathPrefix string)
func (*HTTPRouter) SetRoutes ¶
func (hr *HTTPRouter) SetRoutes(routes []HTTPRoute)
type HandlerFunc ¶
func Chain ¶
func Chain(handler HandlerFunc, middleware ...MiddlewareFunc) HandlerFunc
Chain wraps a handler with the given middleware, applying them in order so the first middleware in the list is the outermost wrapper.
protected := core.Chain(myHandler, authMiddleware, logMiddleware)
r.GET("/secret", protected)
type HealthCheckConfig ¶
type HealthCheckConfig struct {
Enabled bool
Path string
Interval time.Duration
Timeout time.Duration
FailThreshold int
SuccessThreshold int
}
HealthCheckConfig configures active health checking for backends in a domain. When Enabled is true, the proxy periodically sends HTTP GET requests to Path on each backend and marks them healthy or unhealthy based on the response. Backends that fail FailThreshold consecutive checks are taken out of rotation. They are re-added after SuccessThreshold consecutive passing checks.
All fields have sensible defaults when left at zero values:
Interval defaults to 10s
Timeout defaults to 5s
FailThreshold defaults to 3
SuccessThreshold defaults to 2
core.HealthCheckConfig{ Enabled: true, Path: "/healthz", Interval: 5 * time.Second, Timeout: 2 * time.Second, FailThreshold: 3, SuccessThreshold: 2, }
type HpackDecoder ¶
type HpackDecoder struct {
// contains filtered or unexported fields
}
func NewHpackDecoder ¶
func NewHpackDecoder() *HpackDecoder
func (*HpackDecoder) DecodeInto ¶
func (d *HpackDecoder) DecodeInto(headers [][2]string, data []byte) ([][2]string, error)
func (*HpackDecoder) DecodeIntoRequest ¶
func (d *HpackDecoder) DecodeIntoRequest(headers [][2]string, data []byte) ([][2]string, hpackRequestMeta, error)
func (*HpackDecoder) DecodeRequestMeta ¶
func (d *HpackDecoder) DecodeRequestMeta(data []byte) (hpackRequestMeta, error)
type HpackEncoder ¶
type HpackEncoder struct {
Buf []byte
}
func (*HpackEncoder) EncodeHeader ¶
func (e *HpackEncoder) EncodeHeader(name, value string)
func (*HpackEncoder) EncodeIndexed ¶
func (e *HpackEncoder) EncodeIndexed(idx uint64)
func (*HpackEncoder) EncodeInt ¶
func (e *HpackEncoder) EncodeInt(prefix byte, prefixBits uint8, val uint64)
func (*HpackEncoder) EncodeStatus ¶
func (e *HpackEncoder) EncodeStatus(code int)
func (*HpackEncoder) EncodeString ¶
func (e *HpackEncoder) EncodeString(s string)
func (*HpackEncoder) Reset ¶
func (e *HpackEncoder) Reset(dst []byte)
type LoadBalancerType ¶
type LoadBalancerType uint8
const ( LBRoundRobin LoadBalancerType = iota LBWeightedRR LBLeastConn LBIPHash LBRandom )
type MiddlewareFunc ¶
type MiddlewareFunc func(HandlerFunc) HandlerFunc
func AllowMethods ¶
func AllowMethods(methods ...string) MiddlewareFunc
AllowMethods returns middleware that rejects requests whose method is not in the given list with 405 Method Not Allowed.
s.Router.Use(core.AllowMethods("GET", "POST"))
func BasicAuth ¶
func BasicAuth(cfg BasicAuthConfig) MiddlewareFunc
BasicAuth returns middleware that requires HTTP Basic credentials. Passwords are compared in constant time. If the realm is empty it defaults to "Restricted".
s.Router.Use(core.BasicAuth(core.BasicAuthConfig{
Users: map[string]string{"admin": "secret"},
Realm: "Admin Panel",
}))
func BodyLimit ¶
func BodyLimit(maxBytes int64) MiddlewareFunc
BodyLimit returns middleware that rejects bodies larger than maxBytes with 413 Payload Too Large. It checks Content-Length first, then the actual body length.
s.Router.Use(core.BodyLimit(10 << 20)) // 10 MiB
func CORS ¶
func CORS(config CORSConfig) MiddlewareFunc
CORS returns a one-shot middleware from a static CORSConfig. For runtime-updatable CORS use NewCORSEngine + CORSEngine.Middleware.
s.Router.Use(core.CORS(core.CORSConfig{
AllowOrigins: []string{"*"},
AllowMethods: []string{"GET", "POST"},
}))
func Compress ¶
func Compress(cfg CompressConfig) MiddlewareFunc
Compress returns middleware that gzip- or deflate-compresses response bodies based on the client's Accept-Encoding header. Responses below MinSize bytes or already streamed are left untouched.
s.Router.Use(core.Compress(core.CompressConfig{Level: 6, MinSize: 512}))
func Header ¶
func Header(name, value string) MiddlewareFunc
Header returns middleware that sets a fixed response header on every request.
s.Router.Use(core.Header("X-Powered-By", "ALOS"))
func If ¶
func If(predicate func(*Request) bool, inner MiddlewareFunc) MiddlewareFunc
If returns middleware that conditionally applies inner only when predicate returns true for the current request.
s.Router.Use(core.If(
func(req *core.Request) bool { return req.Path != "/health" },
core.Logger(),
))
func Logger ¶
func Logger() MiddlewareFunc
Logger returns middleware that logs every request with method, path, status code, and elapsed time to the standard logger.
s.Router.Use(core.Logger())
func RealIP ¶
func RealIP(trustedProxies ...string) MiddlewareFunc
RealIP returns middleware that overwrites req.RemoteAddr with the value from X-Forwarded-For or X-Real-IP headers. When trustedProxies is non-empty, the header is only trusted if the direct client IP matches one of the listed CIDRs or IPs. When trustedProxies is empty, the header is always trusted — only use this behind a known proxy.
s.Router.Use(core.RealIP("10.0.0.0/8", "172.16.0.0/12"))
func Recovery ¶
func Recovery() MiddlewareFunc
Recovery returns middleware that catches panics in downstream handlers and responds with 500 Internal Server Error instead of crashing the process. Always register it first in the middleware chain.
s.Router.Use(core.Recovery())
func RequestID ¶
func RequestID() MiddlewareFunc
RequestID returns middleware that assigns a monotonically increasing integer ID to each request via the X-Request-ID response header.
s.Router.Use(core.RequestID())
func SecurityHeaders ¶
func SecurityHeaders(cfg SecurityHeadersConfig) MiddlewareFunc
SecurityHeaders returns middleware that injects the configured security headers into every response.
s.Router.Use(core.SecurityHeaders(core.DefaultSecurityHeaders()))
func Timeout ¶
func Timeout(d time.Duration) MiddlewareFunc
Timeout returns middleware that aborts the handler if it takes longer than d. The client receives a 504 Gateway Timeout.
s.Router.Use(core.Timeout(10 * time.Second))
type Param ¶
Param stores one route parameter extracted during routing.
r.GET("/users/:id", func(req *core.Request, resp *core.Response) {
id := req.Params[0].Value
resp.String(id)
})
r.GET("/teams/:team/users/:user", func(req *core.Request, resp *core.Response) {
team := req.Params[0].Value
user := req.Params[1].Value
resp.String(team + ":" + user)
})
type ParsedClientHello ¶
type ParsedClientHello struct {
SessionID []byte
CipherSuites []uint16
X25519PubKey []byte
ALPNProtos []string
ServerName string
SupportedVersions []uint16
// contains filtered or unexported fields
}
func (*ParsedClientHello) Reset ¶
func (ch *ParsedClientHello) Reset()
func (*ParsedClientHello) SupportsTLS13 ¶
func (ch *ParsedClientHello) SupportsTLS13() bool
type PlainH1StreamWriter ¶
type PlainH1StreamWriter struct {
// contains filtered or unexported fields
}
func (*PlainH1StreamWriter) Close ¶
func (w *PlainH1StreamWriter) Close() error
func (*PlainH1StreamWriter) Flush ¶
func (w *PlainH1StreamWriter) Flush() error
func (*PlainH1StreamWriter) WriteChunk ¶
func (w *PlainH1StreamWriter) WriteChunk(data []byte) error
func (*PlainH1StreamWriter) WriteHeader ¶
func (w *PlainH1StreamWriter) WriteHeader(statusCode int, headers [][2]string, contentType string) error
type ProxyCache ¶
type ProxyCache struct {
// contains filtered or unexported fields
}
func NewProxyCache ¶
func NewProxyCache(cfg ProxyCacheConfig) *ProxyCache
func (*ProxyCache) Get ¶
func (pc *ProxyCache) Get(method, host, path, acceptEncoding string) (*cacheEntry, bool)
func (*ProxyCache) Purge ¶
func (pc *ProxyCache) Purge(method, host, path string) bool
func (*ProxyCache) PurgeAll ¶
func (pc *ProxyCache) PurgeAll()
func (*ProxyCache) PurgeDomain ¶
func (pc *ProxyCache) PurgeDomain(domain string) int64
func (*ProxyCache) ServeCached ¶
func (pc *ProxyCache) ServeCached(entry *cacheEntry, req *Request, resp *Response)
func (*ProxyCache) Stats ¶
func (pc *ProxyCache) Stats() (entries int64, totalBytes int64, hits uint64, misses uint64)
func (*ProxyCache) Stop ¶
func (pc *ProxyCache) Stop()
func (*ProxyCache) UpdateConfig ¶
func (pc *ProxyCache) UpdateConfig(cfg ProxyCacheConfig)
type ProxyCacheConfig ¶
type ProxyCacheConfig struct {
Rules []CacheRule
MaxEntrySize int64
DefaultMaxAge time.Duration
MaxTotalBytes int64
MaxEntries int64
StaleWhileRev time.Duration
PreCompress bool
CompressLevel int
CompressMinLen int
}
ProxyCacheConfig controls how the reverse proxy caches backend responses.
cfg := core.DefaultProxyCacheConfig()
cfg.MaxTotalBytes = 512 << 20 // 512 MB total cache
cfg.MaxEntrySize = 8 << 20 // 8 MB max per entry
cfg.DefaultMaxAge = 10 * time.Minute
cfg.PreCompress = true // pre-gzip cached entries
cfg.Rules = []core.CacheRule{
{PathPrefix: "/static/", MaxAge: time.Hour},
{PathPrefix: "/api/", MaxAge: 30 * time.Second, StatusOnly: []int{200}},
}
srv.SetProxyCache(cfg)
func DefaultProxyCacheConfig ¶
func DefaultProxyCacheConfig() ProxyCacheConfig
DefaultProxyCacheConfig returns a ProxyCacheConfig with sensible defaults: 4 MB max entry, 5 minute TTL, 256 MB total, 10k entries, gzip compression at level 6 for responses >= 512 bytes.
type ProxyEngine ¶
type ProxyEngine struct {
OnError ProxyErrorFunc
OnRequest ProxyInterceptFunc
OnResponse ProxyResponseFunc
Cache *ProxyCache
// contains filtered or unexported fields
}
ProxyEngine is the core reverse-proxy component that routes incoming TLS connections to upstream backends based on the SNI domain. It manages connection pools, load balancing, health checking, and optional response caching across all registered domains.
Hook into the proxy lifecycle with:
- OnError: called when a backend request fails (connection error, timeout)
- OnRequest: called before forwarding; modify headers/path or reject
- OnResponse: called after the backend replies; modify headers/status or cache
ProxyEngine is created internally by the Server. Use Server.OnProxyError, Server.OnProxyRequest, and Server.OnProxyResponse to register callbacks.
func NewProxyEngine ¶
func NewProxyEngine() *ProxyEngine
NewProxyEngine creates a ProxyEngine with an empty domain table. This is called internally by Server.New — you typically don't need to call it directly.
func (*ProxyEngine) AddDomain ¶
func (pe *ProxyEngine) AddDomain(cfg DomainConfig)
AddDomain registers or replaces a domain configuration. If a domain with the same name already exists, its health checkers and connection pools are shut down before the new config takes effect. Safe to call at runtime while the server is handling traffic — the swap is atomic.
pe.AddDomain(core.DomainConfig{
Domain: "api.example.com",
Backends: []core.BackendConfig{{Addr: "10.0.0.10:8080"}},
})
func (*ProxyEngine) ListDomains ¶
func (pe *ProxyEngine) ListDomains() []string
ListDomains returns the names of all currently registered proxy domains. The order is non-deterministic.
func (*ProxyEngine) Lookup ¶
func (pe *ProxyEngine) Lookup(host string) *domainState
func (*ProxyEngine) RemoveDomain ¶
func (pe *ProxyEngine) RemoveDomain(domain string)
RemoveDomain removes a domain by name and gracefully shuts down its health checkers and connection pools. No-op if the domain doesn't exist. Safe to call at runtime.
func (*ProxyEngine) Stop ¶
func (pe *ProxyEngine) Stop()
Stop shuts down all health checkers and closes all idle backend connections across every registered domain. Called automatically by Server.Shutdown.
type ProxyError ¶
type ProxyError struct {
Domain string
Backend string
ClientAddr string
Method string
Path string
Attempt int
Err error
}
ProxyError holds context about a failed backend request. It is passed to the OnError callback registered with Server.OnProxyError. Domain and Backend identify which upstream was tried, Attempt indicates which retry this was (starting at 1), and Err contains the underlying network or timeout error.
srv.OnProxyError(func(pe core.ProxyError) {
log.Printf("proxy error domain=%s backend=%s attempt=%d err=%v",
pe.Domain, pe.Backend, pe.Attempt, pe.Err)
})
type ProxyErrorFunc ¶
type ProxyErrorFunc func(ProxyError)
type ProxyInterceptFunc ¶
type ProxyInterceptFunc func(pr *ProxyRequest) bool
type ProxyRequest ¶
type ProxyRequest struct {
Domain string
Backend string
ClientAddr string
Method string
Path string
Headers [][2]string
Host string
}
ProxyRequest is passed to the OnRequest callback before the request is forwarded to the backend. You can inspect or modify Headers, Host, and Path to rewrite the outgoing request. Returning false from the callback rejects the request with a 502 Bad Gateway.
Common use cases:
Inject authentication headers for internal backends
Rewrite paths (e.g. strip a /api prefix)
Block requests based on client IP or headers
srv.OnProxyRequest(func(pr *core.ProxyRequest) bool { // Add internal auth header pr.Headers = append(pr.Headers, [2]string{"X-Internal-Auth", "secret"})
// Strip /api prefix if len(pr.Path) > 4 && pr.Path[:4] == "/api" { pr.Path = pr.Path[4:] } return true })
type ProxyResponse ¶
type ProxyResponse struct {
Domain string
Backend string
ClientAddr string
Method string
Path string
StatusCode int
Headers [][2]string
// contains filtered or unexported fields
}
ProxyResponse is passed to the OnResponse callback after the backend replies but before the response is sent to the client. You can modify Headers and StatusCode to transform what the client receives. Use CacheThis to opt this response into the proxy cache with a specific TTL and hit limit, or DontCache to explicitly skip caching even if a cache rule would match.
srv.OnProxyResponse(func(pr *core.ProxyResponse) {
// Inject a custom header
pr.Headers = append(pr.Headers, [2]string{"X-Proxy", "alos"})
// Cache successful API responses for 5 minutes
if pr.StatusCode == 200 && len(pr.Path) > 4 && pr.Path[:4] == "/api" {
pr.CacheThis(5*time.Minute, 0)
}
// Never cache error responses
if pr.StatusCode >= 400 {
pr.DontCache()
}
})
func (*ProxyResponse) CacheThis ¶
func (pr *ProxyResponse) CacheThis(ttl time.Duration, maxHits uint64, opts ...CacheOption)
CacheThis marks this response for caching with the given TTL. The entry is evicted after ttl elapses or after maxHits cache hits, whichever comes first. Pass 0 for maxHits to keep the entry alive until TTL expiration only.
Optional CacheOption values control gzip pre-compression of the cached body. By default, a gzip copy is stored for responses >= 512 bytes.
// Cache for 10 minutes, unlimited hits pr.CacheThis(10*time.Minute, 0) // Cache for 1 hour, evict after 1000 hits pr.CacheThis(time.Hour, 1000) // Cache without pre-compression pr.CacheThis(5*time.Minute, 0, core.WithPreCompress(false))
func (*ProxyResponse) DontCache ¶
func (pr *ProxyResponse) DontCache()
DontCache prevents this specific response from being cached, overriding any cache rules that would otherwise match. Call this in OnResponse for responses that should never be stored (e.g. user-specific data, error pages).
if pr.StatusCode >= 400 {
pr.DontCache()
}
type ProxyResponseFunc ¶
type ProxyResponseFunc func(pr *ProxyResponse)
type RateLimitEngine ¶
type RateLimitEngine struct {
OnLimit RateLimitFunc
// contains filtered or unexported fields
}
RateLimitEngine tracks per-client request counts against configured rules. It uses lock-free atomics for counters and a sharded map for client state. The engine runs a background goroutine that cleans up stale entries every 30 seconds.
func NewRateLimitEngine ¶
func NewRateLimitEngine() *RateLimitEngine
NewRateLimitEngine creates a new rate limiter with an empty rule set and starts the background cleanup goroutine. Call Stop when the engine is no longer needed.
func (*RateLimitEngine) AddRule ¶
func (rle *RateLimitEngine) AddRule(rule RateLimitRule)
func (*RateLimitEngine) RemoveRule ¶
func (rle *RateLimitEngine) RemoveRule(path string)
func (*RateLimitEngine) SetRules ¶
func (rle *RateLimitEngine) SetRules(rules []RateLimitRule)
func (*RateLimitEngine) Stop ¶
func (rle *RateLimitEngine) Stop()
type RateLimitEvent ¶
type RateLimitEvent struct {
IP string
Path string
Rule RateLimitRule
RetryAfter time.Duration
}
RateLimitEvent is passed to the OnLimit callback when a request is rate-limited. It contains the client IP, request path, the matched rule, and how long the client should wait before retrying.
type RateLimitFunc ¶
type RateLimitFunc func(event RateLimitEvent, req *Request, resp *Response) bool
type RateLimitRule ¶
type RateLimitRule struct {
Path string
MaxReqs int64
Window time.Duration
BlockFor time.Duration
OnLimit RateLimitFunc
}
RateLimitRule defines a rate limit for a specific path pattern. Path can be an exact path, a prefix ending in * (wildcard), or a regex prefixed with ~.
// Exact path: 100 requests per minute, block for 5 minutes on exceed
core.RateLimitRule{
Path: "/api/login",
MaxReqs: 100,
Window: time.Minute,
BlockFor: 5 * time.Minute,
}
// Prefix wildcard: anything under /api/
core.RateLimitRule{
Path: "/api/*",
MaxReqs: 1000,
Window: time.Minute,
}
// Regex: match /users/{digits}
core.RateLimitRule{
Path: "~^/users/[0-9]+$",
MaxReqs: 50,
Window: time.Minute,
}
type Request ¶
type Request struct {
Method string
Path string
Proto string
Host string
RemoteAddr string
Headers [][2]string
Body []byte
StreamID uint32
IsH2 bool
Params [8]Param
ParamCount int
StreamWriter StreamWriter
// contains filtered or unexported fields
}
Request is the handler-facing view of an incoming request.
srv.Router.GET("/users/:id", func(req *core.Request, resp *core.Response) {
resp.String(req.Method + " " + req.Path + " for " + req.ParamValue("id"))
})
srv.Router.POST("/echo", func(req *core.Request, resp *core.Response) {
ct := req.Header("Content-Type")
resp.SetHeader("X-Seen-Content-Type", ct)
resp.Bytes(req.Body)
})
srv.Router.GET("/conn", func(req *core.Request, resp *core.Response) {
resp.String(req.RemoteAddr)
})
func (*Request) Header ¶
Header returns the first matching request header using ASCII case folding.
auth := req.Header("Authorization")
contentType := req.Header("content-type")
origin := req.Header("Origin")
func (*Request) HijackConn ¶
HijackConn hands the connection to the handler for protocols that need raw I/O.
srv.Router.GET("/raw", func(req *core.Request, resp *core.Response) {
conn := req.HijackConn()
if conn == nil {
resp.Status(500).String("hijack failed")
return
}
defer conn.Close()
_, _ = conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nraw"))
})
func (*Request) ParamValue ¶
ParamValue returns a named route parameter.
r.GET("/users/:id", func(req *core.Request, resp *core.Response) {
resp.String(req.ParamValue("id"))
})
r.GET("/users/:id/posts/:postID", func(req *core.Request, resp *core.Response) {
resp.String(req.ParamValue("id") + "/" + req.ParamValue("postID"))
})
type Response ¶
type Response struct {
StatusCode int
Headers [][2]string
ContentType string
// contains filtered or unexported fields
}
Response is the mutable response object passed to every handler.
srv.Router.GET("/text", func(req *core.Request, resp *core.Response) {
resp.Status(200).String("hello")
})
srv.Router.GET("/json", func(req *core.Request, resp *core.Response) {
resp.Status(200).
SetHeader("Cache-Control", "no-store").
JSONString(`{"ok":true}`)
})
srv.Router.GET("/binary", func(req *core.Request, resp *core.Response) {
resp.Status(200).Bytes([]byte{0x41, 0x4c, 0x4f, 0x53})
})
func (*Response) Bytes ¶
Bytes writes raw bytes as application/octet-stream.
resp.Status(200).Bytes(fileData)
func (*Response) GetBody ¶
GetBody returns the current in-memory response body.
body := resp.GetBody()
func (*Response) HTML ¶
HTML writes an HTML response body.
resp.Status(200).HTML("<h1>Welcome</h1>")
func (*Response) IsStreamed ¶
func (*Response) JSON ¶
JSON writes already-encoded JSON bytes.
resp.Status(200).JSON([]byte(`{"users":[]}`))
resp.JSON(payload)
func (*Response) JSONMarshal ¶
JSONMarshal marshals a value with sonic and writes the result as JSON.
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
_ = resp.Status(200).JSONMarshal(User{ID: 1, Name: "Alice"})
_ = resp.JSONMarshal(map[string]any{"ok": true})
func (*Response) JSONString ¶
JSONString writes JSON from a string literal or prebuilt string.
resp.Status(200).JSONString(`{"ok":true}`)
func (*Response) SendFile ¶
func (r *Response) SendFile(path string, opts ...SendFileOption) error
SendFile streams a file to the client with automatic MIME type detection, optional download attachment headers, and optional bandwidth rate limiting. The path is sanitized to prevent directory traversal.
// Serve a file inline:
resp.SendFile("static/image.png")
// Force download with a custom filename:
resp.SendFile("data/report.csv",
core.WithAttachment("report-2024.csv"))
// Rate-limit to 10 Mbps:
resp.SendFile("videos/demo.mp4",
core.WithRateLimit(10),
core.WithAttachment("demo.mp4"))
func (*Response) SetBody ¶
SetBody replaces the body without changing the current content type.
resp.ContentType = "application/xml"
resp.SetBody([]byte("<ok/>"))
func (*Response) SetHeader ¶
SetHeader appends a sanitized response header.
resp.SetHeader("Cache-Control", "no-store")
resp.SetHeader("X-Frame-Options", "DENY")
resp.SetHeader("X-Request-ID", "req-42")
func (*Response) SetHeaderUnsafe ¶
SetHeaderUnsafe appends a trusted response header without sanitization.
resp.SetHeaderUnsafe("Server", "ALOS")
func (*Response) SetSW ¶
func (r *Response) SetSW(sw StreamWriter)
func (*Response) SetStreamer ¶
func (r *Response) SetStreamer(sw StreamWriter)
func (*Response) Status ¶
Status sets the response status code and returns the same Response.
resp.Status(201).String("created")
resp.Status(404).JSONString(`{"error":"not found"}`)
func (*Response) Streamer ¶
func (r *Response) Streamer() StreamWriter
type RouteGroup ¶
type RouteGroup struct {
// contains filtered or unexported fields
}
RouteGroup is a collection of routes that share a common path prefix and middleware stack. Create one with Router.Group.
api := r.Group("/api/v1", authMiddleware)
api.GET("/users", listUsers)
api.POST("/users", createUser)
admin := api.Group("/admin", adminOnly)
admin.DELETE("/users/:id", deleteUser)
func (*RouteGroup) ANY ¶
func (g *RouteGroup) ANY(path string, handler HandlerFunc)
ANY registers a handler for all HTTP methods on the group.
func (*RouteGroup) DELETE ¶
func (g *RouteGroup) DELETE(path string, handler HandlerFunc)
DELETE registers a DELETE handler on the group.
func (*RouteGroup) GET ¶
func (g *RouteGroup) GET(path string, handler HandlerFunc)
GET registers a GET handler on the group.
func (*RouteGroup) Group ¶
func (g *RouteGroup) Group(prefix string, middleware ...MiddlewareFunc) *RouteGroup
Group creates a nested sub-group inheriting the parent's prefix and middleware.
v1 := r.Group("/v1")
admin := v1.Group("/admin", adminAuth)
admin.GET("/stats", statsHandler) // matches /v1/admin/stats
func (*RouteGroup) HEAD ¶
func (g *RouteGroup) HEAD(path string, handler HandlerFunc)
HEAD registers a HEAD handler on the group.
func (*RouteGroup) OPTIONS ¶
func (g *RouteGroup) OPTIONS(path string, handler HandlerFunc)
OPTIONS registers an OPTIONS handler on the group.
func (*RouteGroup) PATCH ¶
func (g *RouteGroup) PATCH(path string, handler HandlerFunc)
PATCH registers a PATCH handler on the group.
func (*RouteGroup) POST ¶
func (g *RouteGroup) POST(path string, handler HandlerFunc)
POST registers a POST handler on the group.
func (*RouteGroup) PUT ¶
func (g *RouteGroup) PUT(path string, handler HandlerFunc)
PUT registers a PUT handler on the group.
func (*RouteGroup) Use ¶
func (g *RouteGroup) Use(middleware ...MiddlewareFunc)
Use adds middleware to the group. These run after any middleware passed to Group and before the route handler.
type Router ¶
type Router struct {
// contains filtered or unexported fields
}
func NewRouter ¶
func NewRouter() *Router
NewRouter creates a new Router with default 404 and 405 handlers. Register routes with the HTTP method helpers (GET, POST, PUT, DELETE, etc.) then call Build before passing the router to the server.
r := core.NewRouter()
r.GET("/", indexHandler)
r.Build()
func (*Router) ANY ¶
func (r *Router) ANY(path string, handler HandlerFunc)
ANY registers a handler that matches all HTTP methods (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, CONNECT, TRACE) at the given path.
r.ANY("/health", func(req *core.Request, resp *core.Response) {
resp.Status(200).String("ok")
})
func (*Router) Build ¶
func (r *Router) Build()
Build pre-compiles the routing table by wrapping all handlers with global middleware and building index lookup tables. Call this once after all routes and middleware are registered, before the server starts handling requests.
r.GET("/", indexHandler)
r.Use(core.Logger)
r.Build()
func (*Router) DELETE ¶
func (r *Router) DELETE(path string, handler HandlerFunc)
DELETE registers a handler for DELETE requests at the given path.
func (*Router) GET ¶
func (r *Router) GET(path string, handler HandlerFunc)
GET registers a handler for GET requests at the given path.
func (*Router) Group ¶
func (r *Router) Group(prefix string, middleware ...MiddlewareFunc) *RouteGroup
Group creates a new RouteGroup with the given path prefix and optional middleware. All routes registered on the group inherit the prefix and middleware chain.
api := r.Group("/api/v1")
api.Use(rateLimiter)
api.GET("/items", listItems)
func (*Router) HEAD ¶
func (r *Router) HEAD(path string, handler HandlerFunc)
HEAD registers a handler for HEAD requests at the given path.
func (*Router) Handle ¶
func (r *Router) Handle(method, path string, handler HandlerFunc)
Handle registers a handler for the given HTTP method and path pattern. Path patterns can include named parameters (:param) and catch-all segments (*name).
r.Handle("GET", "/users/:id", getUser)
r.Handle("GET", "/files/*filepath", serveFiles)
func (*Router) Lookup ¶
func (r *Router) Lookup(method, path string, req *Request) HandlerFunc
Lookup finds the handler for the given method and path, populating any path parameters on the Request. Returns the not-found or method-not-allowed handler when no exact match exists. This is called internally by the server for each incoming request.
func (*Router) Match ¶
Match reports whether a route exists for the given method and path without executing the handler. Useful for testing route registration.
if r.Match("GET", "/api/users") {
fmt.Println("route exists")
}
func (*Router) MethodNotAllowed ¶
func (r *Router) MethodNotAllowed(handler HandlerFunc)
MethodNotAllowed sets a custom handler that runs when a route exists but not for the requested HTTP method.
func (*Router) NotFound ¶
func (r *Router) NotFound(handler HandlerFunc)
NotFound sets a custom handler that runs when no route matches the request path.
r.NotFound(func(req *core.Request, resp *core.Response) {
resp.Status(404).JSON([]byte(`{"error":"not found"}`))
})
func (*Router) OPTIONS ¶
func (r *Router) OPTIONS(path string, handler HandlerFunc)
OPTIONS registers a handler for OPTIONS requests at the given path.
func (*Router) PATCH ¶
func (r *Router) PATCH(path string, handler HandlerFunc)
PATCH registers a handler for PATCH requests at the given path.
func (*Router) POST ¶
func (r *Router) POST(path string, handler HandlerFunc)
POST registers a handler for POST requests at the given path.
func (*Router) PUT ¶
func (r *Router) PUT(path string, handler HandlerFunc)
PUT registers a handler for PUT requests at the given path.
func (*Router) Use ¶
func (r *Router) Use(middleware ...MiddlewareFunc)
Use registers one or more global middleware functions that run on every request in the order they are added.
r.Use(core.Logger, core.Recovery)
r.Use(core.CORS(core.NewCORSEngine(core.CORSConfig{
AllowOrigins: []string{"*"},
})))
type SecurityHeadersConfig ¶
type SecurityHeadersConfig struct {
ContentTypeNosniff bool
XFrameOptions string
XSSProtection bool
HSTSMaxAge int
HSTSSubdomains bool
HSTSPreload bool
ReferrerPolicy string
}
SecurityHeadersConfig controls which security-related headers are injected into every response.
cfg := core.SecurityHeadersConfig{
ContentTypeNosniff: true,
XFrameOptions: "DENY",
XSSProtection: true,
HSTSMaxAge: 63072000,
HSTSSubdomains: true,
HSTSPreload: true,
ReferrerPolicy: "strict-origin-when-cross-origin",
}
func DefaultSecurityHeaders ¶
func DefaultSecurityHeaders() SecurityHeadersConfig
DefaultSecurityHeaders returns a SecurityHeadersConfig with all protections enabled: nosniff, DENY framing, XSS filter, 2-year HSTS with includeSubDomains and preload, and strict-origin-when-cross-origin referrer policy.
type SendFileOption ¶
type SendFileOption func(*sendFileConfig)
func WithAttachment ¶
func WithAttachment(filename string) SendFileOption
WithAttachment sets the Content-Disposition header to "attachment" with the given filename, triggering a file download in the browser.
resp.SendFile("data/export.csv", core.WithAttachment("export-2024.csv"))
func WithContentType ¶
func WithContentType(ct string) SendFileOption
WithContentType overrides the auto-detected MIME type for the file.
resp.SendFile("data.bin", core.WithContentType("application/pdf"))
func WithRateLimit ¶
func WithRateLimit(mbps int64) SendFileOption
WithRateLimit caps the file transfer speed to the given rate in megabits per second and sets the burst size equal to the rate. Valid range is 1-250000 Mbps.
resp.SendFile("video.mp4", core.WithRateLimit(50)) // 50 Mbps
func WithRateLimitBurst ¶
func WithRateLimitBurst(mbps, burstMbps int64) SendFileOption
WithRateLimitBurst is like WithRateLimit but also sets a separate burst size in Mbps, allowing short bursts above the steady-state rate.
resp.SendFile("file.zip", core.WithRateLimitBurst(10, 50)) // 10 Mbps steady, 50 Mbps burst
type Server ¶
type Server struct {
Router *Router
CORS *CORSEngine
RateLimit *RateLimitEngine
// contains filtered or unexported fields
}
Server is the main entry point. Create one with New, configure routes on its Router field, then call ListenAndServeTLS or ListenAndServe.
s := core.New(core.Config{Addr: ":443"})
s.Router.GET("/", handler)
log.Fatal(s.ListenAndServeTLS())
The Server manages its own TLS 1.3 implementation, optional HTTP/2 multiplexing, connection pooling, reverse proxy, CORS, rate limiting, and ACME. All public methods are safe for concurrent use.
func New ¶
New creates a Server with the given Config. When called without arguments it uses DefaultConfig. The returned server is ready for route registration; call ListenAndServeTLS or ListenAndServe to start accepting connections.
s := core.New(core.Config{
Addr: ":443",
PlainHTTP: false,
Listeners: 4,
})
s.Router.GET("/hello", func(req *core.Request, resp *core.Response) {
resp.Status(200).String("hello")
})
log.Fatal(s.ListenAndServeTLS())
func (*Server) AddACMEDomain ¶
func (*Server) AddCertFromFiles ¶
func (*Server) AddDomainCert ¶
func (*Server) AddHTTPRoute ¶
func (*Server) AddProxyDomain ¶
func (s *Server) AddProxyDomain(cfg DomainConfig)
AddProxyDomain registers a reverse-proxy domain. If the ProxyEngine does not exist yet it is created automatically. Safe to call at runtime.
s.AddProxyDomain(core.DomainConfig{
Domain: "api.example.com",
Backends: []core.BackendConfig{
{Addr: "10.0.0.1:8080", Weight: 3},
{Addr: "10.0.0.2:8080", Weight: 1},
},
Balancer: core.LBWeightedRR,
MaxRetries: 2,
HealthCheck: core.HealthCheckConfig{
Path: "/health",
Interval: 10 * time.Second,
Timeout: 2 * time.Second,
},
})
func (*Server) AddRateLimitRule ¶
func (s *Server) AddRateLimitRule(rule RateLimitRule)
AddRateLimitRule appends a single rule without replacing existing ones.
func (*Server) AddSelfSignedCert ¶
func (*Server) EnableACME ¶
func (s *Server) EnableACME(cfg ACMEConfig)
func (*Server) FineTuneWithOptions ¶
func (s *Server) FineTuneWithOptions(options FineTuneOptions) (*FineTuneReport, error)
func (*Server) ListenAndServe ¶
ListenAndServe starts a plain HTTP/1.1 server (no TLS). Use this when Config.PlainHTTP is true or when TLS termination is handled upstream.
s := core.New(core.Config{Addr: ":80", PlainHTTP: true})
s.Router.GET("/", handler)
log.Fatal(s.ListenAndServe())
func (*Server) ListenAndServeTLS ¶
ListenAndServeTLS starts the HTTPS server with ALOS's built-in TLS 1.3 stack. It loads certificates (self-signed, manual PEM, or ACME), opens the configured number of SO_REUSEPORT listeners, optionally advertises HTTP/2 depending on Config.DisableHTTP2, starts the HTTP-to-HTTPS redirect listener, and blocks until Shutdown is called or an unrecoverable error occurs.
log.Fatal(s.ListenAndServeTLS())
func (*Server) NewH1StreamWriter ¶
func (s *Server) NewH1StreamWriter(conn net.Conn, writer *TrafficAEAD) *H1StreamWriter
func (*Server) NewH2StreamWriter ¶
func (*Server) NewPlainH1StreamWriter ¶
func (s *Server) NewPlainH1StreamWriter(conn net.Conn) *PlainH1StreamWriter
func (*Server) OnProxyError ¶
func (s *Server) OnProxyError(fn ProxyErrorFunc)
OnProxyError registers a callback invoked whenever a backend request fails. Use it for alerting or structured logging.
s.OnProxyError(func(pe core.ProxyError) {
log.Printf("proxy error: domain=%s backend=%s err=%v",
pe.Domain, pe.Backend, pe.Err)
})
func (*Server) OnProxyRequest ¶
func (s *Server) OnProxyRequest(fn ProxyInterceptFunc)
OnProxyRequest registers a callback invoked before the request is forwarded to a backend. Modify pr.Headers or pr.Host to alter the outgoing request. Return false to reject with 502.
s.OnProxyRequest(func(pr *core.ProxyRequest) bool {
pr.Headers = append(pr.Headers, [2]string{"X-Forwarded-For", pr.ClientAddr})
return true
})
func (*Server) OnProxyResponse ¶
func (s *Server) OnProxyResponse(fn ProxyResponseFunc)
OnProxyResponse registers a callback invoked after a backend responds (or a cache hit is served). Modify pr.Headers or pr.StatusCode before they reach the client. Call pr.CacheThis() to store the response.
s.OnProxyResponse(func(pr *core.ProxyResponse) {
pr.Headers = append(pr.Headers, [2]string{"X-Proxy-By", "ALOS"})
})
func (*Server) OnRateLimit ¶
func (s *Server) OnRateLimit(fn RateLimitFunc)
OnRateLimit registers a global callback invoked when a request is rate-limited. Return true to indicate the response has been handled, or false to fall through to the default 429 response.
s.OnRateLimit(func(event core.RateLimitEvent, req *core.Request, resp *core.Response) bool {
resp.Status(429).JSON([]byte(`{"error":"too many requests"}`))
return true
})
func (*Server) Proxy ¶
func (s *Server) Proxy() *ProxyEngine
func (*Server) ProxyCacheStats ¶
ProxyCacheStats returns current cache metrics: number of entries, total bytes used, cumulative hits, and cumulative misses.
func (*Server) PurgeAllProxyCache ¶
func (s *Server) PurgeAllProxyCache()
PurgeAllProxyCache drops every entry in the response cache.
func (*Server) PurgeDomainCache ¶
PurgeDomainCache removes all cached responses for the given domain. Returns the number of entries purged.
func (*Server) PurgeProxyCache ¶
PurgeProxyCache removes a single cached response by method, host, and path. Returns true if an entry was found and removed.
func (*Server) ReloadCert ¶
func (*Server) RemoveCert ¶
func (*Server) RemoveHTTPRoute ¶
func (*Server) RemoveProxyDomain ¶
RemoveProxyDomain removes a domain and cleans up health checkers and connection pools for all its backends.
func (*Server) RemoveRateLimitRule ¶
RemoveRateLimitRule removes the rule matching the given path pattern.
func (*Server) ServeH1 ¶
func (s *Server) ServeH1(conn net.Conn, reader, writer *TrafficAEAD, hdrBuf []byte)
func (*Server) ServeH1Plain ¶
func (*Server) ServeH2 ¶
func (s *Server) ServeH2(conn net.Conn, reader, writer *TrafficAEAD, hdrBuf []byte)
func (*Server) ServeH2Plain ¶
func (*Server) SetCORS ¶
func (s *Server) SetCORS(cfg CORSConfig)
SetCORS configures CORS policy for the server.
s.SetCORS(core.CORSConfig{
AllowOrigins: []string{"https://example.com"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowHeaders: []string{"Content-Type", "Authorization"},
ExposeHeaders: []string{"X-Request-ID"},
AllowCredentials: true,
MaxAge: 86400,
})
func (*Server) SetDefaultCert ¶
func (*Server) SetHTTPRoutes ¶
SetHTTPRoutes configures port-80 HTTP routes that proxy plain HTTP traffic to backend servers (instead of 301-redirecting to HTTPS).
s.SetHTTPRoutes([]core.HTTPRoute{
{PathPrefix: "/api/", Backend: "10.0.0.5:3000"},
{PathPrefix: "/", Backend: "10.0.0.6:8080", HostHeader: "backend.local"},
})
func (*Server) SetLogRequests ¶
func (*Server) SetProxy ¶
func (s *Server) SetProxy(pe *ProxyEngine)
func (*Server) SetProxyCache ¶
func (s *Server) SetProxyCache(cfg ProxyCacheConfig)
SetProxyCache enables proxy response caching. Cached responses are matched by method + host + path (query string stripped). Configure per-path rules, total budget, entry size limits, and pre-compression.
s.SetProxyCache(core.ProxyCacheConfig{
MaxEntrySize: 4 << 20,
MaxTotalBytes: 256 << 20,
DefaultMaxAge: 5 * time.Minute,
PreCompress: true,
CompressLevel: 6,
CompressMinLen: 512,
Rules: []core.CacheRule{
{PathPrefix: "/api/", MaxAge: 30 * time.Second},
{PathPrefix: "/static/", MaxAge: 24 * time.Hour},
},
})
func (*Server) SetRateLimitRules ¶
func (s *Server) SetRateLimitRules(rules []RateLimitRule)
SetRateLimitRules replaces all rate-limit rules. Each rule matches a path pattern and enforces a request budget per client IP.
s.SetRateLimitRules([]core.RateLimitRule{
{Path: "/api/*", MaxReqs: 100, Window: 60 * time.Second, BlockFor: 5 * time.Minute},
{Path: "/*", MaxReqs: 300, Window: 60 * time.Second, BlockFor: 2 * time.Minute},
})
func (*Server) Shutdown ¶
Shutdown gracefully drains in-flight connections and stops ACME renewal, rate-limit cleanup, and listener goroutines. Pass a context with a deadline to bound how long the drain may take.
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := s.Shutdown(ctx); err != nil {
log.Printf("shutdown: %v", err)
}
func (*Server) UpdateCORS ¶
func (s *Server) UpdateCORS(cfg CORSConfig)
type ServerStats ¶
type ServerStats struct {
ActiveConns atomic.Int64
TotalConns atomic.Uint64
H2Conns atomic.Uint64
H1Conns atomic.Uint64
TotalReqs atomic.Uint64
BytesIn atomic.Uint64
BytesOut atomic.Uint64
// contains filtered or unexported fields
}
var Stats ServerStats
type ShardedMap ¶
type ShardedMap[K comparable, V any] struct { // contains filtered or unexported fields }
func NewShardedMap ¶
func NewShardedMap[K comparable, V any](hasher func(K) uint64) *ShardedMap[K, V]
func (*ShardedMap[K, V]) Delete ¶
func (s *ShardedMap[K, V]) Delete(key K)
func (*ShardedMap[K, V]) Load ¶
func (s *ShardedMap[K, V]) Load(key K) (V, bool)
func (*ShardedMap[K, V]) LoadOrStore ¶
func (s *ShardedMap[K, V]) LoadOrStore(key K, val V) (V, bool)
func (*ShardedMap[K, V]) Range ¶
func (s *ShardedMap[K, V]) Range(fn func(K, V) bool)
func (*ShardedMap[K, V]) Store ¶
func (s *ShardedMap[K, V]) Store(key K, val V)
type StreamWriter ¶
type TLSConn ¶
func NewTLSConn ¶
type TokenBucket ¶
type TokenBucket struct {
// contains filtered or unexported fields
}
func NewTokenBucket ¶
func NewTokenBucket(ratePerSec, burst int64) *TokenBucket
func (*TokenBucket) Allow ¶
func (tb *TokenBucket) Allow(tokens int64) bool
func (*TokenBucket) Wait ¶
func (tb *TokenBucket) Wait(tokens int64)
func (*TokenBucket) WaitWithDeadline ¶
func (tb *TokenBucket) WaitWithDeadline(tokens int64, deadline time.Time) bool
type TrafficAEAD ¶
type TrafficAEAD struct {
// contains filtered or unexported fields
}
func NewTrafficAEAD ¶
func NewTrafficAEAD(_ func() hash.Hash, secret []byte, cs *CipherSuiteConfig) (*TrafficAEAD, error)
func (*TrafficAEAD) Encrypt ¶
func (t *TrafficAEAD) Encrypt(plaintext []byte) []byte
func (*TrafficAEAD) EncryptAppend ¶
func (t *TrafficAEAD) EncryptAppend(dst, plaintext []byte) []byte
func (*TrafficAEAD) Overhead ¶
func (t *TrafficAEAD) Overhead() int
type WSConn ¶
type WSConn struct {
// contains filtered or unexported fields
}
WSConn is a server-side WebSocket connection (RFC 6455). Create one by calling UpgradeWebSocket inside a route handler, then use ReadMessage and WriteMessage (or WriteText / WriteBinary) to exchange data.
ws := core.UpgradeWebSocket(req, resp)
if ws == nil {
return
}
defer ws.Close()
for {
op, msg, err := ws.ReadMessage()
if err != nil {
break
}
ws.WriteText("echo: " + string(msg))
}
func UpgradeWebSocket ¶
UpgradeWebSocket performs the WebSocket handshake on the current request. It validates the required headers (Upgrade, Connection, Sec-WebSocket-Key, Sec-WebSocket-Version) and hijacks the underlying connection.
Returns a *WSConn on success, or nil if the handshake fails (in which case an error response is already written).
r.GET("/ws", func(req *core.Request, resp *core.Response) {
ws := core.UpgradeWebSocket(req, resp)
if ws == nil {
return
}
defer ws.Close()
for {
_, msg, err := ws.ReadMessage()
if err != nil {
break
}
ws.WriteText(string(msg))
}
})
func (*WSConn) Close ¶
Close sends a close frame and closes the underlying connection. Safe to call multiple times.
func (*WSConn) Ping ¶
Ping sends a WebSocket ping frame to the client. The client should respond with a pong automatically.
func (*WSConn) ReadMessage ¶
ReadMessage reads the next WebSocket frame. It returns the opcode (0x1 for text, 0x2 for binary), the payload, and any error. Close frames are handled automatically — a close reply is sent and io.EOF is returned. Ping frames trigger an automatic pong response.
func (*WSConn) SetDeadline ¶
SetDeadline sets the read and write deadline on the underlying connection.
func (*WSConn) WriteBinary ¶
WriteBinary sends a binary WebSocket frame.
func (*WSConn) WriteMessage ¶
WriteMessage writes a WebSocket frame with the given opcode and payload. Typically use WriteText or WriteBinary instead of calling this directly.
type WriteRequest ¶
Source Files
¶
- acme.go
- cert_store.go
- consts.go
- debug.go
- errors.go
- finetune.go
- h1.go
- h1_plain.go
- h2_conn.go
- h2_frame.go
- h2_stream.go
- hpack.go
- http_redirect.go
- json.go
- listener_linux.go
- middleware.go
- monotime.go
- pools.go
- proxy.go
- proxy_balance.go
- proxy_cache.go
- proxy_forward.go
- proxy_health.go
- proxy_pool.go
- ratelimit.go
- ratelimit_engine.go
- request.go
- response.go
- router.go
- rps.go
- runtime_tune_linux.go
- sendfile.go
- server.go
- shardmap.go
- socket_opts_linux.go
- stats.go
- stream.go
- tls_crypto.go
- tls_handshake.go
- tls_precompute.go
- tls_record.go
- uring_linux_amd64.go
- uring_modern_linux_amd64.go
- uring_plain_h2_linux_amd64.go
- uring_plain_workers_linux_amd64.go
- uring_probe_linux_amd64.go
- uring_tls_h2_native_linux_amd64.go
- uring_tls_h2_shared_linux_amd64.go
- uring_tls_workers_linux_amd64.go
- utils.go
- websocket.go
- x25519_pool.go