Rename the settings whose names do not say what they control (closes #234)
check / check (push) Waiting to run

Applies the setting renames of the naming audit under the SWW_WAF_ and
SWW_RPROXY_ prefixes, with sneak's names for the IP reputation cache
time and the two time limits, which now take milliseconds. The rproxy
log field default_disposition becomes waf_backend_no_answer, and
config.Config and config.FromEnvironment become config.WAF and
config.WAFFromEnvironment. Go fields, test names and prose follow. No
aliases; nothing reads the old names.

Model: opus-5-5
This commit is contained in:
clawbot committed 2026-11-12 05:53:58 +00:00
1 parent aaa9719f02
commit 36c4f91583
97 files changed
+1928 -1728

No files matched your search

+2 -2
View File
@@ -407,7 +407,7 @@ func TestAMethodNotPassedOnIsAnswered405(t *testing.T) {
line := out.requestLine(t)
if line["status"] != float64(http.StatusMethodNotAllowed) ||
line["disposition"] != nil || line["default_disposition"] != nil {
line["disposition"] != nil || line["waf_backend_no_answer"] != nil {
t.Errorf("line %v, want status 405 and no disposition", line)
}
@@ -490,7 +490,7 @@ func TestARequestThatCannotGoToWAFAsSentIsRefused(t *testing.T) {
line := out.requestLine(t)
if line["status"] != float64(http.StatusBadRequest) ||
line["disposition"] != nil || line["default_disposition"] != nil {
line["disposition"] != nil || line["waf_backend_no_answer"] != nil {
t.Errorf("line %v, want status 400 and no disposition", line)
}
+6 -5
View File
@@ -61,12 +61,13 @@ type request struct {
start time.Time
// disposition is what is done with the request: waf's valid disposition,
// or SWW_RPROXY_DEFAULT_DISPOSITION. It is "" when neither gave one.
// or SWW_RPROXY_WAF_BACKEND_NO_ANSWER_DISPOSITION. It is "" when neither
// gave one.
disposition string
// answered is true when waf gave disposition, which makes a report due,
// and byDefault when SWW_RPROXY_DEFAULT_DISPOSITION did.
answered bool
byDefault bool
// and wafNoAnswer when SWW_RPROXY_WAF_BACKEND_NO_ANSWER_DISPOSITION did.
answered bool
wafNoAnswer bool
// asn and country are waf's X-Client-ASN and X-Client-Country, for the
// app.
asn, country string
@@ -450,7 +451,7 @@ func (rq *request) finish(ctx context.Context) {
),
DurationResponseMS: requestlog.Milliseconds(end.Sub(requestEnd)),
Disposition: rq.disposition,
DefaultDisposition: rq.byDefault,
WAFBackendNoAnswer: rq.wafNoAnswer,
},
)
if err != nil {
+8 -5
View File
@@ -1,9 +1,10 @@
// Package rproxy is the reverse proxy in front of one app that asks waf
// about each request. It passes a request waf allows to the app and the
// app's answer back, within the size and time limits. Any other answer from
// waf goes to the visitor as waf gave it. SWW_RPROXY_DEFAULT_DISPOSITION
// decides only when waf cannot be connected to, does not answer at all, or
// does not answer within SWW_RPROXY_TIMEOUT_MS. rproxy itself refuses a request with a
// waf goes to the visitor as waf gave it.
// SWW_RPROXY_WAF_BACKEND_NO_ANSWER_DISPOSITION decides only when waf cannot
// be connected to, does not answer at all, or does not answer within
// SWW_RPROXY_WAF_BACKEND_TIMEOUT_MS. rproxy itself refuses a request with a
// method it does not pass on, or one it cannot put to waf as the visitor
// sent it. It keeps nothing between requests and writes nothing to disk. "rproxy" in
// SPEC.md says what it does.
@@ -108,7 +109,8 @@ func New(params Params) *Server {
}
// WaitForReports returns once the reports being sent have gone or failed,
// which SWW_RPROXY_TIMEOUT_MS bounds. Any report after this call is dropped: that of
// which SWW_RPROXY_WAF_BACKEND_TIMEOUT_MS bounds. Any report after this call
// is dropped: that of
// a WebSocket that closes while rproxy stops, for one.
func (s *Server) WaitForReports() {
s.h.reportsMu.Lock()
@@ -217,7 +219,8 @@ 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. waf answers a path under ownEndpointPrefix itself, so
// such a request gets here only when SWW_RPROXY_DEFAULT_DISPOSITION allowed it.
// such a request gets here only when
// SWW_RPROXY_WAF_BACKEND_NO_ANSWER_DISPOSITION allowed it.
// ctx is the request's own context.
func (rq *request) passToApp(ctx context.Context) {
maxBytes := rq.h.config.MaxRequestSize
+23 -23
View File
@@ -44,13 +44,13 @@ const (
// The settings the tests set.
const (
timeoutSetting = "SWW_RPROXY_TIMEOUT_MS"
defaultDisposition = "SWW_RPROXY_DEFAULT_DISPOSITION"
trustedProxies = "SWW_RPROXY_TRUSTED_PROXIES"
maxRequestSize = "SWW_RPROXY_MAX_REQUEST_SIZE"
maxResponseSize = "SWW_RPROXY_MAX_RESPONSE_SIZE"
maxRequestTime = "SWW_RPROXY_MAX_REQUEST_TIME_MS"
maxResponseTime = "SWW_RPROXY_MAX_RESPONSE_TIME_MS"
timeoutSetting = "SWW_RPROXY_WAF_BACKEND_TIMEOUT_MS"
noAnswerSetting = "SWW_RPROXY_WAF_BACKEND_NO_ANSWER_DISPOSITION"
trustedProxies = "SWW_RPROXY_TRUSTED_PROXIES"
maxRequestSize = "SWW_RPROXY_MAX_REQUEST_SIZE"
maxResponseSize = "SWW_RPROXY_MAX_RESPONSE_SIZE"
maxRequestTime = "SWW_RPROXY_MAX_REQUEST_TIME_MS"
maxResponseTime = "SWW_RPROXY_MAX_RESPONSE_TIME_MS"
)
// The headers the tests set and look at.
@@ -774,7 +774,7 @@ func TestDenyGivesTheVisitorWAFsAnswer(t *testing.T) {
line := out.requestLine(t)
if line["disposition"] != dispositionDeny ||
line["default_disposition"] != nil {
line["waf_backend_no_answer"] != nil {
t.Errorf("line %v, want waf's deny", line)
}
}
@@ -1031,7 +1031,7 @@ func TestAnAnswerOtherThanAllowGoesToTheVisitorAsWAFGaveIt(t *testing.T) {
standIn.URL,
app.URL,
map[string]string{
defaultDisposition: setting,
noAnswerSetting: setting,
},
)
@@ -1047,7 +1047,7 @@ func TestAnAnswerOtherThanAllowGoesToTheVisitorAsWAFGaveIt(t *testing.T) {
line := out.requestLine(t)
if line["status"] != float64(tc.status) ||
line["default_disposition"] != nil {
line["waf_backend_no_answer"] != nil {
t.Errorf(
"line %v, want status %d and no default",
line,
@@ -1213,8 +1213,8 @@ func TestAnAnswerThatCannotBePassedOnIsAnswered502(t *testing.T) {
backend(t),
app.URL,
map[string]string{
timeoutSetting: "60000",
defaultDisposition: setting,
timeoutSetting: "60000",
noAnswerSetting: setting,
},
)
@@ -1224,7 +1224,7 @@ func TestAnAnswerThatCannotBePassedOnIsAnswered502(t *testing.T) {
line := out.requestLine(t)
if line["status"] != float64(http.StatusBadGateway) ||
line["disposition"] != nil || line["default_disposition"] != nil {
line["disposition"] != nil || line["waf_backend_no_answer"] != nil {
t.Errorf(
"line %v, want status 502 and no disposition",
line,
@@ -1274,7 +1274,7 @@ func TestWithoutAnAnswerTheDefaultDispositionDecides(t *testing.T) {
line := out.requestLine(t)
if line["disposition"] != dispositionAllow ||
line["default_disposition"] != true {
line["waf_backend_no_answer"] != true {
t.Errorf("line %v, want allow by default", line)
}
})
@@ -1290,8 +1290,8 @@ func TestWithoutAnAnswerTheDefaultDispositionDecides(t *testing.T) {
backend(t),
app.URL,
map[string]string{
timeoutSetting: "200",
defaultDisposition: dispositionDeny,
timeoutSetting: "200",
noAnswerSetting: dispositionDeny,
},
)
@@ -1302,7 +1302,7 @@ func TestWithoutAnAnswerTheDefaultDispositionDecides(t *testing.T) {
line := out.requestLine(t)
if line["disposition"] != dispositionDeny ||
line["default_disposition"] != true {
line["waf_backend_no_answer"] != true {
t.Errorf("line %v, want deny by default", line)
}
})
@@ -1330,8 +1330,8 @@ func TestAVisitorThatGoesAwayWhileWAFIsAskedGetsNoDefault(t *testing.T) {
standIn.URL,
app.URL,
map[string]string{
timeoutSetting: "60000",
defaultDisposition: disposition,
timeoutSetting: "60000",
noAnswerSetting: disposition,
},
)
@@ -1343,7 +1343,7 @@ func TestAVisitorThatGoesAwayWhileWAFIsAskedGetsNoDefault(t *testing.T) {
line := out.requestLine(t)
if line["status"] != 0.0 || line["disposition"] != nil ||
line["default_disposition"] != nil {
line["waf_backend_no_answer"] != nil {
t.Errorf("line %v, want status 0 and no disposition", line)
}
@@ -1892,10 +1892,10 @@ func TestLogLineGivesTheRequestAsSent(t *testing.T) {
}
}
if line["default_disposition"] != nil {
if line["waf_backend_no_answer"] != nil {
t.Errorf(
"default_disposition is %v, want it left out",
line["default_disposition"],
"waf_backend_no_answer is %v, want it left out",
line["waf_backend_no_answer"],
)
}
+12 -11
View File
@@ -67,15 +67,16 @@ func (rq *request) handleNoUsableAnswer(ctx context.Context, err error) {
rq.answer(http.StatusBadGateway)
default:
// waf cannot be connected to, does not answer at all, or does not answer
// within SWW_RPROXY_TIMEOUT_MS. A request that keeps waf busy past
// SWW_RPROXY_TIMEOUT_MS, like any request while waf is overloaded, gets
// SWW_RPROXY_DEFAULT_DISPOSITION here. deny closes this, at the cost of answering 503
// whenever waf is slow. Making such requests hard to send is
// within SWW_RPROXY_WAF_BACKEND_TIMEOUT_MS. A request that keeps waf
// busy past SWW_RPROXY_WAF_BACKEND_TIMEOUT_MS, like any request while
// waf is overloaded, gets SWW_RPROXY_WAF_BACKEND_NO_ANSWER_DISPOSITION
// here. deny closes this, at the cost of answering 503 whenever waf is
// slow. Making such requests hard to send is
// https://git.eeqj.de/sneak/smallwebwaf/issues/182.
rq.h.processLog.Warn("waf gave no answer", "error", err.Error())
rq.disposition = rq.h.config.DefaultDisposition
rq.byDefault = true
rq.disposition = rq.h.config.WAFBackendNoAnswerDisposition
rq.wafNoAnswer = true
if rq.disposition == waf.DispositionAllow {
rq.passToApp(ctx)
@@ -86,10 +87,10 @@ func (rq *request) handleNoUsableAnswer(ctx context.Context, err error) {
}
// ask sends waf the question, and returns its answer, which must have come
// whole within SWW_RPROXY_TIMEOUT_MS. It ends when ctx does, as when the visitor goes
// away.
// whole within SWW_RPROXY_WAF_BACKEND_TIMEOUT_MS. It ends when ctx does, as
// when the visitor goes away.
func (rq *request) ask(ctx context.Context) (*wafAnswer, error) {
ctx, cancel := context.WithTimeout(ctx, rq.h.config.Timeout)
ctx, cancel := context.WithTimeout(ctx, rq.h.config.WAFBackendTimeout)
defer cancel()
question, err := rq.newQuestion(ctx)
@@ -242,14 +243,14 @@ func (h *handler) sendReport(ctx context.Context, report *waf.Report) {
}
// postReport posts report to waf, and waits for its answer for up to
// SWW_RPROXY_TIMEOUT_MS.
// SWW_RPROXY_WAF_BACKEND_TIMEOUT_MS.
func (h *handler) postReport(ctx context.Context, report *waf.Report) error {
body, err := json.Marshal(report)
if err != nil {
return fmt.Errorf("encode the report: %w", err)
}
ctx, cancel := context.WithTimeout(ctx, h.config.Timeout)
ctx, cancel := context.WithTimeout(ctx, h.config.WAFBackendTimeout)
defer cancel()
req, err := http.NewRequestWithContext( //nolint:gosec // a setting's URL