1
0
mirror of https://github.com/containous/traefik.git synced 2025-03-19 18:50:12 +03:00

Do not read response body for HEAD requests

Co-authored-by: Romain <rtribotte@users.noreply.github.com>
This commit is contained in:
Kevin Pollet 2025-01-14 15:16:05 +01:00 committed by GitHub
parent ad99c5bbea
commit 0528c054a6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 46 additions and 6 deletions

View File

@ -20,8 +20,9 @@ import (
// rwWithUpgrade contains a ResponseWriter and an upgradeHandler,
// used to upgrade the connection (e.g. Websockets).
type rwWithUpgrade struct {
RW http.ResponseWriter
Upgrade upgradeHandler
ReqMethod string
RW http.ResponseWriter
Upgrade upgradeHandler
}
// conn is an enriched net.Conn.
@ -211,6 +212,10 @@ func (c *conn) handleResponse(r rwWithUpgrade) error {
r.RW.WriteHeader(res.StatusCode())
if noResponseBodyExpected(r.ReqMethod) {
return nil
}
if res.Header.ContentLength() == 0 {
return nil
}
@ -444,8 +449,8 @@ func (c *connPool) askForNewConn(errCh chan<- error) {
c.releaseConn(newConn)
}
// isBodyAllowedForStatus reports whether a given response status code
// permits a body. See RFC 7230, section 3.3.
// isBodyAllowedForStatus reports whether a given response status code permits a body.
// See RFC 7230, section 3.3.
// From https://github.com/golang/go/blame/master/src/net/http/transfer.go#L459
func isBodyAllowedForStatus(status int) bool {
switch {
@ -458,3 +463,9 @@ func isBodyAllowedForStatus(status int) bool {
}
return true
}
// noResponseBodyExpected reports whether a given request method permits a body.
// From https://github.com/golang/go/blame/master/src/net/http/transfer.go#L250
func noResponseBodyExpected(requestMethod string) bool {
return requestMethod == "HEAD"
}

View File

@ -284,8 +284,9 @@ func (p *ReverseProxy) roundTrip(rw http.ResponseWriter, req *http.Request, outR
// Sending the responseWriter unlocks the connection readLoop, to handle the response.
co.RWCh <- rwWithUpgrade{
RW: rw,
Upgrade: upgradeResponseHandler(req.Context(), reqUpType),
ReqMethod: req.Method,
RW: rw,
Upgrade: upgradeResponseHandler(req.Context(), reqUpType),
}
if err := <-co.ErrCh; err != nil {

View File

@ -278,6 +278,34 @@ func TestPreservePath(t *testing.T) {
assert.Equal(t, http.StatusOK, res.Code)
}
func TestHeadRequest(t *testing.T) {
var callCount int
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
callCount++
assert.Equal(t, http.MethodHead, req.Method)
rw.Header().Set("Content-Length", "42")
}))
t.Cleanup(server.Close)
builder := NewProxyBuilder(&transportManagerMock{}, static.FastProxyConfig{})
serverURL, err := url.JoinPath(server.URL)
require.NoError(t, err)
proxyHandler, err := builder.Build("", testhelpers.MustParseURL(serverURL), true, true)
require.NoError(t, err)
req := httptest.NewRequest(http.MethodHead, "/", http.NoBody)
res := httptest.NewRecorder()
proxyHandler.ServeHTTP(res, req)
assert.Equal(t, 1, callCount)
assert.Equal(t, http.StatusOK, res.Code)
}
func newCertificate(t *testing.T, domain string) *tls.Certificate {
t.Helper()