1 Commits
Author SHA1 Message Date
sneak 7da6e147ef TestRequestTimeouts expects 504 when none of the body reached the app (closes #49)
check / check (push) Successful in 2m27s
In the cases where the app reads and the client stops sending halfway,
smallwebwaf waits on the client only once it has passed the first bytes
of the body to the app. A test process held up for the whole 300 ms
timeout before then rightly gets 504, as SPEC.md asks, so the test was
wrong to expect 408 every time.

The app in those cases now records whether it received any of the body.
Once the app has finished with the request, the case expects 408 and its
log line if it did, and 504 and its log line if not.

Model: opus-5-5
2026-10-04 03:26:18 +00:00
+27 -10
View File
@@ -5,8 +5,10 @@ import (
"io"
"net"
"net/http"
"net/http/httptest"
"strconv"
"sync"
"sync/atomic"
"testing"
"time"
@@ -66,32 +68,47 @@ func TestRequestTimeouts(t *testing.T) {
t.Parallel()
var (
app *httptest.Server
appURL string
sendRequest func(*testing.T, string) net.Conn
appGotBody atomic.Bool
)
if tc.appTakesNothing {
appURL, sendRequest = startAppThatTakesNothing(t), sendLargeBody
} else {
appURL, sendRequest = startApp(t, readBody).URL, sendPartOfBody
app = startApp(t, func(_ http.ResponseWriter, r *http.Request) {
n, _ := io.Copy(io.Discard, r.Body)
appGotBody.Store(n > 0)
})
appURL, sendRequest = app.URL, sendPartOfBody
}
addr, out := startProxy(t, appURL, tc.env)
start := time.Now()
conn := sendRequest(t, addr)
wantStatus(t, readResponse(t, conn), tc.want)
got := readResponse(t, sendRequest(t, addr))
wantTimedOut(t, start)
wantLine(t, out.requestLine(t), tc.want, requestlog.ActionTimedOut)
want := tc.want
if app != nil {
// Close returns once the app has finished with the request.
app.Close()
// Until some of the body has reached the app, smallwebwaf
// waits on the app, and SPEC.md asks for 504; the timeout
// runs out then only if the test process is held up.
if !appGotBody.Load() {
want = http.StatusGatewayTimeout
}
}
wantStatus(t, got, want)
wantLine(t, out.requestLine(t), want, requestlog.ActionTimedOut)
})
}
}
// readBody is an app that reads the request body, then answers.
func readBody(_ http.ResponseWriter, r *http.Request) {
_, _ = io.Copy(io.Discard, r.Body)
}
// startAppThatTakesNothing starts an app that accepts connections and
// never reads from them, and returns its URL.
func startAppThatTakesNothing(t *testing.T) string {