A client that stops sending after the app answers is timed out #135

Open
clawbot wants to merge 1 commits from issue-130-client-timeout-after-early-answer into next
2 changed files with 33 additions and 1 deletions
+11 -1
View File
@@ -789,9 +789,19 @@ func (rq *request) responseTimedOut() {
}
}
// responseReceived is called once the app has sent its whole answer.
// responseReceived is called once the app has sent its whole answer. An
// app may answer before the client has sent its whole body, as with a 404
// it sends without reading it. The timeouts then run on: until the
// transport's read of the body returns, Go's server cannot send the
// answer, and SWWAF_CLIENT_REQUEST_TIMEOUT is what ends that read for a
// client that stops sending.
func (rq *request) responseReceived() {
rq.complete = true
if rq.body != nil && !rq.body.received.Load() {
return
}
rq.stopTimers()
}
+22
View File
@@ -194,6 +194,28 @@ func sendLargeBody(t *testing.T, addr string) net.Conn {
return conn
}
func TestClientStopsSendingAfterTheAppHasAnswered(t *testing.T) {
t.Parallel()
// The app answers at once without reading the body, as an app does
// for a path it does not serve.
app := startApp(t, http.NotFound)
addr, out := startProxy(t, app.URL, map[string]string{
clientRequestTimeout: shortTimeoutSetting,
metricsToken: token,
})
start := time.Now()
got := readResponse(t, sendPartOfBody(t, addr))
wantTimedOut(t, start)
// The app's answer came before the time ran out, so the client is
// sent that answer, not smallwebwaf's 408.
wantStatus(t, got, http.StatusNotFound)
wantLine(t, out.requestLine(t), http.StatusNotFound, requestlog.ActionTimedOut)
wantLimitHits(t, addr, clientRequestTimeout, 1)
}
func TestAppTooSlowToAnswer(t *testing.T) {
t.Parallel()