A route may have its own listener: every request there is that route, paths unprefixed

Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
This commit is contained in:
2026-09-25 19:59:21 -07:00
parent 35b07ece81
commit fa1c398fc4
10 changed files with 392 additions and 12 deletions
+33 -3
View File
@@ -198,15 +198,45 @@ func peekModel(r *http.Request) (string, []byte, error) {
return req.Model, body, nil
}
// ServeHTTP routes, fingerprints, leases a host, queues per (host, model), forwards with streaming,
// tees the response for usage/timings, and records one accounting row. Every error answer is JSON
// {"error":"…"}.
// ServeHTTP routes, then serves the request over the shared flow below: fingerprint, lease a host,
// queue per (host, model), forward with streaming, tee the response for usage/timings, and record
// one accounting row. Every error answer is JSON {"error":"…"}.
func (p *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
route, rest, code, msg := p.route(r)
if code != 0 {
p.writeError(w, code, msg)
return
}
p.serve(w, r, route, rest)
}
// ForRoute serves route alone, for its dedicated listener: every request there is this route, the
// whole path passed upstream as it is (no route segment is taken from it). A request from an unknown
// route is 404; a different X-Crossbar-Route header is a 400 (an equal one is ignored); a prefixed
// path or a path outside the allowed set is 404. Then it runs the same serve flow as ServeHTTP.
func (p *Handler) ForRoute(route string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if _, _, ok := p.cfg.Route(route); !ok {
p.writeError(w, http.StatusNotFound, "unknown route")
return
}
if hdr := r.Header.Get(RouteHeader); hdr != "" && hdr != route {
p.writeError(w, http.StatusBadRequest, "conflicting route")
return
}
rest := r.URL.Path
if !allowedPath(rest) {
p.writeError(w, http.StatusNotFound, "not found")
return
}
p.serve(w, r, route, rest)
})
}
// serve fingerprints, leases a host, queues per (host, model), forwards with streaming, tees the
// response for usage/timings, and records one accounting row. Both ServeHTTP and ForRoute reach this
// after they have settled the route and the upstream path (rest).
func (p *Handler) serve(w http.ResponseWriter, r *http.Request, route, rest string) {
routeCfg, _, _ := p.cfg.Route(route)
isControl := isControlCall(r.Method, rest)