Documentation
¶
Overview ¶
Package celeris provides an ultra-low latency HTTP server with dual-architecture I/O (io_uring + epoll) and a high-level API for routing and request handling.
Quick Start ¶
s := celeris.New(celeris.Config{Addr: ":8080"})
s.GET("/hello", func(c *celeris.Context) error {
return c.String(200, "Hello, World!")
})
log.Fatal(s.Start())
Routing ¶
Routes support static paths, named parameters, and catch-all wildcards:
s.GET("/users/:id", handler) // /users/42 → Param("id") = "42"
s.GET("/files/*path", handler) // /files/a/b → Param("path") = "/a/b"
URL Parameters ¶
Access matched parameters by name. Type-safe parsing methods are available:
id := c.Param("id") // string
n, err := c.ParamInt("id") // int
n64, err := c.ParamInt64("id") // int64
Query parameters support defaults and multi-values:
page := c.Query("page") // string
page := c.QueryDefault("page", "1") // with default
limit := c.QueryInt("limit", 10) // int with default
tags := c.QueryValues("tag") // []string
all := c.QueryParams() // url.Values
raw := c.RawQuery() // raw query string
Route Groups ¶
api := s.Group("/api")
api.GET("/items", listItems)
Middleware ¶
Middleware is provided by the github.com/goceleris/middlewares module. Use Server.Use to register middleware globally or per route group.
s.Use(middlewares.Logger(), middlewares.Recovery())
To write custom middleware, use the HandlerFunc signature and call Context.Next to invoke downstream handlers. Next returns the first error from downstream, which middleware can handle or propagate:
func timing() celeris.HandlerFunc {
return func(c *celeris.Context) error {
start := time.Now()
err := c.Next()
elapsed := time.Since(start)
c.SetHeader("x-response-time", elapsed.String())
return err
}
}
Error Handling ¶
Handlers return errors. Unhandled errors are caught by the routerAdapter safety net: *HTTPError writes its Code+Message; bare errors write 500.
s.GET("/data", func(c *celeris.Context) error {
data, err := fetchData()
if err != nil {
return celeris.NewHTTPError(500, "fetch failed")
}
return c.JSON(200, data)
})
Middleware can intercept errors from downstream handlers:
s.Use(func(c *celeris.Context) error {
err := c.Next()
if err != nil {
log.Println("error:", err)
return c.JSON(500, map[string]string{"error": "internal"})
}
return nil
})
Custom 404 / 405 Handlers ¶
s.NotFound(func(c *celeris.Context) error {
return c.JSON(404, map[string]string{"error": "not found"})
})
s.MethodNotAllowed(func(c *celeris.Context) error {
return c.JSON(405, map[string]string{"error": "method not allowed"})
})
Graceful Shutdown ¶
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
s := celeris.New(celeris.Config{
Addr: ":8080",
ShutdownTimeout: 10 * time.Second,
})
s.GET("/ping", func(c *celeris.Context) error {
return c.String(200, "pong")
})
if err := s.StartWithContext(ctx); err != nil {
log.Fatal(err)
}
Engine Selection ¶
On Linux, choose between IOUring, Epoll, Adaptive, or Std engines. On other platforms, only Std is available.
s := celeris.New(celeris.Config{
Addr: ":8080",
Engine: celeris.Adaptive,
})
Protocol Selection ¶
The Protocol field controls HTTP version negotiation:
celeris.HTTP1 // HTTP/1.1 only (default) celeris.H2C // HTTP/2 cleartext (h2c) only celeris.Auto // Auto-detect: serves both HTTP/1.1 and H2C
Example:
s := celeris.New(celeris.Config{
Addr: ":8080",
Protocol: celeris.Auto,
})
net/http Compatibility ¶
Wrap existing net/http handlers. Response bodies from adapted handlers are buffered in memory (capped at 100 MB).
s.GET("/legacy", celeris.Adapt(legacyHandler))
Context Lifecycle ¶
Context objects are pooled and recycled between requests. Do not retain references to a *Context after the handler returns. Copy any needed values before returning. For the request body specifically, use Context.BodyCopy to obtain a copy that outlives the handler:
safe := c.BodyCopy() // safe to pass to a goroutine
When using Detach, the returned done function MUST be called — failure to do so permanently leaks the Context from the pool.
Observability ¶
The Server.Collector method returns an observe.Collector that records per-request metrics (throughput, latency histogram, error rate, active connections). Use Collector.Snapshot to retrieve a point-in-time copy:
snap := s.Collector().Snapshot() fmt.Println(snap.RequestsTotal, snap.ErrorsTotal)
For Prometheus or debug endpoint integration, see the github.com/goceleris/middlewares module.
Configuration ¶
Config.Workers controls the number of I/O workers (default: GOMAXPROCS). Config.ShutdownTimeout sets the graceful shutdown deadline for StartWithContext (default: 30s).
Named Routes & Reverse URLs ¶
Assign names to routes with Route.Name, then generate URLs via Server.URL:
s.GET("/users/:id", handler).Name("user")
url, _ := s.URL("user", "42") // "/users/42"
For catch-all routes the value replaces the wildcard segment:
s.GET("/files/*filepath", handler).Name("files")
url, _ := s.URL("files", "/css/style.css") // "/files/css/style.css"
Use Server.Routes to list all registered routes.
Form Handling ¶
Parse url-encoded and multipart form bodies:
name := c.FormValue("name")
all := c.FormValues("tags")
For file uploads, use FormFile or MultipartForm:
file, header, err := c.FormFile("avatar")
defer file.Close()
File Serving ¶
Serve static files with automatic content-type detection and Range support:
s.GET("/download", func(c *celeris.Context) error {
return c.File("/var/data/report.pdf")
})
Callers must sanitize user-supplied paths to prevent directory traversal.
Static File Serving ¶
Serve an entire directory under a URL prefix:
s.Static("/assets", "./public")
This is equivalent to:
s.GET("/assets/*filepath", func(c *celeris.Context) error {
return c.FileFromDir("./public", c.Param("filepath"))
})
Streaming ¶
For simple cases, stream an io.Reader as a buffered response (capped at 100 MB):
return c.Stream(200, "text/plain", reader)
For true incremental streaming (SSE, chunked responses), use StreamWriter with the Detach pattern:
s.GET("/events", func(c *celeris.Context) error {
sw := c.StreamWriter()
if sw == nil {
return c.String(200, "streaming not supported")
}
done := c.Detach()
sw.WriteHeader(200, [][2]string{{"content-type", "text/event-stream"}})
go func() {
defer done()
defer sw.Close()
for event := range events {
sw.Write([]byte("data: " + event + "\n\n"))
sw.Flush()
}
}()
return nil
})
StreamWriter returns nil if the engine does not support streaming. The std engine supports streaming; native engines (io_uring, epoll) will support it in a future release.
Cookies ¶
Read and write cookies:
val, err := c.Cookie("session")
c.SetCookie(&celeris.Cookie{Name: "session", Value: token, HTTPOnly: true})
Authentication ¶
Extract HTTP Basic Authentication credentials:
user, pass, ok := c.BasicAuth()
Request Body Parsing ¶
Bind auto-detects the format from Content-Type:
var user User
if err := c.Bind(&user); err != nil {
return err
}
Or use format-specific methods:
c.BindJSON(&user) // application/json c.BindXML(&user) // application/xml
For raw body access:
body := c.Body() // []byte, valid only during handler safe := c.BodyCopy() // []byte, safe to retain after handler r := c.BodyReader() // io.Reader wrapper
Response Methods ¶
Context provides typed response methods:
c.JSON(200, data) // application/json
c.XML(200, data) // application/xml
c.HTML(200, "<h1>Hello</h1>") // text/html
c.String(200, "Hello, %s", name) // text/plain (fmt.Sprintf)
c.Blob(200, "image/png", pngBytes) // arbitrary content type
c.NoContent(204) // status only, no body
c.Redirect(302, "/new-location") // redirect with Location header
c.File("/path/to/report.pdf") // file with MIME detection + Range
c.FileFromDir(baseDir, userPath) // safe file serving (traversal-safe)
c.Stream(200, "text/plain", reader) // io.Reader → response (100 MB cap)
c.Respond(200, data) // auto-format based on Accept header
All response methods return ErrResponseWritten if called after a response has already been sent.
Content Negotiation ¶
Inspect the Accept header and auto-select the response format:
best := c.Negotiate("application/json", "application/xml", "text/plain")
Or use Respond to auto-format based on Accept:
return c.Respond(200, myStruct) // JSON, XML, or text based on Accept
Accept Negotiation ¶
Beyond content type, negotiate encodings and languages:
enc := c.AcceptsEncodings("gzip", "br", "identity")
lang := c.AcceptsLanguages("en", "fr", "de")
Route-Level Middleware ¶
Attach middleware to individual routes without creating a group:
s.GET("/admin", adminHandler).Use(authMiddleware)
Route.Use inserts middleware before the final handler, after server/group middleware. Must be called before Server.Start.
Response Capture ¶
Middleware can inspect the response body after c.Next() by opting in:
func logger() celeris.HandlerFunc {
return func(c *celeris.Context) error {
c.CaptureResponse()
err := c.Next()
body := c.ResponseBody() // captured response body
ct := c.ResponseContentType() // captured Content-Type
// ... log body, ct ...
return err
}
}
Response Buffering ¶
Middleware that needs to transform response bodies (compress, ETag, cache) uses BufferResponse to intercept and modify the response before it is sent:
func compress() celeris.HandlerFunc {
return func(c *celeris.Context) error {
c.BufferResponse()
err := c.Next()
if err != nil {
return err
}
body := c.ResponseBody()
compressed := gzip(body)
c.SetResponseBody(compressed)
c.SetHeader("content-encoding", "gzip")
return c.FlushResponse()
}
}
BufferResponse is depth-tracked: multiple middleware layers can each call BufferResponse, and the response is only sent when the outermost layer calls FlushResponse. If middleware forgets to flush, a safety net in the handler adapter auto-flushes the response.
CaptureResponse and BufferResponse serve different purposes. CaptureResponse is read-only: the response is written to the wire AND a copy is captured for inspection (ideal for loggers). BufferResponse defers the wire write entirely, allowing middleware to transform the body before sending (ideal for compress, ETag, cache). If both are active, BufferResponse takes precedence.
Response Inspection ¶
Check response state from middleware after calling c.Next():
written := c.IsWritten() // true after response sent to wire size := c.BytesWritten() // response body size in bytes status := c.StatusCode() // status code set by handler status := c.ResponseStatus() // captured status (with BufferResponse) hdrs := c.RequestHeaders() // all request headers as [][2]string
Error Types ¶
Handlers signal HTTP errors via HTTPError:
return celeris.NewHTTPError(404, "user not found") return celeris.NewHTTPError(500, "db error").WithError(err) // wrap cause
Sentinel errors for common conditions:
celeris.ErrResponseWritten // response already sent celeris.ErrEmptyBody // Bind called with empty body celeris.ErrNoCookie // Cookie() with missing cookie celeris.ErrHijackNotSupported // Hijack on unsupported connection
Flow Control ¶
Middleware calls Next to invoke downstream handlers. Abort stops the chain:
err := c.Next() // call next handler; returns first error c.Abort() // stop chain (does not write response) c.AbortWithStatus(403) // stop chain and send status code c.IsAborted() // true if Abort was called
Key-Value Storage ¶
Store request-scoped data for sharing between middleware and handlers:
c.Set("userID", 42)
id, ok := c.Get("userID")
all := c.Keys() // copy of all stored pairs
Content-Disposition ¶
Set Content-Disposition headers for file downloads or inline display:
c.Attachment("report.pdf") // prompts download
c.Inline("image.png") // suggests inline display
Request Detection ¶
Detect request characteristics:
c.IsWebSocket() // true if Upgrade: websocket c.IsTLS() // true if X-Forwarded-Proto is "https"
Form Presence ¶
FormValueOk distinguishes a missing field from an empty value:
val, ok := c.FormValueOk("name")
if !ok {
// field was not submitted
}
Request Inspection ¶
Additional request accessors:
scheme := c.Scheme() // "http" or "https" (checks X-Forwarded-Proto) ip := c.ClientIP() // from X-Forwarded-For or X-Real-Ip method := c.Method() // HTTP method path := c.Path() // path without query string full := c.FullPath() // matched route pattern (e.g. "/users/:id") raw := c.RawQuery() // raw query string without leading '?'
Remote Address ¶
Context.RemoteAddr returns the TCP peer address. On native engines (epoll, io_uring), the address is captured from accept(2) or getpeername(2). On the std engine, it comes from http.Request.RemoteAddr.
addr := c.RemoteAddr() // e.g. "192.168.1.1:54321"
Host ¶
Context.Host returns the request host, checking the :authority pseudo-header first (HTTP/2) then falling back to the Host header (HTTP/1.1):
host := c.Host() // e.g. "example.com"
Connection Hijacking ¶
HTTP/1.1 connections can be hijacked on all engines for WebSocket or other protocols that require raw TCP access:
conn, err := c.Hijack()
if err != nil {
return err
}
defer conn.Close()
// conn is a net.Conn — caller owns the connection
HTTP/2 connections cannot be hijacked because multiplexed streams share a single TCP connection.
Graceful Restart ¶
Start the server with a pre-existing listener for zero-downtime deploys:
ln, _ := celeris.InheritListener("LISTEN_FD")
if ln != nil {
log.Fatal(s.StartWithListener(ln))
} else {
log.Fatal(s.Start())
}
Config Surface Area ¶
In addition to the basic config fields, the following tuning fields are available:
celeris.Config{
// Basic
Addr: ":8080",
Protocol: celeris.Auto, // HTTP1, H2C, or Auto
Engine: celeris.Adaptive, // IOUring, Epoll, Adaptive, Std
// Workers
Workers: 0, // I/O workers (default GOMAXPROCS)
// Timeouts (0 = default: 300s read/write, 600s idle; -1 = no timeout)
ReadTimeout: 0,
WriteTimeout: 0,
IdleTimeout: 0,
ShutdownTimeout: 30*time.Second,
// Limits
MaxFormSize: 0, // multipart form memory (0 = 32 MB; -1 = unlimited)
MaxConns: 0, // max connections per worker (0 = unlimited)
// H2 Tuning
MaxConcurrentStreams: 100, // H2 streams per connection
MaxFrameSize: 16384, // H2 frame payload size
InitialWindowSize: 65535, // H2 stream flow-control window
MaxHeaderBytes: 0, // header block size (0 = 16 MB)
// I/O
DisableKeepAlive: false, // disable HTTP keep-alive
BufferSize: 0, // per-connection I/O buffer (0 = engine default)
SocketRecvBuf: 0, // SO_RCVBUF (0 = OS default)
SocketSendBuf: 0, // SO_SNDBUF (0 = OS default)
// Observability
DisableMetrics: false, // skip per-request metric recording
Logger: nil, // *slog.Logger for engine diagnostics
// Connection callbacks (must be fast — blocks the event loop)
OnConnect: func(addr string) { ... },
OnDisconnect: func(addr string) { ... },
}
Listener Address ¶
After Start or StartWithContext, Server.Addr returns the bound address. This is useful when listening on ":0" to discover the OS-assigned port:
addr := s.Addr() // net.Addr; use addr.String() for "127.0.0.1:49152"
Testing ¶
The github.com/goceleris/celeris/celeristest package provides test helpers:
ctx, rec := celeristest.NewContext("GET", "/hello")
defer celeristest.ReleaseContext(ctx)
handler(ctx)
// inspect rec.StatusCode, rec.Headers, rec.Body
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris"
)
func main() {
s := celeris.New(celeris.Config{Addr: ":8080"})
s.GET("/hello", func(c *celeris.Context) error {
return c.String(200, "Hello, World!")
})
// s.Start() blocks until shutdown
_ = s // prevent unused error in example
fmt.Println("server configured")
}
Output: server configured
Index ¶
- Constants
- Variables
- func InheritListener(envVar string) (net.Listener, error)
- func ToHandler(h HandlerFunc) http.Handler
- type Config
- type Context
- func (c *Context) Abort()
- func (c *Context) AbortWithStatus(code int) error
- func (c *Context) AcceptsEncodings(offers ...string) string
- func (c *Context) AcceptsLanguages(offers ...string) string
- func (c *Context) AddHeader(key, value string)
- func (c *Context) Attachment(filename string)
- func (c *Context) BasicAuth() (username, password string, ok bool)
- func (c *Context) Bind(v any) error
- func (c *Context) BindJSON(v any) error
- func (c *Context) BindXML(v any) error
- func (c *Context) Blob(code int, contentType string, data []byte) error
- func (c *Context) Body() []byte
- func (c *Context) BodyCopy() []byte
- func (c *Context) BodyReader() io.Reader
- func (c *Context) BufferResponse()
- func (c *Context) BytesWritten() int
- func (c *Context) CaptureResponse()
- func (c *Context) ClientIP() string
- func (c *Context) ContentLength() int64
- func (c *Context) Context() context.Context
- func (c *Context) Cookie(name string) (string, error)
- func (c *Context) DeleteCookie(name, path string)
- func (c *Context) Detach() (done func())
- func (c *Context) File(filePath string) error
- func (c *Context) FileFromDir(baseDir, userPath string) error
- func (c *Context) FlushResponse() error
- func (c *Context) FormFile(name string) (multipart.File, *multipart.FileHeader, error)
- func (c *Context) FormValue(name string) string
- func (c *Context) FormValueOk(name string) (string, bool)
- func (c *Context) FormValues(name string) []string
- func (c *Context) FullPath() string
- func (c *Context) Get(key string) (any, bool)
- func (c *Context) HTML(code int, html string) error
- func (c *Context) Header(key string) string
- func (c *Context) Hijack() (net.Conn, error)
- func (c *Context) Host() string
- func (c *Context) Inline(filename string)
- func (c *Context) IsAborted() bool
- func (c *Context) IsTLS() bool
- func (c *Context) IsWebSocket() bool
- func (c *Context) IsWritten() bool
- func (c *Context) JSON(code int, v any) error
- func (c *Context) Keys() map[string]any
- func (c *Context) Method() string
- func (c *Context) MultipartForm() (*multipart.Form, error)
- func (c *Context) Negotiate(offers ...string) string
- func (c *Context) Next() error
- func (c *Context) NoContent(code int) error
- func (c *Context) Param(key string) string
- func (c *Context) ParamInt(key string) (int, error)
- func (c *Context) ParamInt64(key string) (int64, error)
- func (c *Context) Path() string
- func (c *Context) Query(key string) string
- func (c *Context) QueryDefault(key, defaultValue string) string
- func (c *Context) QueryInt(key string, defaultValue int) int
- func (c *Context) QueryParams() url.Values
- func (c *Context) QueryValues(key string) []string
- func (c *Context) RawQuery() string
- func (c *Context) Redirect(code int, url string) error
- func (c *Context) RemoteAddr() string
- func (c *Context) RequestHeaders() [][2]string
- func (c *Context) Respond(code int, v any) error
- func (c *Context) ResponseBody() []byte
- func (c *Context) ResponseContentType() string
- func (c *Context) ResponseHeaders() [][2]string
- func (c *Context) ResponseStatus() int
- func (c *Context) Scheme() string
- func (c *Context) Set(key string, value any)
- func (c *Context) SetClientIP(ip string)
- func (c *Context) SetContext(ctx context.Context)
- func (c *Context) SetCookie(cookie *Cookie)
- func (c *Context) SetHeader(key, value string)
- func (c *Context) SetHost(host string)
- func (c *Context) SetPath(p string)
- func (c *Context) SetRawQuery(q string)
- func (c *Context) SetResponseBody(body []byte)
- func (c *Context) SetScheme(scheme string)
- func (c *Context) Status(code int) *Context
- func (c *Context) StatusCode() int
- func (c *Context) Stream(code int, contentType string, r io.Reader) error
- func (c *Context) StreamWriter() *StreamWriter
- func (c *Context) String(code int, format string, args ...any) error
- func (c *Context) XML(code int, v any) error
- type Cookie
- type EngineInfo
- type EngineMetrics
- type EngineType
- type HTTPError
- type HandlerFunc
- type Param
- type Params
- type Protocol
- type Route
- type RouteGroup
- func (g *RouteGroup) Any(path string, handlers ...HandlerFunc) *RouteGroup
- func (g *RouteGroup) DELETE(path string, handlers ...HandlerFunc) *Route
- func (g *RouteGroup) GET(path string, handlers ...HandlerFunc) *Route
- func (g *RouteGroup) Group(prefix string, middleware ...HandlerFunc) *RouteGroup
- func (g *RouteGroup) HEAD(path string, handlers ...HandlerFunc) *Route
- func (g *RouteGroup) Handle(method, path string, handlers ...HandlerFunc) *Route
- func (g *RouteGroup) OPTIONS(path string, handlers ...HandlerFunc) *Route
- func (g *RouteGroup) PATCH(path string, handlers ...HandlerFunc) *Route
- func (g *RouteGroup) POST(path string, handlers ...HandlerFunc) *Route
- func (g *RouteGroup) PUT(path string, handlers ...HandlerFunc) *Route
- func (g *RouteGroup) Static(prefix, root string) *Route
- func (g *RouteGroup) Use(middleware ...HandlerFunc) *RouteGroup
- type RouteInfo
- type SameSite
- type Server
- func (s *Server) Addr() net.Addr
- func (s *Server) Any(path string, handlers ...HandlerFunc) *Server
- func (s *Server) Collector() *observe.Collector
- func (s *Server) DELETE(path string, handlers ...HandlerFunc) *Route
- func (s *Server) EngineInfo() *EngineInfo
- func (s *Server) GET(path string, handlers ...HandlerFunc) *Route
- func (s *Server) Group(prefix string, middleware ...HandlerFunc) *RouteGroup
- func (s *Server) HEAD(path string, handlers ...HandlerFunc) *Route
- func (s *Server) Handle(method, path string, handlers ...HandlerFunc) *Route
- func (s *Server) MethodNotAllowed(handler HandlerFunc) *Server
- func (s *Server) NotFound(handler HandlerFunc) *Server
- func (s *Server) OPTIONS(path string, handlers ...HandlerFunc) *Route
- func (s *Server) PATCH(path string, handlers ...HandlerFunc) *Route
- func (s *Server) POST(path string, handlers ...HandlerFunc) *Route
- func (s *Server) PUT(path string, handlers ...HandlerFunc) *Route
- func (s *Server) PauseAccept() error
- func (s *Server) ResumeAccept() error
- func (s *Server) Routes() []RouteInfo
- func (s *Server) Shutdown(ctx context.Context) error
- func (s *Server) Start() error
- func (s *Server) StartWithContext(ctx context.Context) error
- func (s *Server) StartWithListener(ln net.Listener) error
- func (s *Server) StartWithListenerAndContext(ctx context.Context, ln net.Listener) error
- func (s *Server) Static(prefix, root string) *Route
- func (s *Server) URL(name string, params ...string) (string, error)
- func (s *Server) URLMap(name string, params map[string]string) (string, error)
- func (s *Server) Use(middleware ...HandlerFunc) *Server
- type StreamWriter
Examples ¶
- Package
- Adapt
- Context.AcceptsEncodings
- Context.Attachment
- Context.BasicAuth
- Context.Bind
- Context.BufferResponse
- Context.Cookie
- Context.File
- Context.FormValue
- Context.Hijack
- Context.IsWebSocket
- Context.JSON
- Context.Negotiate
- Context.Param
- Context.Query
- Context.Redirect
- Context.RemoteAddr
- Context.Respond
- Context.StreamWriter
- Context.XML
- NewHTTPError
- Server.Group
- Server.NotFound
- Server.Routes
- Server.StartWithContext
- Server.Static
- Server.URL
- Server.Use
Constants ¶
const DefaultMaxFormSize int64 = 32 << 20
DefaultMaxFormSize is the default maximum memory used for multipart form parsing (32 MB), matching net/http.
const Version = "1.2.0"
Version is the semantic version of the celeris module.
Variables ¶
var ErrAcceptControlNotSupported = errors.New("celeris: engine does not support accept control")
ErrAcceptControlNotSupported is returned by PauseAccept/ResumeAccept when the active engine does not implement accept control (e.g. std engine).
var ErrAlreadyStarted = errors.New("celeris: server already started")
ErrAlreadyStarted is returned when Start or StartWithContext is called on a server that is already running.
var ErrDuplicateRouteName = errors.New("celeris: duplicate route name")
ErrDuplicateRouteName is returned by Route.TryName when a route with the given name has already been registered.
var ErrEmptyBody = errors.New("celeris: empty request body")
ErrEmptyBody is returned by Bind, BindJSON, and BindXML when the request body is empty.
var ErrHijackNotSupported = stream.ErrHijackNotSupported
ErrHijackNotSupported is returned by Hijack when the connection does not support takeover (e.g. HTTP/2 multiplexed streams).
var ErrInvalidRedirectCode = errors.New("celeris: redirect status code must be 3xx")
ErrInvalidRedirectCode is returned by Context.Redirect when the status code is not in the range 300–308.
var ErrNoCookie = errors.New("celeris: named cookie not present")
ErrNoCookie is returned by Context.Cookie when the named cookie is not present.
var ErrResponseWritten = errors.New("celeris: response already written")
ErrResponseWritten is returned when a response method is called after a response has already been written.
var ErrRouteNotFound = errors.New("celeris: named route not found")
ErrRouteNotFound is returned by Server.URL when no route with the given name has been registered.
Functions ¶
func InheritListener ¶ added in v1.1.0
InheritListener returns a net.Listener from the file descriptor in the named environment variable. Returns nil, nil if the variable is not set. Used for zero-downtime restart patterns.
func ToHandler ¶ added in v1.1.0
func ToHandler(h HandlerFunc) http.Handler
ToHandler wraps a celeris HandlerFunc as an http.Handler for use with net/http routers, middleware, or test infrastructure. The returned handler converts the *http.Request into a stream.Stream, invokes the celeris handler, and writes the response back via http.ResponseWriter.
This is the reverse of Adapt / AdaptFunc which wrap net/http handlers for use inside celeris.
Types ¶
type Config ¶
type Config struct {
// Addr is the TCP address to listen on (e.g. ":8080").
Addr string
// Protocol is the HTTP protocol version (default Auto — auto-detect H1/H2).
Protocol Protocol
// Engine is the I/O engine (default Adaptive on Linux, Std elsewhere).
Engine EngineType
// Workers is the number of I/O worker goroutines (default GOMAXPROCS).
Workers int
// ReadTimeout is the max duration for reading the entire request.
// Zero uses the default (300s). Set to -1 for no timeout.
ReadTimeout time.Duration
// WriteTimeout is the max duration for writing the response.
// Zero uses the default (300s). Set to -1 for no timeout.
WriteTimeout time.Duration
// IdleTimeout is the max duration a keep-alive connection may be idle.
// Zero uses the default (600s). Set to -1 for no timeout.
IdleTimeout time.Duration
// ShutdownTimeout is the max duration to wait for in-flight requests during
// graceful shutdown via StartWithContext (default 30s).
ShutdownTimeout time.Duration
// MaxFormSize is the maximum memory used for multipart form parsing
// (default 32 MB). Set to -1 to disable the limit.
MaxFormSize int64
// MaxRequestBodySize is the maximum allowed request body size in bytes
// across all protocols (H1, H2, bridge). 0 uses the default (100 MB).
// Set to -1 to disable the limit (unlimited).
MaxRequestBodySize int64
// MaxConcurrentStreams limits simultaneous H2 streams per connection (default 100).
MaxConcurrentStreams uint32
// MaxFrameSize is the max H2 frame payload size (default 16384, range 16384-16777215).
MaxFrameSize uint32
// InitialWindowSize is the H2 initial stream window size (default 65535).
InitialWindowSize uint32
// MaxHeaderBytes is the max header block size (default 16 MB, min 4096).
MaxHeaderBytes int
// DisableKeepAlive disables HTTP keep-alive; each request gets its own connection.
DisableKeepAlive bool
// BufferSize is the per-connection I/O buffer size in bytes (0 = engine default).
BufferSize int
// SocketRecvBuf sets SO_RCVBUF for accepted connections (0 = OS default).
SocketRecvBuf int
// SocketSendBuf sets SO_SNDBUF for accepted connections (0 = OS default).
SocketSendBuf int
// MaxConns is the max simultaneous connections per worker (0 = unlimited).
MaxConns int
// DisableMetrics disables the built-in metrics collector. When true,
// [Server.Collector] returns nil and per-request metric recording is skipped.
// Default false (metrics enabled).
DisableMetrics bool
// OnExpectContinue is called when an H1 request contains "Expect: 100-continue".
// If the callback returns false, the server responds with 417 Expectation Failed
// and skips reading the body. If nil, the server always sends 100 Continue.
OnExpectContinue func(method, path string, headers [][2]string) bool
// OnConnect is called when a new connection is accepted. The addr is the
// remote peer address. Must be fast — blocks the event loop.
OnConnect func(addr string)
// OnDisconnect is called when a connection is closed. The addr is the
// remote peer address. Must be fast — blocks the event loop.
OnDisconnect func(addr string)
// Logger is the structured logger (default slog.Default()).
Logger *slog.Logger
}
Config holds the public server configuration.
type Context ¶
type Context struct {
// contains filtered or unexported fields
}
Context is the request context passed to handlers. It is pooled via sync.Pool. A Context is obtained from the pool and must not be retained after the handler returns.
func (*Context) Abort ¶
func (c *Context) Abort()
Abort prevents pending handlers from being called. Does not write a response. Use AbortWithStatus to abort and send a status code.
func (*Context) AbortWithStatus ¶
AbortWithStatus calls Abort and writes a status code with no body. It returns the error from NoContent for propagation.
func (*Context) AcceptsEncodings ¶ added in v1.1.0
AcceptsEncodings returns the best matching encoding from the Accept-Encoding header, or empty string if none match.
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris/celeristest"
)
func main() {
ctx, _ := celeristest.NewContext("GET", "/data",
celeristest.WithHeader("accept-encoding", "gzip, br;q=0.8"),
)
defer celeristest.ReleaseContext(ctx)
fmt.Println(ctx.AcceptsEncodings("br", "gzip"))
}
Output: gzip
func (*Context) AcceptsLanguages ¶ added in v1.1.0
AcceptsLanguages returns the best matching language from the Accept-Language header, or empty string if none match.
func (*Context) AddHeader ¶
AddHeader appends a response header value. Unlike SetHeader, it does not replace existing values — use this for headers that allow multiple values (e.g. set-cookie).
func (*Context) Attachment ¶ added in v1.1.0
Attachment sets the Content-Disposition header to "attachment" with the given filename, prompting the client to download the response.
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris/celeristest"
)
func main() {
ctx, rec := celeristest.NewContext("GET", "/download")
defer celeristest.ReleaseContext(ctx)
ctx.Attachment("report.pdf")
_ = ctx.Blob(200, "application/pdf", []byte("content"))
fmt.Println(rec.Header("content-disposition"))
}
Output: attachment; filename="report.pdf"
func (*Context) BasicAuth ¶
BasicAuth extracts HTTP Basic Authentication credentials from the Authorization header. Returns the username, password, and true if valid credentials are present; otherwise returns zero values and false.
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris/celeristest"
)
func main() {
ctx, _ := celeristest.NewContext("GET", "/admin",
celeristest.WithBasicAuth("alice", "secret"),
)
defer celeristest.ReleaseContext(ctx)
user, _, ok := ctx.BasicAuth()
fmt.Println(ok, user)
}
Output: true alice
func (*Context) Bind ¶
Bind auto-detects the request body format from the Content-Type header and deserializes into v. Supports application/json (default) and application/xml. Returns ErrEmptyBody if the body is empty, or the underlying encoding/json or encoding/xml error if deserialization fails.
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris/celeristest"
)
func main() {
type User struct {
Name string `json:"name"`
}
body := []byte(`{"name":"bob"}`)
ctx, _ := celeristest.NewContext("POST", "/users",
celeristest.WithBody(body),
celeristest.WithContentType("application/json"),
)
defer celeristest.ReleaseContext(ctx)
var u User
err := ctx.Bind(&u)
fmt.Println(err)
fmt.Println(u.Name)
}
Output: <nil> bob
func (*Context) BindJSON ¶
BindJSON deserializes the JSON request body into v. Returns ErrEmptyBody if the body is empty.
func (*Context) BindXML ¶
BindXML deserializes the XML request body into v. Returns ErrEmptyBody if the body is empty.
func (*Context) Blob ¶
Blob writes a response with the given content type and data. Returns ErrResponseWritten if a response has already been sent.
func (*Context) Body ¶
Body returns the raw request body. The returned slice must not be modified or retained after the handler returns.
func (*Context) BodyCopy ¶ added in v1.1.0
BodyCopy returns a copy of the request body that is safe to retain after the handler returns. Use this instead of Body() when the body must outlive the request lifecycle (e.g., for async processing or logging).
func (*Context) BodyReader ¶ added in v1.1.0
BodyReader returns an io.Reader for the request body. This wraps the already-received body bytes.
func (*Context) BufferResponse ¶ added in v1.1.0
func (c *Context) BufferResponse()
BufferResponse instructs response methods (JSON, XML, Blob, NoContent, etc.) to capture the response instead of writing to the wire. Multiple middleware layers can call BufferResponse — responses are depth-tracked and only sent when the outermost layer calls FlushResponse.
Example ¶
package main
import (
"fmt"
"strings"
"github.com/goceleris/celeris/celeristest"
)
func main() {
ctx, rec := celeristest.NewContext("GET", "/data")
defer celeristest.ReleaseContext(ctx)
ctx.BufferResponse()
_ = ctx.String(200, "original")
// Transform the buffered body before sending.
body := ctx.ResponseBody()
ctx.SetResponseBody([]byte(strings.ToUpper(string(body))))
_ = ctx.FlushResponse()
fmt.Println(rec.StatusCode)
fmt.Println(rec.BodyString())
}
Output: 200 ORIGINAL
func (*Context) BytesWritten ¶ added in v1.1.0
BytesWritten returns the response body size in bytes, or 0 if no response was written. For NoContent responses, returns 0.
func (*Context) CaptureResponse ¶ added in v1.1.0
func (c *Context) CaptureResponse()
CaptureResponse enables response body capture for this request. After calling Next(), use ResponseBody() and ResponseContentType() to inspect. The response is written to the wire AND a copy is captured for inspection (ideal for loggers). Use BufferResponse to defer the wire write entirely.
func (*Context) ClientIP ¶
ClientIP extracts the client IP. If SetClientIP has been called, the override value is returned. Otherwise it reads X-Forwarded-For or X-Real-Ip headers. Returns empty string if neither header is present. These headers can be spoofed by clients. In production behind a reverse proxy, ensure only trusted proxies set these headers.
func (*Context) ContentLength ¶ added in v1.2.0
ContentLength returns the value of the Content-Length request header parsed as int64. Returns -1 if the header is absent or invalid.
func (*Context) Context ¶
Context returns the request's context.Context. The returned context is always non-nil; it defaults to the stream's context.
func (*Context) Cookie ¶
Cookie returns the value of the named cookie from the request, or ErrNoCookie if not found. Values are returned as-is without decoding.
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris"
"github.com/goceleris/celeris/celeristest"
)
func main() {
ctx, rec := celeristest.NewContext("GET", "/test",
celeristest.WithCookie("session", "abc123"),
)
defer celeristest.ReleaseContext(ctx)
val, err := ctx.Cookie("session")
fmt.Println(val, err)
ctx.SetCookie(&celeris.Cookie{Name: "token", Value: "xyz", HTTPOnly: true})
_ = ctx.NoContent(200)
fmt.Println(rec.Header("set-cookie"))
}
Output: abc123 <nil> token=xyz; HttpOnly
func (*Context) DeleteCookie ¶ added in v1.2.0
DeleteCookie appends a Set-Cookie header that instructs the client to delete the named cookie. The path must match the original cookie's path.
func (*Context) Detach ¶ added in v1.1.0
func (c *Context) Detach() (done func())
Detach removes the Context from the handler chain's lifecycle. After Detach, the Context will not be released when the handler returns. The caller MUST call the returned done function when finished with the Context — failure to do so permanently leaks the Context from the pool. This is required for streaming responses on native engines where the handler must return to free the event loop thread.
func (*Context) File ¶
File serves the named file. The content type is detected from the file extension. Supports Range requests for partial content (HTTP 206).
The entire file is loaded into memory (capped at 100 MB). Returns HTTPError with status 413 if the file exceeds this limit. For large files, consider using StreamWriter instead.
Security: filePath is opened directly — callers MUST sanitize user-supplied paths (e.g. filepath.Clean + prefix check) to prevent directory traversal.
Example ¶
package main
import (
"fmt"
"os"
"github.com/goceleris/celeris/celeristest"
)
func main() {
dir, _ := os.MkdirTemp("", "celeris-example-*")
defer func() { _ = os.RemoveAll(dir) }()
_ = os.WriteFile(dir+"/hello.txt", []byte("hello"), 0644)
ctx, rec := celeristest.NewContext("GET", "/download")
defer celeristest.ReleaseContext(ctx)
_ = ctx.File(dir + "/hello.txt")
fmt.Println(rec.StatusCode)
fmt.Println(rec.BodyString())
}
Output: 200 hello
func (*Context) FileFromDir ¶
FileFromDir safely serves a file from within baseDir. The userPath is cleaned and joined with baseDir; if the result escapes baseDir, a 400 error is returned. This prevents directory traversal when serving user-supplied paths.
func (*Context) FlushResponse ¶ added in v1.1.0
FlushResponse sends the buffered response to the wire. Each call decrements the buffer depth; the actual write happens when depth reaches zero. Returns nil if nothing was buffered. Returns ErrResponseWritten if already sent. Calling FlushResponse without a prior BufferResponse is a safe no-op.
func (*Context) FormFile ¶
FormFile returns the first file for the named form field. Returns HTTPError with status 400 if the request is not multipart or the field is missing.
func (*Context) FormValue ¶
FormValue returns the first value for the named form field. Parses the request body on first call (url-encoded or multipart).
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris/celeristest"
)
func main() {
ctx, _ := celeristest.NewContext("POST", "/submit",
celeristest.WithBody([]byte("name=alice&color=blue")),
celeristest.WithContentType("application/x-www-form-urlencoded"),
)
defer celeristest.ReleaseContext(ctx)
fmt.Println(ctx.FormValue("name"))
fmt.Println(ctx.FormValue("color"))
}
Output: alice blue
func (*Context) FormValueOk ¶
FormValueOk returns the first value for the named form field plus a boolean indicating whether the field was present. Unlike FormValue, callers can distinguish a missing field from an empty value.
func (*Context) FormValues ¶
FormValues returns all values for the named form field.
func (*Context) FullPath ¶
FullPath returns the matched route pattern (e.g. "/users/:id"). Returns empty string if no route was matched.
func (*Context) HTML ¶
HTML writes an HTML response with the given status code. Returns ErrResponseWritten if a response has already been sent.
func (*Context) Header ¶
Header returns the value of the named request header. Keys must be lowercase (HTTP/2 mandates lowercase; the H1 parser normalizes to lowercase).
func (*Context) Hijack ¶ added in v1.1.0
Hijack takes over the underlying TCP connection. After Hijack, the caller owns the connection and is responsible for closing it. Supported on all engines for HTTP/1.1 connections. HTTP/2 connections cannot be hijacked (multiplexed streams share a single TCP connection).
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris/celeristest"
)
func main() {
ctx, _ := celeristest.NewContext("GET", "/ws")
defer celeristest.ReleaseContext(ctx)
// celeristest uses a mock writer that does not implement Hijacker,
// so Hijack returns ErrHijackNotSupported.
_, err := ctx.Hijack()
fmt.Println(err)
}
Output: celeris: hijack not supported by this engine
func (*Context) Host ¶ added in v1.1.0
Host returns the request host from the :authority pseudo-header (HTTP/2) or the Host header (HTTP/1.1). If SetHost has been called, the override value is returned instead.
func (*Context) Inline ¶ added in v1.1.0
Inline sets the Content-Disposition header to "inline" with the given filename, suggesting the client display the content in-browser.
func (*Context) IsWebSocket ¶ added in v1.1.0
IsWebSocket returns true if the request is a WebSocket upgrade.
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris/celeristest"
)
func main() {
ctx, _ := celeristest.NewContext("GET", "/ws",
celeristest.WithHeader("upgrade", "websocket"),
)
defer celeristest.ReleaseContext(ctx)
fmt.Println(ctx.IsWebSocket())
}
Output: true
func (*Context) IsWritten ¶ added in v1.1.0
IsWritten returns true if a response has been written to the wire.
func (*Context) JSON ¶
JSON serializes v as JSON and writes it with the given status code. Returns ErrResponseWritten if a response has already been sent.
Example ¶
package main
import (
"encoding/json"
"fmt"
"github.com/goceleris/celeris/celeristest"
)
func main() {
ctx, rec := celeristest.NewContext("GET", "/api/user")
defer celeristest.ReleaseContext(ctx)
_ = ctx.JSON(200, map[string]string{"name": "alice"})
fmt.Println(rec.StatusCode)
fmt.Println(rec.Header("content-type"))
var m map[string]string
_ = json.Unmarshal(rec.Body, &m)
fmt.Println(m["name"])
}
Output: 200 application/json alice
func (*Context) Keys ¶
Keys returns a copy of all key-value pairs stored on this context. Returns nil if no values have been set.
func (*Context) MultipartForm ¶
MultipartForm returns the parsed multipart form, including file uploads. Returns HTTPError with status 400 if the request is not multipart.
func (*Context) Negotiate ¶ added in v1.1.0
Negotiate inspects the Accept header and returns the best matching content type from the provided offers. Returns "" if no match. Supports quality values (q=).
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris/celeristest"
)
func main() {
ctx, _ := celeristest.NewContext("GET", "/data",
celeristest.WithHeader("accept", "application/xml, application/json;q=0.9"),
)
defer celeristest.ReleaseContext(ctx)
best := ctx.Negotiate("application/json", "application/xml")
fmt.Println(best)
}
Output: application/xml
func (*Context) Next ¶
Next executes the next handler in the chain. It returns the first non-nil error from a downstream handler, short-circuiting the remaining chain. Middleware can inspect or swallow errors by checking the return value.
func (*Context) NoContent ¶
NoContent writes a response with no body. Returns ErrResponseWritten if a response has already been sent.
func (*Context) Param ¶
Param returns the value of a URL parameter by name.
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris/celeristest"
)
func main() {
ctx, _ := celeristest.NewContext("GET", "/users/42",
celeristest.WithParam("id", "42"),
)
defer celeristest.ReleaseContext(ctx)
fmt.Println(ctx.Param("id"))
}
Output: 42
func (*Context) ParamInt ¶
ParamInt returns a URL parameter parsed as an int. Returns an error if the parameter is missing or not a valid integer.
func (*Context) ParamInt64 ¶
ParamInt64 returns a URL parameter parsed as an int64. Returns an error if the parameter is missing or not a valid integer.
func (*Context) Query ¶
Query returns the value of a query parameter by name. Results are cached so repeated calls for different keys do not re-parse the query string.
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris/celeristest"
)
func main() {
ctx, _ := celeristest.NewContext("GET", "/search",
celeristest.WithQuery("q", "celeris"),
celeristest.WithQuery("page", "2"),
)
defer celeristest.ReleaseContext(ctx)
fmt.Println(ctx.Query("q"))
fmt.Println(ctx.QueryDefault("limit", "10"))
}
Output: celeris 10
func (*Context) QueryDefault ¶
QueryDefault returns the value of a query parameter, or the default if absent or empty.
func (*Context) QueryInt ¶
QueryInt returns a query parameter parsed as an int. Returns the provided default value if the key is absent or not a valid integer.
func (*Context) QueryParams ¶
QueryParams returns all query parameters as url.Values.
func (*Context) QueryValues ¶
QueryValues returns all values for the given query parameter key. Returns nil if the key is not present.
func (*Context) RawQuery ¶ added in v1.1.0
RawQuery returns the raw query string without the leading '?'. Returns empty string if the URL has no query component.
func (*Context) Redirect ¶
Redirect sends an HTTP redirect to the given URL with the specified status code. Returns ErrInvalidRedirectCode if code is not in the range 300–308. Returns ErrResponseWritten if a response has already been sent.
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris/celeristest"
)
func main() {
ctx, rec := celeristest.NewContext("GET", "/old")
defer celeristest.ReleaseContext(ctx)
_ = ctx.Redirect(301, "/new")
fmt.Println(rec.StatusCode)
fmt.Println(rec.Header("location"))
}
Output: 301 /new
func (*Context) RemoteAddr ¶ added in v1.1.0
RemoteAddr returns the TCP peer address (e.g. "192.168.1.1:54321"). Returns empty string if unavailable.
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris/celeristest"
)
func main() {
// RemoteAddr returns empty from celeristest by default.
ctx, _ := celeristest.NewContext("GET", "/info")
defer celeristest.ReleaseContext(ctx)
fmt.Printf("addr=%q\n", ctx.RemoteAddr())
}
Output: addr=""
func (*Context) RequestHeaders ¶ added in v1.1.0
RequestHeaders returns all request headers as key-value pairs. The returned slice is a copy safe for concurrent use.
func (*Context) Respond ¶ added in v1.1.0
Respond writes the response in the format that best matches the Accept header. Supported types: application/json, application/xml, text/plain. Falls back to JSON if no match.
Example ¶
package main
import (
"encoding/json"
"fmt"
"github.com/goceleris/celeris/celeristest"
)
func main() {
ctx, rec := celeristest.NewContext("GET", "/data",
celeristest.WithHeader("accept", "application/json"),
)
defer celeristest.ReleaseContext(ctx)
_ = ctx.Respond(200, map[string]string{"key": "value"})
fmt.Println(rec.Header("content-type"))
var m map[string]string
_ = json.Unmarshal(rec.Body, &m)
fmt.Println(m["key"])
}
Output: application/json value
func (*Context) ResponseBody ¶ added in v1.1.0
ResponseBody returns the captured response body, or nil if capture was not enabled. Available after Context.CaptureResponse + c.Next(), or after Context.BufferResponse + a response method (JSON, Blob, etc.).
func (*Context) ResponseContentType ¶ added in v1.1.0
ResponseContentType returns the captured Content-Type, or "" if not captured.
func (*Context) ResponseHeaders ¶ added in v1.2.0
ResponseHeaders returns the response headers that have been set so far. The returned slice must not be modified. Use SetHeader or AddHeader to change response headers.
func (*Context) ResponseStatus ¶ added in v1.1.0
ResponseStatus returns the captured response status code.
func (*Context) Scheme ¶
Scheme returns the request scheme ("http" or "https"). If SetScheme has been called, the override value is returned. Otherwise it checks the X-Forwarded-Proto header first (set by reverse proxies), then falls back to the :scheme pseudo-header from the original request. Returns "http" if neither source provides a value.
func (*Context) SetClientIP ¶ added in v1.2.0
SetClientIP overrides the value returned by ClientIP. This is useful in middleware that validates and extracts the real client IP from trusted proxy headers, so downstream handlers see the canonical IP.
func (*Context) SetContext ¶
SetContext sets the request's context. The provided ctx must be non-nil.
func (*Context) SetCookie ¶
SetCookie appends a Set-Cookie header to the response. Cookie values are sent as-is without encoding (per RFC 6265). Callers are responsible for encoding values if needed. Semicolons in Name, Value, Path, and Domain are stripped to prevent cookie attribute injection.
func (*Context) SetHeader ¶
SetHeader sets a response header, replacing any existing value for the key. Keys are lowercased for HTTP/2 compliance (RFC 7540 §8.1.2). CRLF characters are stripped to prevent header injection.
func (*Context) SetHost ¶ added in v1.2.0
SetHost overrides the value returned by Host. This is useful in middleware that normalizes the host (e.g., stripping port, applying X-Forwarded-Host).
func (*Context) SetPath ¶ added in v1.1.0
SetPath overrides the request path. This is useful in middleware that rewrites URLs (e.g. prefix stripping) before downstream handlers see the path.
func (*Context) SetRawQuery ¶ added in v1.2.0
SetRawQuery overrides the raw query string. Any cached query parameters from a previous call to Query/QueryValues/QueryParams are invalidated.
func (*Context) SetResponseBody ¶ added in v1.1.0
SetResponseBody replaces the buffered response body. Only valid after BufferResponse + c.Next(). Used by transform middleware (compress, etc.).
func (*Context) SetScheme ¶ added in v1.2.0
SetScheme overrides the value returned by Scheme. This is useful in middleware that determines the actual scheme from trusted proxy headers (e.g., X-Forwarded-Proto) and wants downstream handlers to see the canonical value without re-parsing headers.
func (*Context) Status ¶
Status sets the response status code and returns the Context for chaining. Note: response methods (JSON, Blob, etc.) take their own status code parameter and do not read the value set by Status.
func (*Context) StatusCode ¶
StatusCode returns the response status code set by the handler.
func (*Context) Stream ¶
Stream reads all data from r (capped at 100 MB) and writes it as the response with the given status code and content type. Returns HTTPError with status 413 if the data exceeds 100 MB.
func (*Context) StreamWriter ¶ added in v1.1.0
func (c *Context) StreamWriter() *StreamWriter
StreamWriter returns a StreamWriter for incremental response writing. Returns nil if the engine does not support streaming. On native engines (epoll, io_uring), the caller must call Context.Detach before spawning a goroutine that uses the StreamWriter. Call Close() when done.
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris/celeristest"
)
func main() {
ctx, _ := celeristest.NewContext("GET", "/events")
defer celeristest.ReleaseContext(ctx)
// celeristest mock does not implement Streamer, so StreamWriter is nil.
sw := ctx.StreamWriter()
fmt.Println(sw == nil)
}
Output: true
func (*Context) String ¶
String writes a formatted string response. Returns ErrResponseWritten if a response has already been sent.
func (*Context) XML ¶
XML serializes v as XML and writes it with the given status code. Returns ErrResponseWritten if a response has already been sent.
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris/celeristest"
)
func main() {
type Item struct {
Name string
}
ctx, rec := celeristest.NewContext("GET", "/item")
defer celeristest.ReleaseContext(ctx)
_ = ctx.XML(200, Item{Name: "widget"})
fmt.Println(rec.StatusCode)
fmt.Println(rec.Header("content-type"))
}
Output: 200 application/xml
type Cookie ¶
type Cookie struct {
// Name is the cookie name.
Name string
// Value is the cookie value.
Value string
// Path limits the scope of the cookie to the given URL path.
Path string
// Domain limits the scope of the cookie to the given domain.
Domain string
// MaxAge=0 means no Max-Age attribute is sent. Negative value means
// delete the cookie (Max-Age=0 in the header).
MaxAge int
// Expires sets the Expires attribute for legacy client compatibility
// (e.g. IE11). Zero value means no Expires is sent. Prefer MaxAge
// for modern clients.
Expires time.Time
// Secure flags the cookie for HTTPS-only transmission.
Secure bool
// HTTPOnly prevents client-side scripts from accessing the cookie.
HTTPOnly bool
// SameSite controls cross-site request cookie behavior.
SameSite SameSite
}
Cookie represents an HTTP cookie for use with Context.SetCookie.
type EngineInfo ¶
type EngineInfo struct {
// Type identifies the active I/O engine (IOUring, Epoll, Adaptive, or Std).
Type EngineType
// Metrics is a point-in-time snapshot of engine-level performance counters.
Metrics EngineMetrics
}
EngineInfo provides read-only information about the running engine.
type EngineMetrics ¶
type EngineMetrics = engine.EngineMetrics
EngineMetrics is a point-in-time snapshot of engine-level performance counters.
type EngineType ¶
type EngineType engine.EngineType
EngineType identifies which I/O engine implementation is in use.
const ( // Adaptive dynamically switches between Epoll and IOUring based on load (default on Linux). Adaptive EngineType = EngineType(engine.Adaptive) // Epoll uses Linux edge-triggered epoll for I/O (Linux only). Epoll EngineType = EngineType(engine.Epoll) // IOUring uses Linux io_uring for asynchronous I/O (Linux 5.10+ required). IOUring EngineType = EngineType(engine.IOUring) // Std uses Go's net/http standard library server (all platforms). Std EngineType = EngineType(engine.Std) )
type HTTPError ¶
type HTTPError struct {
// Code is the HTTP status code (e.g. 400, 404, 500).
Code int
// Message is a human-readable error description sent in the response body.
Message string
// Err is an optional wrapped error for use with errors.Is / errors.As.
Err error
}
HTTPError is a structured error that carries an HTTP status code. Handlers return HTTPError to signal a specific status code to the routerAdapter safety net. Use NewHTTPError to create one.
func NewHTTPError ¶
NewHTTPError creates an HTTPError with the given status code and message. To wrap an existing error, use the WithError method on the returned HTTPError.
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris"
)
func main() {
err := celeris.NewHTTPError(404, "user not found")
fmt.Println(err.Error())
}
Output: code=404, message=user not found
func (*HTTPError) Error ¶
Error returns a string representation including the status code and message.
type HandlerFunc ¶
HandlerFunc defines the handler used by middleware and routes. Returning a non-nil error propagates it up through the middleware chain. The routerAdapter safety net writes an appropriate response for unhandled errors.
func Adapt ¶
func Adapt(h http.Handler) HandlerFunc
Adapt wraps a standard net/http Handler so it can be used as a celeris HandlerFunc. The adapted handler receives a reconstructed *http.Request with headers, body, and context from the celeris Context. Response body is buffered in memory, capped at 100MB.
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris"
)
func main() {
_ = celeris.Adapt(nil) // wraps any net/http Handler
fmt.Println("adapter created")
}
Output: adapter created
func AdaptFunc ¶
func AdaptFunc(h http.HandlerFunc) HandlerFunc
AdaptFunc wraps a standard net/http handler function. It is a convenience wrapper equivalent to Adapt(http.HandlerFunc(h)).
type Param ¶
type Param struct {
// Key is the parameter name from the route pattern (e.g. "id" from ":id").
Key string
// Value is the matched segment from the request path (e.g. "42").
Value string
}
Param is a single URL parameter consisting of a key and a value.
type Route ¶
type Route struct {
// contains filtered or unexported fields
}
Route is an opaque handle to a registered route. Use the Name method to assign a name for reverse lookup via Server.URL.
func (*Route) Name ¶
Name sets a name for this route, enabling reverse URL generation via Server.URL. Panics if a route with the same name is already registered.
func (*Route) TryName ¶
TryName is like Route.Name but returns an error instead of panicking when a route with the same name already exists.
func (*Route) Use ¶ added in v1.1.0
func (r *Route) Use(middleware ...HandlerFunc) *Route
Use prepends middleware to this specific route's handler chain. Must be called before Server.Start. Panics if the route has no handlers.
type RouteGroup ¶
type RouteGroup struct {
// contains filtered or unexported fields
}
RouteGroup is a collection of routes that share a common path prefix and middleware. Use Server.Group to create one. A RouteGroup must not be used after Server.Start is called.
func (*RouteGroup) Any ¶
func (g *RouteGroup) Any(path string, handlers ...HandlerFunc) *RouteGroup
Any registers a handler for all HTTP methods.
func (*RouteGroup) DELETE ¶
func (g *RouteGroup) DELETE(path string, handlers ...HandlerFunc) *Route
DELETE registers a handler for DELETE requests.
func (*RouteGroup) GET ¶
func (g *RouteGroup) GET(path string, handlers ...HandlerFunc) *Route
GET registers a handler for GET requests.
func (*RouteGroup) Group ¶
func (g *RouteGroup) Group(prefix string, middleware ...HandlerFunc) *RouteGroup
Group creates a sub-group with the given path prefix. The sub-group inherits middleware from the parent group.
func (*RouteGroup) HEAD ¶
func (g *RouteGroup) HEAD(path string, handlers ...HandlerFunc) *Route
HEAD registers a handler for HEAD requests.
func (*RouteGroup) Handle ¶
func (g *RouteGroup) Handle(method, path string, handlers ...HandlerFunc) *Route
Handle registers a handler for the given HTTP method and path pattern.
func (*RouteGroup) OPTIONS ¶
func (g *RouteGroup) OPTIONS(path string, handlers ...HandlerFunc) *Route
OPTIONS registers a handler for OPTIONS requests.
func (*RouteGroup) PATCH ¶
func (g *RouteGroup) PATCH(path string, handlers ...HandlerFunc) *Route
PATCH registers a handler for PATCH requests.
func (*RouteGroup) POST ¶
func (g *RouteGroup) POST(path string, handlers ...HandlerFunc) *Route
POST registers a handler for POST requests.
func (*RouteGroup) PUT ¶
func (g *RouteGroup) PUT(path string, handlers ...HandlerFunc) *Route
PUT registers a handler for PUT requests.
func (*RouteGroup) Static ¶ added in v1.1.0
func (g *RouteGroup) Static(prefix, root string) *Route
Static registers a GET handler that serves files from root under the given prefix. Uses FileFromDir for path traversal protection.
func (*RouteGroup) Use ¶
func (g *RouteGroup) Use(middleware ...HandlerFunc) *RouteGroup
Use adds middleware to this group. Group middleware runs after server-level middleware but before route handlers within this group. Middleware chains are composed at route registration time, so Use must be called before registering routes on this group.
type RouteInfo ¶
type RouteInfo struct {
// Method is the HTTP method (e.g. "GET", "POST").
Method string
// Path is the route pattern (e.g. "/users/:id").
Path string
// HandlerCount is the total number of handlers (middleware + handler) in the chain.
HandlerCount int
}
RouteInfo describes a registered route. Returned by Server.Routes.
type SameSite ¶
type SameSite int
SameSite controls the SameSite attribute of a cookie.
const ( // SameSiteDefaultMode leaves the SameSite attribute unset (browser default). SameSiteDefaultMode SameSite = iota // SameSiteLaxMode sets SameSite=Lax (cookies sent with top-level navigations). SameSiteLaxMode // SameSiteStrictMode sets SameSite=Strict (cookies sent only in first-party context). SameSiteStrictMode // SameSiteNoneMode sets SameSite=None (requires Secure; cookies sent in all contexts). SameSiteNoneMode )
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the top-level entry point for a celeris HTTP server. A Server is safe for concurrent use after Start is called. Route registration methods (GET, POST, Use, Group, etc.) must be called before Start.
func (*Server) Addr ¶
Addr returns the listener's bound address, or nil if the server has not been started. Useful when listening on ":0" to discover the OS-assigned port.
func (*Server) Any ¶
func (s *Server) Any(path string, handlers ...HandlerFunc) *Server
Any registers a handler for all HTTP methods.
func (*Server) Collector ¶
Collector returns the metrics collector, or nil if the server has not been started or if Config.DisableMetrics is true.
func (*Server) DELETE ¶
func (s *Server) DELETE(path string, handlers ...HandlerFunc) *Route
DELETE registers a handler for DELETE requests.
func (*Server) EngineInfo ¶
func (s *Server) EngineInfo() *EngineInfo
EngineInfo returns information about the running engine, or nil if not started.
func (*Server) GET ¶
func (s *Server) GET(path string, handlers ...HandlerFunc) *Route
GET registers a handler for GET requests.
func (*Server) Group ¶
func (s *Server) Group(prefix string, middleware ...HandlerFunc) *RouteGroup
Group creates a new route group with the given prefix and middleware. Middleware provided here runs after server-level middleware but before route handlers.
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris"
)
func main() {
s := celeris.New(celeris.Config{Addr: ":8080"})
api := s.Group("/api")
api.GET("/users", func(_ *celeris.Context) error { return nil })
api.GET("/posts", func(_ *celeris.Context) error { return nil })
fmt.Println("group registered")
}
Output: group registered
func (*Server) HEAD ¶
func (s *Server) HEAD(path string, handlers ...HandlerFunc) *Route
HEAD registers a handler for HEAD requests.
func (*Server) Handle ¶
func (s *Server) Handle(method, path string, handlers ...HandlerFunc) *Route
Handle registers a handler for the given HTTP method and path pattern. Use this for non-standard methods (e.g., WebDAV PROPFIND) or when the method is determined at runtime.
func (*Server) MethodNotAllowed ¶
func (s *Server) MethodNotAllowed(handler HandlerFunc) *Server
MethodNotAllowed registers a custom handler for requests where the path matches but the HTTP method does not. The Allow header is set automatically.
func (*Server) NotFound ¶
func (s *Server) NotFound(handler HandlerFunc) *Server
NotFound registers a custom handler for requests that do not match any route.
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris"
)
func main() {
s := celeris.New(celeris.Config{Addr: ":8080"})
s.NotFound(func(c *celeris.Context) error {
return c.JSON(404, map[string]string{"error": "not found"})
})
fmt.Println("custom 404 set")
}
Output: custom 404 set
func (*Server) OPTIONS ¶
func (s *Server) OPTIONS(path string, handlers ...HandlerFunc) *Route
OPTIONS registers a handler for OPTIONS requests.
func (*Server) PATCH ¶
func (s *Server) PATCH(path string, handlers ...HandlerFunc) *Route
PATCH registers a handler for PATCH requests.
func (*Server) POST ¶
func (s *Server) POST(path string, handlers ...HandlerFunc) *Route
POST registers a handler for POST requests.
func (*Server) PUT ¶
func (s *Server) PUT(path string, handlers ...HandlerFunc) *Route
PUT registers a handler for PUT requests.
func (*Server) PauseAccept ¶ added in v1.2.0
PauseAccept stops accepting new connections. Existing connections continue to be served. Returns ErrAcceptControlNotSupported if the engine does not support accept control (e.g. std engine).
func (*Server) ResumeAccept ¶ added in v1.2.0
ResumeAccept resumes accepting new connections after PauseAccept. Returns ErrAcceptControlNotSupported if the engine does not support accept control.
func (*Server) Routes ¶
Routes returns information about all registered routes. Output is sorted by method, then path for deterministic results.
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris"
)
func main() {
s := celeris.New(celeris.Config{Addr: ":8080"})
s.GET("/a", func(_ *celeris.Context) error { return nil })
s.POST("/b", func(_ *celeris.Context) error { return nil })
routes := s.Routes()
fmt.Println(len(routes))
}
Output: 2
func (*Server) Shutdown ¶
Shutdown gracefully shuts down the server. Returns nil if the server has not been started.
func (*Server) Start ¶
Start initializes and starts the server, blocking until Shutdown is called or the engine returns an error. Use StartWithContext for context-based lifecycle management.
Returns ErrAlreadyStarted if called more than once. May also return configuration validation errors or engine initialization errors.
func (*Server) StartWithContext ¶
StartWithContext starts the server with the given context for lifecycle management. When the context is canceled, the server shuts down gracefully using Config.ShutdownTimeout (default 30s).
Returns ErrAlreadyStarted if called more than once. May also return configuration validation errors or engine initialization errors.
Example ¶
package main
import (
"context"
"fmt"
"os"
"os/signal"
"github.com/goceleris/celeris"
)
func main() {
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
_ = ctx // prevent unused error
s := celeris.New(celeris.Config{Addr: ":8080"})
s.GET("/ping", func(c *celeris.Context) error {
return c.String(200, "pong")
})
// In a real app: log.Fatal(s.StartWithContext(ctx))
fmt.Println("configured")
}
Output: configured
func (*Server) StartWithListener ¶ added in v1.1.0
StartWithListener starts the server using an existing net.Listener. This enables zero-downtime restarts via socket inheritance (e.g., passing the listener FD to a child process via environment variable).
Returns ErrAlreadyStarted if called more than once.
func (*Server) StartWithListenerAndContext ¶ added in v1.1.0
StartWithListenerAndContext combines Server.StartWithListener and Server.StartWithContext. When the context is canceled, the server shuts down gracefully using [Config.ShutdownTimeout].
func (*Server) Static ¶ added in v1.1.0
Static registers a GET handler that serves files from root under the given prefix. Uses FileFromDir for path traversal protection.
s.Static("/assets", "./public")
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris"
)
func main() {
s := celeris.New(celeris.Config{Addr: ":8080"})
s.Static("/assets", "./public")
routes := s.Routes()
fmt.Println(routes[0].Method, routes[0].Path)
}
Output: GET /assets/*filepath
func (*Server) URL ¶
URL generates a URL for the named route by substituting positional parameters. Parameter values are substituted in order for :param segments. For *catchAll segments, the value replaces the wildcard (a leading "/" is de-duplicated). Values are inserted as-is without URL encoding — callers should encode if needed. Returns ErrRouteNotFound if no route with the given name exists.
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris"
)
func main() {
s := celeris.New(celeris.Config{Addr: ":8080"})
s.GET("/users/:id", func(_ *celeris.Context) error { return nil }).Name("user")
url, err := s.URL("user", "42")
fmt.Println(url, err)
}
Output: /users/42 <nil>
func (*Server) URLMap ¶
URLMap generates a URL for the named route by substituting named parameters from a map. This is an alternative to Server.URL that avoids positional ordering errors. Returns ErrRouteNotFound if no route with the given name has been registered.
func (*Server) Use ¶
func (s *Server) Use(middleware ...HandlerFunc) *Server
Use registers global middleware that runs before every route handler. Middleware executes in registration order. Middleware chains are composed at route registration time, so Use must be called before registering routes.
Example ¶
package main
import (
"fmt"
"github.com/goceleris/celeris"
)
func main() {
s := celeris.New(celeris.Config{Addr: ":8080"})
s.Use(func(c *celeris.Context) error {
fmt.Println("middleware executed")
return c.Next()
})
s.GET("/", func(c *celeris.Context) error {
return c.String(200, "ok")
})
fmt.Println("middleware registered")
}
Output: middleware registered
type StreamWriter ¶ added in v1.1.0
type StreamWriter struct {
// contains filtered or unexported fields
}
StreamWriter provides incremental response writing. Obtained via Context.StreamWriter.
func (*StreamWriter) Close ¶ added in v1.1.0
func (sw *StreamWriter) Close() error
Close signals end of the response body.
func (*StreamWriter) Flush ¶ added in v1.1.0
func (sw *StreamWriter) Flush() error
Flush ensures buffered data is sent to the network.
func (*StreamWriter) Write ¶ added in v1.1.0
func (sw *StreamWriter) Write(data []byte) (int, error)
Write sends a chunk of the response body. May be called multiple times.
func (*StreamWriter) WriteHeader ¶ added in v1.1.0
func (sw *StreamWriter) WriteHeader(status int, headers [][2]string) error
WriteHeader sends the status line and headers. Must be called once before Write.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package adaptive implements a dual-engine controller that dynamically switches between io_uring and epoll based on runtime telemetry.
|
Package adaptive implements a dual-engine controller that dynamically switches between io_uring and epoll based on runtime telemetry. |
|
Package celeristest provides test utilities for celeris handlers.
|
Package celeristest provides test utilities for celeris handlers. |
|
Package engine defines the core Engine interface and associated types used by all I/O engine implementations (io_uring, epoll, adaptive, std).
|
Package engine defines the core Engine interface and associated types used by all I/O engine implementations (io_uring, epoll, adaptive, std). |
|
epoll
Package epoll implements the epoll-based I/O engine for Linux.
|
Package epoll implements the epoll-based I/O engine for Linux. |
|
iouring
Package iouring implements an engine backed by Linux io_uring.
|
Package iouring implements an engine backed by Linux io_uring. |
|
std
Package std provides an engine implementation backed by net/http.
|
Package std provides an engine implementation backed by net/http. |
|
Package internal contains shared utilities.
|
Package internal contains shared utilities. |
|
conn
Package conn provides shared HTTP/1.1 and HTTP/2 connection handling.
|
Package conn provides shared HTTP/1.1 and HTTP/2 connection handling. |
|
cpumon
Package cpumon provides CPU utilization monitoring with platform-specific implementations.
|
Package cpumon provides CPU utilization monitoring with platform-specific implementations. |
|
ctxkit
Package ctxkit provides internal hooks for creating and releasing celeris contexts from the celeristest package without exposing implementation types in the public API.
|
Package ctxkit provides internal hooks for creating and releasing celeris contexts from the celeristest package without exposing implementation types in the public API. |
|
negotiate
Package negotiate provides HTTP content negotiation utilities.
|
Package negotiate provides HTTP content negotiation utilities. |
|
platform
Package platform provides OS-level helpers for CPU pinning and NUMA distribution.
|
Package platform provides OS-level helpers for CPU pinning and NUMA distribution. |
|
sockopts
Package sockopts provides socket option helpers for TCP tuning across platforms.
|
Package sockopts provides socket option helpers for TCP tuning across platforms. |
|
timer
Package timer implements a hierarchical timer wheel for efficient timeout management in event-driven I/O engines.
|
Package timer implements a hierarchical timer wheel for efficient timeout management in event-driven I/O engines. |
|
middleware
|
|
|
compress
module
|
|
|
metrics
module
|
|
|
otel
module
|
|
|
Package observe provides lightweight, lock-free metrics collection for celeris servers.
|
Package observe provides lightweight, lock-free metrics collection for celeris servers. |
|
Package probe provides capability detection for io_uring and epoll.
|
Package probe provides capability detection for io_uring and epoll. |
|
protocol
|
|
|
detect
Package detect provides HTTP protocol detection from initial connection bytes.
|
Package detect provides HTTP protocol detection from initial connection bytes. |
|
h1
Package h1 implements a zero-copy HTTP/1.1 parser.
|
Package h1 implements a zero-copy HTTP/1.1 parser. |
|
h2
Package h2 provides HTTP/2 frame handling and stream management.
|
Package h2 provides HTTP/2 frame handling and stream management. |
|
h2/frame
Package frame provides HTTP/2 frame type definitions, parsing, writing, and HPACK integration.
|
Package frame provides HTTP/2 frame type definitions, parsing, writing, and HPACK integration. |
|
h2/stream
Package stream manages HTTP/2 stream lifecycle, state transitions, flow control, and frame processing.
|
Package stream manages HTTP/2 stream lifecycle, state transitions, flow control, and frame processing. |
|
Package resource defines server configuration, resource limits, and default presets.
|
Package resource defines server configuration, resource limits, and default presets. |
|
test
|
|
|
benchmark/framework
command
Package main runs a standalone celeris.Server for external benchmarking with wrk, hey, or other load generators.
|
Package main runs a standalone celeris.Server for external benchmarking with wrk, hey, or other load generators. |
|
benchmark/profiled
command
Package main runs a celeris framework server with pprof profiling enabled.
|
Package main runs a celeris framework server with pprof profiling enabled. |
|
benchmark/server
command
Package main runs a standalone celeris server for external benchmarking with wrk, hey, or other load generators.
|
Package main runs a standalone celeris server for external benchmarking with wrk, hey, or other load generators. |
|
iouring-probe
command
Minimal io_uring probe that tests every flag combination to find what works.
|
Minimal io_uring probe that tests every flag combination to find what works. |
|
loadtest
command
Package main runs load tests against all celeris engine configurations.
|
Package main runs load tests against all celeris engine configurations. |
|
loadtest/fullstack
command
Package main runs full-stack load tests through the celeris.Server application layer (router, Context, JSON encoding, response writing) across all engine configs.
|
Package main runs full-stack load tests through the celeris.Server application layer (router, Context, JSON encoding, response writing) across all engine configs. |
|
loadtest/rawtcp
command
Package main runs a raw TCP load test against celeris.Server to measure server-side performance without Go HTTP client overhead.
|
Package main runs a raw TCP load test against celeris.Server to measure server-side performance without Go HTTP client overhead. |