mirror of
https://github.com/golang/go
synced 2024-11-17 03:04:44 -07:00
net/http: remove misleading response headers on error
ServeContent API is to set some headers you want to see in the response before calling ServeContent. But if there is an error, those headers should be removed otherwise they might confuse the client. Removing those headers is useful in general in the case of an error, so we remove them in http.Error. Fixes #50905.
This commit is contained in:
parent
f27a57ffb8
commit
32b6f045a7
@ -27,6 +27,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"testing/fstest"
|
"testing/fstest"
|
||||||
@ -1694,3 +1695,64 @@ func testFileServerDirWithRootFile(t *testing.T, mode testMode) {
|
|||||||
testDirFile(t, FileServerFS(os.DirFS("testdata/index.html")))
|
testDirFile(t, FileServerFS(os.DirFS("testdata/index.html")))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServeContentHeadersWithError(t *testing.T) {
|
||||||
|
contents := []byte("content")
|
||||||
|
ts := newClientServerTest(t, http1Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/octet-stream")
|
||||||
|
w.Header().Set("Content-Length", strconv.Itoa(len(contents)))
|
||||||
|
w.Header().Set("Content-Encoding", "gzip")
|
||||||
|
w.Header().Set("Etag", `"abcdefgh"`)
|
||||||
|
w.Header().Set("Last-Modified", "Wed, 21 Oct 2015 07:28:00 GMT")
|
||||||
|
w.Header().Set("Cache-Control", "immutable")
|
||||||
|
w.Header().Set("Other-Header", "test")
|
||||||
|
ServeContent(w, r, "", time.Time{}, bytes.NewReader(contents))
|
||||||
|
})).ts
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
req, err := NewRequest("GET", ts.URL, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
req.Header.Set("Range", "bytes=100-10000")
|
||||||
|
|
||||||
|
c := ts.Client()
|
||||||
|
res, err := c.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
out, _ := io.ReadAll(res.Body)
|
||||||
|
res.Body.Close()
|
||||||
|
|
||||||
|
if g, e := res.StatusCode, 416; g != e {
|
||||||
|
t.Errorf("got status = %d; want %d", g, e)
|
||||||
|
}
|
||||||
|
if g, e := string(out), "invalid range: failed to overlap\n"; g != e {
|
||||||
|
t.Errorf("got body = %q; want %q", g, e)
|
||||||
|
}
|
||||||
|
if g, e := res.Header.Get("Content-Type"), "text/plain; charset=utf-8"; g != e {
|
||||||
|
t.Errorf("got content-type = %q, want %q", g, e)
|
||||||
|
}
|
||||||
|
if g, e := res.Header.Get("Content-Length"), strconv.Itoa(len(out)); g != e {
|
||||||
|
t.Errorf("got content-length = %q, want %q", g, e)
|
||||||
|
}
|
||||||
|
if g, e := res.Header.Get("Content-Encoding"), ""; g != e {
|
||||||
|
t.Errorf("got content-encoding = %q, want %q", g, e)
|
||||||
|
}
|
||||||
|
if g, e := res.Header.Get("Etag"), ""; g != e {
|
||||||
|
t.Errorf("got etag = %q, want %q", g, e)
|
||||||
|
}
|
||||||
|
if g, e := res.Header.Get("Last-Modified"), ""; g != e {
|
||||||
|
t.Errorf("got last-modified = %q, want %q", g, e)
|
||||||
|
}
|
||||||
|
if g, e := res.Header.Get("Cache-Control"), "no-cache"; g != e {
|
||||||
|
t.Errorf("got cache-control = %q, want %q", g, e)
|
||||||
|
}
|
||||||
|
if g, e := res.Header.Get("Content-Range"), "bytes */7"; g != e {
|
||||||
|
t.Errorf("got content-range = %q, want %q", g, e)
|
||||||
|
}
|
||||||
|
if g, e := res.Header.Get("Other-Header"), "test"; g != e {
|
||||||
|
t.Errorf("got other-header = %q, want %q", g, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2173,9 +2173,20 @@ func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
|
|||||||
// writes are done to w.
|
// writes are done to w.
|
||||||
// The error message should be plain text.
|
// The error message should be plain text.
|
||||||
func Error(w ResponseWriter, error string, code int) {
|
func Error(w ResponseWriter, error string, code int) {
|
||||||
w.Header().Del("Content-Length")
|
h := w.Header()
|
||||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
// We delete headers which might be valid for some other content,
|
||||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
// but not anymore for the error content.
|
||||||
|
h.Del("Content-Length")
|
||||||
|
h.Del("Content-Encoding")
|
||||||
|
h.Del("Etag")
|
||||||
|
h.Del("Last-Modified")
|
||||||
|
// There might be cache control headers set for some other content,
|
||||||
|
// but we reset it to no-cache for the error content.
|
||||||
|
h.Set("Cache-Control", "no-cache")
|
||||||
|
// There might be content type already set, but we reset it to
|
||||||
|
// text/plain for the error message.
|
||||||
|
h.Set("Content-Type", "text/plain; charset=utf-8")
|
||||||
|
h.Set("X-Content-Type-Options", "nosniff")
|
||||||
w.WriteHeader(code)
|
w.WriteHeader(code)
|
||||||
fmt.Fprintln(w, error)
|
fmt.Fprintln(w, error)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user