Rename the program to sww and its deciding daemon to discriminator (closes #218) (#221)
check / check (push) Failing after 1m34s

This commit was merged in pull request #221.
This commit is contained in:
clawbot committed 2026-11-07 06:51:06 +01:00
1 parent 2e2f6f7175
commit beb503b233
106 files changed
+3302 -3275

No files matched your search

+33 -33
View File
@@ -1,10 +1,10 @@
// Package rproxy is the reverse proxy in front of one app that asks servewaf
// about each request. It passes a request servewaf allows to the app and the
// Package rproxy is the reverse proxy in front of one app that asks discriminator
// about each request. It passes a request discriminator allows to the app and the
// app's answer back, within the size and time limits. Any other answer from
// servewaf goes to the visitor as servewaf gave it. SWRP_DEFAULT_DISPOSITION
// decides only when servewaf cannot be connected to, does not answer at all, or
// discriminator goes to the visitor as discriminator gave it. SWRP_DEFAULT_DISPOSITION
// decides only when discriminator cannot be connected to, does not answer at all, or
// does not answer within SWRP_TIMEOUT_MS. rproxy itself refuses a request with a
// method it does not pass on, or one it cannot put to servewaf as the visitor
// method it does not pass on, or one it cannot put to discriminator as the visitor
// sent it. It keeps nothing between requests and never touches disk. "rproxy" in
// SPEC.md says what it does.
package rproxy
@@ -22,10 +22,10 @@ import (
"time"
"sneak.berlin/go/smallwebwaf/internal/config"
"sneak.berlin/go/smallwebwaf/internal/servewaf"
"sneak.berlin/go/smallwebwaf/internal/discriminator"
)
// How rproxy keeps connections to the app and to servewaf open between
// How rproxy keeps connections to the app and to discriminator open between
// requests.
const (
idleConns = 100
@@ -45,9 +45,9 @@ const (
idleTimeout = 120 * time.Second
)
// adminPrefix starts the path of every request for smallwebwaf itself, which
// adminPrefix starts the path of every request for sww itself, which
// never reaches the app.
const adminPrefix = "/_smallwebwaf/"
const adminPrefix = "/_sww/"
// allowedMethods lists the methods rproxy passes on, as an Allow header gives
// them. It answers any other method 405 itself.
@@ -62,14 +62,14 @@ type Params struct {
ProcessLog *slog.Logger
}
// Server is the server `smallwebwaf rproxy` runs.
// Server is the server `sww rproxy` runs.
type Server struct {
*http.Server
h *handler
}
// New returns the server `smallwebwaf rproxy` runs. Go's server itself refuses
// New returns the server `sww rproxy` runs. Go's server itself refuses
// a request line and headers over requestHeaderMaxBytes, with 431, closes a
// connection idle for idleTimeout, and applies SWRP_MAX_REQUEST_TIME_MS while
// the headers arrive. The handler applies the time and size limits from then
@@ -78,14 +78,14 @@ func New(params Params) *Server {
backend := params.Config.WAFBackend
errorLog := slog.NewLogLogger(params.ProcessLog.Handler(), slog.LevelWarn)
h := &handler{
config: params.Config,
requestLog: params.RequestLog,
processLog: params.ProcessLog,
errorLog: errorLog,
transport: newTransport(),
serveWAFTransport: newServeWAFTransport(),
config: params.Config,
requestLog: params.RequestLog,
processLog: params.ProcessLog,
errorLog: errorLog,
transport: newTransport(),
discriminatorTransport: newDiscriminatorTransport(),
reportURL: (&url.URL{
Scheme: backend.Scheme, Host: backend.Host, Path: servewaf.ReportPath,
Scheme: backend.Scheme, Host: backend.Host, Path: discriminator.ReportPath,
}).String(),
}
@@ -120,10 +120,10 @@ type handler struct {
requestLog io.Writer
processLog *slog.Logger
errorLog *log.Logger
// transport carries requests to the app, and serveWAFTransport questions and
// reports to servewaf.
transport http.RoundTripper
serveWAFTransport http.RoundTripper
// transport carries requests to the app, and discriminatorTransport questions and
// reports to discriminator.
transport http.RoundTripper
discriminatorTransport http.RoundTripper
// reportURL is where the reports go.
reportURL string
// reports waits for the reports being sent. reportsMu guards starting one
@@ -145,11 +145,11 @@ func newTransport() *http.Transport {
}
}
// newServeWAFTransport returns what carries questions and reports to servewaf.
// It speaks HTTP/1.1 only. Go's HTTP/2 client refuses to send a visitor's Upgrade
// header, or a Connection header other than close or keep-alive, and that would
// read as servewaf giving no answer.
func newServeWAFTransport() *http.Transport {
// newDiscriminatorTransport returns what carries questions and reports to
// discriminator. It speaks HTTP/1.1 only. Go's HTTP/2 client refuses to send
// a visitor's Upgrade header, or a Connection header other than close or
// keep-alive, and that would read as discriminator giving no answer.
func newDiscriminatorTransport() *http.Transport {
transport := newTransport()
transport.Protocols = new(http.Protocols)
transport.Protocols.SetHTTP1(true)
@@ -158,15 +158,15 @@ func newServeWAFTransport() *http.Transport {
}
// ServeHTTP handles one request: it answers the health check itself, refuses a
// request with a method it does not pass on or one it cannot put to servewaf as
// request with a method it does not pass on or one it cannot put to discriminator as
// the visitor sent it, and for any other request reads the first part of the
// body, asks servewaf, and does what the answer says. Once the answer has ended,
// body, asks discriminator, and does what the answer says. Once the answer has ended,
// it writes the request's log line and sends its report.
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
rq := h.newRequest(w, r)
defer rq.finish(r.Context())
if r.Method == http.MethodGet && r.URL.Path == servewaf.HealthPath {
if r.Method == http.MethodGet && r.URL.Path == discriminator.HealthPath {
rq.answerHealth()
return
@@ -199,9 +199,9 @@ func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
rq.noteAnswer(answer)
switch rq.disposition {
case servewaf.DispositionAllow:
case discriminator.DispositionAllow:
rq.passToApp(r.Context())
case servewaf.DispositionClose:
case discriminator.DispositionClose:
// This panic has Go's server close the connection without an answer,
// and log nothing; the deferred finish still runs.
panic(http.ErrAbortHandler)
@@ -211,7 +211,7 @@ func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
// passToApp passes the request on to the app, unless a limit or its path keeps
// it from the app. servewaf answers a path under adminPrefix itself, so such a
// it from the app. discriminator answers a path under adminPrefix itself, so such a
// request gets here only when SWRP_DEFAULT_DISPOSITION allowed it. ctx is the
// request's own context.
func (rq *request) passToApp(ctx context.Context) {