An answer from the app without a Content-Type reaches the client without one (closes #127)
check / check (push) Waiting to run

Go's server adds a Content-Type it guesses from the body when the
response's headers have no Content-Type key, which happened to some
of the app's answers and not others, as the first part of the body or
the headers went out first. When the app sends none, smallwebwaf now
sets the key with no value on the client's response, which sends none.

Model: opus-5-5
This commit is contained in:
2026-10-20 13:43:52 +00:00
parent 75f28ee0b5
commit 1e70698cfc
2 changed files with 42 additions and 0 deletions
+35
View File
@@ -151,6 +151,41 @@ func wantRequestFields(t *testing.T, line logLine, host string, sent, received i
} }
} }
func TestAddsNoContentTypeTheAppDidNotSend(t *testing.T) {
t.Parallel()
const typed = "text/plain"
app := startApp(t, func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/typed" {
w.Header().Set("Content-Type", typed)
} else {
// The key with no value keeps Go's server from adding one.
w.Header()["Content-Type"] = nil
}
_, _ = io.WriteString(w, "<!doctype html><title>page</title>")
})
addr, _ := startProxy(t, app.URL, nil)
// Go's server guesses a Content-Type for an answer without one only
// when the first part of the body goes out with the headers, which
// happens to some answers and not others: the test asks many times.
for range 50 {
got := get(t, addr, "/")
if got.header.Values("Content-Type") != nil {
t.Fatalf("client got Content-Type %q, want none",
got.header.Get("Content-Type"))
}
}
got := get(t, addr, "/typed")
if got.header.Get("Content-Type") != typed {
t.Errorf("client got Content-Type %q, want %q",
got.header.Get("Content-Type"), typed)
}
}
func TestStreamsTheRequestBody(t *testing.T) { func TestStreamsTheRequestBody(t *testing.T) {
t.Parallel() t.Parallel()
+7
View File
@@ -421,6 +421,13 @@ func (rq *request) modifyResponse(res *http.Response) error {
return errResponseTooLarge return errResponseTooLarge
} }
// Go's server adds a Content-Type it guesses from the body to a
// response whose headers have no Content-Type key. The key with no
// value sends none, as the app sent none.
if res.Header.Get("Content-Type") == "" {
rq.out.Header()["Content-Type"] = nil
}
res.Body = &responseBody{body: limitBody(res.Body, maxBytes), rq: rq} res.Body = &responseBody{body: limitBody(res.Body, maxBytes), rq: rq}
rq.startClientResponseTimeout() rq.startClientResponseTimeout()