check / check (push) Canceled after 0s
The 30-second limit is now chi's middleware.Timeout, which answers 504 and never writes from a second goroutine. It runs after JSONResponseMiddleware, so a handler that wrote nothing is not sent a 200 first. One rule covers the handlers: right after each database read or host name lookup, before looking at what came back, error or not, a handler asks deadlinePassed whether the time limit has passed and, if so, answers 504, with the JSON error body on JSON routes. A cut-off read can return an error, or part of its rows or none without one, so only this check tells it from a complete read. JSONValidationMiddleware answers 504 with the JSON error body when the limit has passed and the handler wrote nothing. Model: opus-5-5
56 lines
1.7 KiB
Go
56 lines
1.7 KiB
Go
package server
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/go-chi/chi/v5/middleware"
|
|
)
|
|
|
|
// setupRoutes configures the HTTP routes
|
|
func (s *Server) setupRoutes() {
|
|
r := chi.NewRouter()
|
|
|
|
// Middleware
|
|
r.Use(middleware.RequestID)
|
|
r.Use(middleware.RealIP)
|
|
r.Use(RequestLoggerMiddleware(s.logger.Logger)) // Structured request logging
|
|
r.Use(middleware.Recoverer)
|
|
r.Use(JSONResponseMiddleware)
|
|
// Timeout must come after JSONResponseMiddleware, which sends its answer
|
|
// when the handler returns and would send a 200 ahead of Timeout's 504 for
|
|
// a handler that wrote nothing.
|
|
const requestTimeout = 30 * time.Second // Increased from 8s for slow queries
|
|
r.Use(middleware.Timeout(requestTimeout))
|
|
|
|
// Routes
|
|
r.Get("/", s.handleIndex())
|
|
r.Get("/status", s.handleStatusHTML())
|
|
r.Get("/status.json", JSONValidationMiddleware(s.handleStatusJSON()).ServeHTTP)
|
|
r.Get("/.well-known/healthcheck.json", JSONValidationMiddleware(s.handleHealthCheck()).ServeHTTP)
|
|
|
|
// AS and prefix detail pages
|
|
r.Get("/as/{asn}", s.handleASDetail())
|
|
r.Get("/prefix/{prefix}/{len}", s.handlePrefixDetail())
|
|
r.Get("/prefixlength/{length}", s.handlePrefixLength())
|
|
r.Get("/prefixlength6/{length}", s.handlePrefixLength6())
|
|
|
|
// IP info JSON endpoints (replaces old /ip redirect)
|
|
r.Route("/ip", func(r chi.Router) {
|
|
r.Use(JSONValidationMiddleware)
|
|
r.Get("/", s.handleIPInfo()) // Client IP
|
|
r.Get("/{addr}", s.handleIPInfo()) // Specified IP
|
|
})
|
|
|
|
// API routes
|
|
r.Route("/api/v1", func(r chi.Router) {
|
|
r.Use(JSONValidationMiddleware)
|
|
r.Get("/stats", s.handleStats())
|
|
r.Get("/ip/{ip}", s.handleIPLookup())
|
|
r.Get("/as/{asn}", s.handleASDetailJSON())
|
|
r.Get("/prefix/{prefix}/{len}", s.handlePrefixDetailJSON())
|
|
})
|
|
|
|
s.router = r
|
|
}
|