Rename internal/proxy to internal/servewaf (closes #173)
check / check (push) Successful in 3m44s

The package passes nothing on since the one-process mode went: it answers rproxy's questions, takes its reports and answers servewaf's own endpoints. It is now named after the command it serves, with `git mv`, and its constructor is `servewaf.New`. `SPEC.md` and the other documents follow. No change of behaviour.

Model: opus-5-5
This commit was merged in pull request #201.
This commit is contained in:
clawbot committed 2026-11-06 20:02:17 +01:00
1 parent 3cb41f27a8
commit a63b7e4d2d
50 files changed
+491 -489

No files matched your search

+61 -61
View File
@@ -16,9 +16,9 @@ import (
"time"
"sneak.berlin/go/smallwebwaf/internal/config"
"sneak.berlin/go/smallwebwaf/internal/proxy"
"sneak.berlin/go/smallwebwaf/internal/requestlog"
"sneak.berlin/go/smallwebwaf/internal/rproxy"
"sneak.berlin/go/smallwebwaf/internal/servewaf"
)
// post is the start of a POST whose headers end with what follows it.
@@ -71,11 +71,11 @@ func TestABodyAnnouncedOverItsLimitIsRefusedOnceServeWAFAllowsIt(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
servewaf := startServeWAF(t, allow)
standIn := startServeWAF(t, allow)
app := startApp(t, func(http.ResponseWriter, *http.Request) {
t.Error("the app was asked")
})
addr, _ := startRProxy(t, servewaf.URL, app.URL, map[string]string{
addr, _ := startRProxy(t, standIn.URL, app.URL, map[string]string{
maxRequestSize: tc.limit,
})
@@ -85,11 +85,11 @@ func TestABodyAnnouncedOverItsLimitIsRefusedOnceServeWAFAllowsIt(t *testing.T) {
t.Errorf("answered %+v, want 413", got)
}
if asked := servewaf.question(t); len(asked.body) != tc.asked {
if asked := standIn.question(t); len(asked.body) != tc.asked {
t.Errorf("the question carries %d bytes, want %d", len(asked.body), tc.asked)
}
report := servewaf.report(t)
report := standIn.report(t)
if report.Status != http.StatusRequestEntityTooLarge {
t.Errorf("report %+v, want status 413", report)
}
@@ -100,9 +100,9 @@ func TestABodyAnnouncedOverItsLimitIsRefusedOnceServeWAFAllowsIt(t *testing.T) {
func TestADenyOutranksTheBodySizeLimit(t *testing.T) {
t.Parallel()
servewaf := startServeWAF(t, deny)
standIn := startServeWAF(t, deny)
app := startApp(t, greet)
addr, _ := startRProxy(t, servewaf.URL, app.URL, map[string]string{
addr, _ := startRProxy(t, standIn.URL, app.URL, map[string]string{
maxRequestSize: "1K",
})
@@ -132,12 +132,12 @@ func TestABodyNotAnnouncedOverItsLimitIsRefused(t *testing.T) {
var asked atomic.Bool
servewaf := startServeWAF(t, allow)
standIn := startServeWAF(t, allow)
app := startApp(t, func(w http.ResponseWriter, r *http.Request) {
asked.Store(true)
greet(w, r)
})
addr, _ := startRProxy(t, servewaf.URL, app.URL, map[string]string{
addr, _ := startRProxy(t, standIn.URL, app.URL, map[string]string{
maxRequestSize: tc.limit,
})
@@ -165,12 +165,12 @@ func TestAResponseOverItsLimit(t *testing.T) {
t.Run("announced, is refused", func(t *testing.T) {
t.Parallel()
servewaf := startServeWAF(t, allow)
standIn := startServeWAF(t, allow)
app := startApp(t, func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set(contentLengthHeader, strconv.Itoa(len(large)))
_, _ = io.WriteString(w, large)
})
addr, _ := startRProxy(t, servewaf.URL, app.URL, map[string]string{
addr, _ := startRProxy(t, standIn.URL, app.URL, map[string]string{
maxResponseSize: "1K",
})
@@ -179,7 +179,7 @@ func TestAResponseOverItsLimit(t *testing.T) {
t.Errorf("answered %d, want 502", got.status)
}
if report := servewaf.report(t); report.Status != http.StatusBadGateway {
if report := standIn.report(t); report.Status != http.StatusBadGateway {
t.Errorf("report %+v, want status 502", report)
}
})
@@ -187,13 +187,13 @@ func TestAResponseOverItsLimit(t *testing.T) {
t.Run("not announced, is cut off", func(t *testing.T) {
t.Parallel()
servewaf := startServeWAF(t, allow)
standIn := startServeWAF(t, allow)
app := startApp(t, func(w http.ResponseWriter, _ *http.Request) {
_, _ = io.WriteString(w, large[:1])
_ = http.NewResponseController(w).Flush()
_, _ = io.WriteString(w, large[1:])
})
addr, _ := startRProxy(t, servewaf.URL, app.URL, map[string]string{
addr, _ := startRProxy(t, standIn.URL, app.URL, map[string]string{
maxResponseSize: "1K",
})
@@ -205,7 +205,7 @@ func TestAResponseOverItsLimit(t *testing.T) {
t.Errorf("read %d bytes (%v), want the answer cut off", len(text), err)
}
report := servewaf.report(t)
report := standIn.report(t)
if report.Status != http.StatusOK || report.ResponseBytes > 1<<10 {
t.Errorf("report %+v, want status 200 and at most 1K of the answer", report)
}
@@ -217,11 +217,11 @@ func TestAHeadWhoseAnswerAnnouncesMoreThanTheResponseLimitIsPassedOn(t *testing.
const announced = "2048"
servewaf := startServeWAF(t, allow)
standIn := startServeWAF(t, allow)
app := startApp(t, func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set(contentLengthHeader, announced)
})
addr, _ := startRProxy(t, servewaf.URL, app.URL, map[string]string{
addr, _ := startRProxy(t, standIn.URL, app.URL, map[string]string{
maxResponseSize: "1K",
})
@@ -240,9 +240,9 @@ func TestASettingOfOffSetsNoLimit(t *testing.T) {
t.Run(setting, func(t *testing.T) {
t.Parallel()
servewaf := startServeWAF(t, allow)
standIn := startServeWAF(t, allow)
app := startApp(t, greet)
addr, _ := startRProxy(t, servewaf.URL, app.URL, map[string]string{
addr, _ := startRProxy(t, standIn.URL, app.URL, map[string]string{
setting: "off",
})
@@ -251,7 +251,7 @@ func TestASettingOfOffSetsNoLimit(t *testing.T) {
wantGreeting(t, visit(t, newRequest(t, http.MethodPost, addr, "/",
strings.NewReader("a body"))))
if got := get(t, addr, proxy.HealthPath); got.status != http.StatusOK {
if got := get(t, addr, servewaf.HealthPath); got.status != http.StatusOK {
t.Errorf("answered %+v, want rproxy's own 200", got)
}
})
@@ -270,9 +270,9 @@ func TestAVisitorTooSlowToSendTheFirstPartIsAnswered408(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
servewaf := startServeWAF(t, allow)
standIn := startServeWAF(t, allow)
app := startApp(t, greet)
addr, out := startRProxy(t, servewaf.URL, app.URL, map[string]string{
addr, out := startRProxy(t, standIn.URL, app.URL, map[string]string{
maxRequestTime: "500",
})
@@ -288,11 +288,11 @@ func TestAVisitorTooSlowToSendTheFirstPartIsAnswered408(t *testing.T) {
t.Errorf("line %v, want no disposition and 10 bytes", line)
}
if len(servewaf.questions) != 0 {
if len(standIn.questions) != 0 {
t.Error("servewaf was asked")
}
servewaf.wantNoReport(t)
standIn.wantNoReport(t)
})
}
}
@@ -300,9 +300,9 @@ func TestAVisitorTooSlowToSendTheFirstPartIsAnswered408(t *testing.T) {
func TestAVisitorThatGoesAwayBeforeTheFirstPartIsNotAsked(t *testing.T) {
t.Parallel()
servewaf := startServeWAF(t, allow)
standIn := startServeWAF(t, allow)
app := startApp(t, greet)
addr, out := startRProxy(t, servewaf.URL, app.URL, nil)
addr, out := startRProxy(t, standIn.URL, app.URL, nil)
conn := dial(t, addr)
send(t, conn, post+announcedLength(100)+"some of it")
@@ -313,7 +313,7 @@ func TestAVisitorThatGoesAwayBeforeTheFirstPartIsNotAsked(t *testing.T) {
t.Errorf("line %v, want no answer and no disposition", line)
}
if len(servewaf.questions) != 0 {
if len(standIn.questions) != 0 {
t.Error("servewaf was asked")
}
}
@@ -334,9 +334,9 @@ func TestABodyThatCannotBeReadClosesTheConnectionWithoutAnAnswer(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
servewaf := startServeWAF(t, allow)
standIn := startServeWAF(t, allow)
app := startApp(t, greet)
addr, out := startRProxy(t, servewaf.URL, app.URL, nil)
addr, out := startRProxy(t, standIn.URL, app.URL, nil)
conn := dial(t, addr)
send(t, conn, tc.request)
@@ -364,7 +364,7 @@ func TestABodyThatCannotBeReadClosesTheConnectionWithoutAnAnswer(t *testing.T) {
t.Errorf("line %v, want no answer and no disposition", line)
}
if len(servewaf.questions) != 0 {
if len(standIn.questions) != 0 {
t.Error("servewaf was asked")
}
})
@@ -404,11 +404,11 @@ func TestABodyLeftUnreadIsReadOnlyUntilTheRequestTimeLimit(t *testing.T) {
announced = 100 * questionBodyMaxBytes
)
servewaf := startServeWAF(t, allow)
standIn := startServeWAF(t, allow)
app := startApp(t, func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNoContent)
})
_, _, server := startServer(t, servewaf.URL, app.URL, map[string]string{
_, _, server := startServer(t, standIn.URL, app.URL, map[string]string{
maxRequestTime: strconv.FormatInt(limit.Milliseconds(), 10),
})
@@ -454,9 +454,9 @@ func TestAnAnswerRProxyGivesItselfHasTheResponseTimeToBeSent(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
servewaf := startServeWAF(t, deny)
standIn := startServeWAF(t, deny)
app := startApp(t, greet)
_, _, server := startServer(t, servewaf.URL, app.URL, map[string]string{
_, _, server := startServer(t, standIn.URL, app.URL, map[string]string{
maxResponseTime: strconv.FormatInt(limit.Milliseconds(), 10),
})
@@ -484,9 +484,9 @@ func TestAnAnswerRProxyGivesItselfHasTheResponseTimeToBeSent(t *testing.T) {
func TestAVisitorTooSlowToSendTheRestIsAnswered408(t *testing.T) {
t.Parallel()
servewaf := startServeWAF(t, allow)
standIn := startServeWAF(t, allow)
app := startApp(t, greet)
addr, _ := startRProxy(t, servewaf.URL, app.URL, map[string]string{
addr, _ := startRProxy(t, standIn.URL, app.URL, map[string]string{
maxRequestTime: "3000",
})
@@ -498,11 +498,11 @@ func TestAVisitorTooSlowToSendTheRestIsAnswered408(t *testing.T) {
t.Errorf("status %d, want 408", status)
}
if asked := servewaf.question(t); len(asked.body) != questionBodyMaxBytes {
if asked := standIn.question(t); len(asked.body) != questionBodyMaxBytes {
t.Errorf("the question carries %d bytes", len(asked.body))
}
if report := servewaf.report(t); report.Status != http.StatusRequestTimeout {
if report := standIn.report(t); report.Status != http.StatusRequestTimeout {
t.Errorf("report %+v, want status 408", report)
}
}
@@ -553,8 +553,8 @@ func TestAnAppTooSlowToTakeTheRequestIsAnswered504(t *testing.T) {
writeSize = 32 << 10
)
servewaf := startServeWAF(t, allow)
addr, _ := startRProxy(t, servewaf.URL, startAppThatTakesNothing(t),
standIn := startServeWAF(t, allow)
addr, _ := startRProxy(t, standIn.URL, startAppThatTakesNothing(t),
map[string]string{maxRequestTime: "3000"})
conn := dial(t, addr)
@@ -580,14 +580,14 @@ func TestAnAppTooSlowToAnswerIsAnswered504(t *testing.T) {
t.Parallel()
release := make(chan struct{})
servewaf := startServeWAF(t, allow)
standIn := startServeWAF(t, allow)
app := startApp(t, func(http.ResponseWriter, *http.Request) {
<-release
})
t.Cleanup(func() { close(release) })
addr, _ := startRProxy(t, servewaf.URL, app.URL, map[string]string{
addr, _ := startRProxy(t, standIn.URL, app.URL, map[string]string{
maxResponseTime: "300",
})
@@ -596,7 +596,7 @@ func TestAnAppTooSlowToAnswerIsAnswered504(t *testing.T) {
t.Errorf("answered %d, want 504", got.status)
}
if report := servewaf.report(t); report.Status != http.StatusGatewayTimeout {
if report := standIn.report(t); report.Status != http.StatusGatewayTimeout {
t.Errorf("report %+v, want status 504", report)
}
}
@@ -607,7 +607,7 @@ func TestAnAppTooSlowToFinishItsAnswerIsCutOff(t *testing.T) {
const start = "the start"
release := make(chan struct{})
servewaf := startServeWAF(t, allow)
standIn := startServeWAF(t, allow)
app := startApp(t, func(w http.ResponseWriter, _ *http.Request) {
_, _ = io.WriteString(w, start)
_ = http.NewResponseController(w).Flush()
@@ -619,7 +619,7 @@ func TestAnAppTooSlowToFinishItsAnswerIsCutOff(t *testing.T) {
// The time limit is long enough for a loaded host to pass on the start of the
// answer before it runs out.
addr, _ := startRProxy(t, servewaf.URL, app.URL, map[string]string{
addr, _ := startRProxy(t, standIn.URL, app.URL, map[string]string{
maxResponseTime: "3000",
})
@@ -642,7 +642,7 @@ func TestAnAppTooSlowToFinishItsAnswerIsCutOff(t *testing.T) {
res.StatusCode, body, err, start)
}
if report := servewaf.report(t); report.Status != http.StatusOK {
if report := standIn.report(t); report.Status != http.StatusOK {
t.Errorf("report %+v, want the status the visitor got", report)
}
}
@@ -656,7 +656,7 @@ func TestAVisitorTooSlowToTakeTheAnswerIsCutOff(t *testing.T) {
writeSize = 32 << 10
)
servewaf := startServeWAF(t, allow)
standIn := startServeWAF(t, allow)
app := startApp(t, func(w http.ResponseWriter, _ *http.Request) {
part := make([]byte, writeSize)
@@ -669,7 +669,7 @@ func TestAVisitorTooSlowToTakeTheAnswerIsCutOff(t *testing.T) {
})
// The time limit is long enough for a loaded host to start passing on the
// answer before it runs out.
addr, out := startRProxy(t, servewaf.URL, app.URL, map[string]string{
addr, out := startRProxy(t, standIn.URL, app.URL, map[string]string{
maxResponseTime: "3000",
})
@@ -684,7 +684,7 @@ func TestAVisitorTooSlowToTakeTheAnswerIsCutOff(t *testing.T) {
t.Errorf("line %v, want status 200 and the answer cut off", line)
}
report := servewaf.report(t)
report := standIn.report(t)
if report.Status != http.StatusOK || report.ResponseBytes >= bodySize {
t.Errorf("report %+v, want status 200 and the answer cut off", report)
}
@@ -693,15 +693,15 @@ func TestAVisitorTooSlowToTakeTheAnswerIsCutOff(t *testing.T) {
func TestAnAppThatCannotBeReachedIsAnswered502WithAReport(t *testing.T) {
t.Parallel()
servewaf := startServeWAF(t, allow)
addr, _ := startRProxy(t, servewaf.URL, nowhere, nil)
standIn := startServeWAF(t, allow)
addr, _ := startRProxy(t, standIn.URL, nowhere, nil)
got := get(t, addr, "/")
if got.status != http.StatusBadGateway {
t.Errorf("answered %d, want 502", got.status)
}
if report := servewaf.report(t); report.Status != http.StatusBadGateway {
if report := standIn.report(t); report.Status != http.StatusBadGateway {
t.Errorf("report %+v, want status 502", report)
}
}
@@ -709,11 +709,11 @@ func TestAnAppThatCannotBeReachedIsAnswered502WithAReport(t *testing.T) {
func TestAVisitorThatStopsSendingAfterTheAppHasAnsweredGetsTheAnswer(t *testing.T) {
t.Parallel()
servewaf := startServeWAF(t, allow)
standIn := startServeWAF(t, allow)
app := startApp(t, func(w http.ResponseWriter, _ *http.Request) {
_, _ = io.WriteString(w, greeting)
})
addr, _ := startRProxy(t, servewaf.URL, app.URL, map[string]string{
addr, _ := startRProxy(t, standIn.URL, app.URL, map[string]string{
maxRequestTime: "3000",
})
@@ -732,12 +732,12 @@ func TestAVisitorThatStopsSendingWhileTheAppWorksGetsNoAnswer(t *testing.T) {
t.Parallel()
working := make(chan struct{})
servewaf := startServeWAF(t, allow)
standIn := startServeWAF(t, allow)
app := startApp(t, func(_ http.ResponseWriter, r *http.Request) {
close(working)
<-r.Context().Done()
})
addr, out := startRProxy(t, servewaf.URL, app.URL, nil)
addr, out := startRProxy(t, standIn.URL, app.URL, nil)
conn := dial(t, addr)
send(t, conn, "GET / HTTP/1.1\r\nHost: site.example\r\n\r\n")
@@ -773,7 +773,7 @@ func TestTheRequestTimeLimitDoesNotCutAnAnswerOnceTheAppHasTheRequest(t *testing
const answer = "the end of a long answer"
servewaf := startServeWAF(t, allow)
standIn := startServeWAF(t, allow)
app := startApp(t, func(w http.ResponseWriter, r *http.Request) {
_, _ = io.Copy(io.Discard, r.Body)
_ = http.NewResponseController(w).Flush()
@@ -782,7 +782,7 @@ func TestTheRequestTimeLimitDoesNotCutAnAnswerOnceTheAppHasTheRequest(t *testing
_, _ = io.WriteString(w, answer)
})
addr, _ := startRProxy(t, servewaf.URL, app.URL, map[string]string{
addr, _ := startRProxy(t, standIn.URL, app.URL, map[string]string{
maxRequestTime: "2000",
})
@@ -802,18 +802,18 @@ func TestAVisitorThatStopsSendingGetsAnAnswerRProxyGivesByTheDeadline(t *testing
{"a deny", post, http.StatusForbidden},
{
"the health check",
"GET " + proxy.HealthPath + " HTTP/1.1\r\nHost: site.example\r\n",
"GET " + servewaf.HealthPath + " HTTP/1.1\r\nHost: site.example\r\n",
http.StatusOK,
},
} {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
servewaf := startServeWAF(t, deny)
standIn := startServeWAF(t, deny)
app := startApp(t, greet)
// The time limit is long enough for a loaded host to read the first part of
// the body before it runs out.
addr, _ := startRProxy(t, servewaf.URL, app.URL, map[string]string{
addr, _ := startRProxy(t, standIn.URL, app.URL, map[string]string{
maxRequestTime: "3000",
})