-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Closed as duplicate
Closed as duplicate
Copy link
Description
Since version 2.9.0, returning an error
in a caddy middleware's ServeHTTP
function causes caddy to fail silently. Only with the debug
option, the cause is visible.
Minimal caddy middleware example
package caddy_error_handling
import (
"errors"
"net/http"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
)
func init() {
caddy.RegisterModule(Example{})
httpcaddyfile.RegisterHandlerDirective("example", parseCaddyfile)
}
type Example struct {
}
func (Example) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "http.handlers.example",
New: func() caddy.Module { return new(Example) },
}
}
func (m Example) UnmarshalCaddyfile(_ *caddyfile.Dispenser) error { return nil }
func (m Example) ServeHTTP(w http.ResponseWriter, _ *http.Request, _ caddyhttp.Handler) error {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("error"))
return errors.New("example error")
}
func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
var m Example
err := m.UnmarshalCaddyfile(h.Dispenser)
return m, err
}
Caddyfile:
{
debug
order example before respond
}
http:// {
example
respond 200 {
body ok
close
}
}
When executing a HTTP request that uses the middleware, there is no response:
❯ curl -v http://localhost
* Host localhost:80 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:80...
* Connected to localhost (::1) port 80
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/8.7.1
> Accept: */*
>
* Request completely sent off
* Empty reply from server
* Closing connection
curl: (52) Empty reply from server
In debug mode, caddy logs:
2025/02/06 16:48:54.648 DEBUG http.stdlib http: panic serving [::1]:56190: runtime error: invalid memory address or nil pointer dereference
goroutine 51 [running]:
net/http.(*conn).serve.func1()
net/http/server.go:1947 +0xb0
panic({0x1041657e0?, 0x104f7f390?})
runtime/panic.go:785 +0x124
github.com/caddyserver/caddy/v2/modules/caddyhttp.(*Server).ServeHTTP(0x140003aaa88, {0x1043b8478, 0x1400057e0e0}, 0x140003b6140)
github.com/caddyserver/caddy/v2@v2.9.0/modules/caddyhttp/server.go:445 +0xf00
net/http.serverHandler.ServeHTTP({0x1400037a420?}, {0x1043b8478?, 0x1400057e0e0?}, 0x6?)
net/http/server.go:3210 +0xbc
net/http.(*conn).serve(0x140004be2d0, {0x1043bba40, 0x14000148540})
net/http/server.go:2092 +0x4fc
created by net/http.(*Server).Serve in goroutine 71
net/http/server.go:3360 +0x3dc
When running caddy 2.8, there is no error, and caddy responds with HTTP 400 and "error", as it should be.
To mitigate this, can return a caddyhttp.HandlerError
instead of a plain error
in the ServeHTTP
function:
func (m Example) ServeHTTP(w http.ResponseWriter, _ *http.Request, _ caddyhttp.Handler) error {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("error"))
return caddyhttp.HandlerError{
StatusCode: http.StatusBadRequest,
Err: errors.New("example error"),
}
}
If it is expected that a HandlerError
is returned, then this should be documented in the httphandler.Handler
or httphandler.MiddlewareHandler
interfaces.
Metadata
Metadata
Assignees
Labels
No labels