mirror of
https://github.com/valyala/fasthttp.git
synced 2026-06-14 15:56:44 +03:00
Do not send response body (and content-length) for 1xx, 204 and 304 responses
This commit is contained in:
@@ -181,6 +181,9 @@ func (h *ResponseHeader) ContentLength() int {
|
||||
// -1 means Transfer-Encoding: chunked.
|
||||
// -2 means Transfer-Encoding: identity.
|
||||
func (h *ResponseHeader) SetContentLength(contentLength int) {
|
||||
if h.mustSkipContentLength() {
|
||||
return
|
||||
}
|
||||
h.contentLength = contentLength
|
||||
if contentLength >= 0 {
|
||||
h.contentLengthBytes = AppendUint(h.contentLengthBytes[:0], contentLength)
|
||||
@@ -196,6 +199,20 @@ func (h *ResponseHeader) SetContentLength(contentLength int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (h *ResponseHeader) mustSkipContentLength() bool {
|
||||
// From http/1.1 specs:
|
||||
// All 1xx (informational), 204 (no content), and 304 (not modified) responses MUST NOT include a message-body
|
||||
statusCode := h.StatusCode()
|
||||
|
||||
// Fast path.
|
||||
if statusCode < 100 || statusCode == StatusOK {
|
||||
return false
|
||||
}
|
||||
|
||||
// Slow path.
|
||||
return statusCode == StatusNotModified || statusCode == StatusNoContent || statusCode < 200
|
||||
}
|
||||
|
||||
// ContentLength returns Content-Length header value.
|
||||
//
|
||||
// It may be negative:
|
||||
|
||||
@@ -674,7 +674,7 @@ func (resp *Response) ReadLimitBody(r *bufio.Reader, maxBodySize int) error {
|
||||
}
|
||||
}
|
||||
|
||||
if !isSkipResponseBody(resp.Header.StatusCode()) && !resp.SkipBody {
|
||||
if !resp.mustSkipBody() {
|
||||
resp.body, err = readBody(r, resp.Header.ContentLength(), maxBodySize, resp.body)
|
||||
if err != nil {
|
||||
resp.Reset()
|
||||
@@ -685,13 +685,8 @@ func (resp *Response) ReadLimitBody(r *bufio.Reader, maxBodySize int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func isSkipResponseBody(statusCode int) bool {
|
||||
// From http/1.1 specs:
|
||||
// All 1xx (informational), 204 (no content), and 304 (not modified) responses MUST NOT include a message-body
|
||||
if statusCode >= 100 && statusCode < 200 {
|
||||
return true
|
||||
}
|
||||
return statusCode == StatusNoContent || statusCode == StatusNotModified
|
||||
func (resp *Response) mustSkipBody() bool {
|
||||
return resp.SkipBody || resp.Header.mustSkipContentLength()
|
||||
}
|
||||
|
||||
var errRequestHostRequired = errors.New("Missing required Host header in request")
|
||||
@@ -844,6 +839,8 @@ func (resp *Response) deflateBody(level int) error {
|
||||
// Write doesn't flush response to w for performance reasons.
|
||||
func (resp *Response) Write(w *bufio.Writer) error {
|
||||
var err error
|
||||
sendBody := !resp.mustSkipBody()
|
||||
|
||||
if resp.bodyStream != nil {
|
||||
contentLength := resp.Header.ContentLength()
|
||||
if contentLength < 0 {
|
||||
@@ -860,7 +857,7 @@ func (resp *Response) Write(w *bufio.Writer) error {
|
||||
if err = resp.Header.Write(w); err != nil {
|
||||
return err
|
||||
}
|
||||
if !resp.SkipBody {
|
||||
if sendBody {
|
||||
if err = writeBodyFixedSize(w, resp.bodyStream, int64(contentLength)); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -870,7 +867,7 @@ func (resp *Response) Write(w *bufio.Writer) error {
|
||||
if err = resp.Header.Write(w); err != nil {
|
||||
return err
|
||||
}
|
||||
if !resp.SkipBody {
|
||||
if sendBody {
|
||||
if err = writeBodyChunked(w, resp.bodyStream); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -883,7 +880,7 @@ func (resp *Response) Write(w *bufio.Writer) error {
|
||||
if err = resp.Header.Write(w); err != nil {
|
||||
return err
|
||||
}
|
||||
if !resp.SkipBody {
|
||||
if sendBody {
|
||||
_, err = w.Write(resp.body)
|
||||
}
|
||||
return err
|
||||
|
||||
+34
-4
@@ -13,17 +13,47 @@ import (
|
||||
func TestResponseSkipBody(t *testing.T) {
|
||||
var r Response
|
||||
|
||||
r.SkipBody = true
|
||||
// set StatusNotModified
|
||||
r.Header.SetStatusCode(StatusNotModified)
|
||||
r.SetBodyString("foobar")
|
||||
s := r.String()
|
||||
if strings.Contains(s, "\r\n\r\nfoobar") {
|
||||
t.Fatalf("unexpected non-zero body in request %q", s)
|
||||
t.Fatalf("unexpected non-zero body in response %q", s)
|
||||
}
|
||||
if strings.Contains(s, "Content-Length: ") {
|
||||
t.Fatalf("unexpected content-length in response %q", s)
|
||||
}
|
||||
if strings.Contains(s, "Content-Type: ") {
|
||||
t.Fatalf("unexpected content-type in response %q", s)
|
||||
}
|
||||
|
||||
// set StatusNoContent
|
||||
r.Header.SetStatusCode(StatusNoContent)
|
||||
r.SetBodyString("foobar")
|
||||
s = r.String()
|
||||
if strings.Contains(s, "\r\n\r\nfoobar") {
|
||||
t.Fatalf("unexpected non-zero body in response %q", s)
|
||||
}
|
||||
if strings.Contains(s, "Content-Length: ") {
|
||||
t.Fatalf("unexpected content-length in response %q", s)
|
||||
}
|
||||
if strings.Contains(s, "Content-Type: ") {
|
||||
t.Fatalf("unexpected content-type in response %q", s)
|
||||
}
|
||||
|
||||
// explicitly skip body
|
||||
r.Header.SetStatusCode(StatusOK)
|
||||
r.SkipBody = true
|
||||
r.SetBodyString("foobar")
|
||||
s = r.String()
|
||||
if strings.Contains(s, "\r\n\r\nfoobar") {
|
||||
t.Fatalf("unexpected non-zero body in response %q", s)
|
||||
}
|
||||
if !strings.Contains(s, "Content-Length: 6\r\n") {
|
||||
t.Fatalf("unexpected content-length in request %q", s)
|
||||
t.Fatalf("unexpected content-length in response %q", s)
|
||||
}
|
||||
if !strings.Contains(s, "Content-Type: ") {
|
||||
t.Fatalf("unexpected content-type in request %q", s)
|
||||
t.Fatalf("expecting content-type in response %q", s)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user