diff options
author | Sergey Ponomarev <stokito@gmail.com> | 2022-06-05 16:47:59 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-05 15:47:59 +0200 |
commit | c9f43eaa1b02d6867e489a39e92926c68facb60c (patch) | |
tree | 2f5343a5572a07eb207d2e7caf7b2480aad18c37 /header.go | |
parent | Optimize server connection close logic (#1310) (diff) | |
download | fasthttp-c9f43eaa1b02d6867e489a39e92926c68facb60c.tar.gz fasthttp-c9f43eaa1b02d6867e489a39e92926c68facb60c.tar.bz2 fasthttp-c9f43eaa1b02d6867e489a39e92926c68facb60c.zip |
Response.ContentEncoding(): store as field and avoid using Header.SetCanonical() (#1311)
* Response.ContentEncoding(): store as field
The CE is not so often used for plain APIs responses and even not so often used for static files and on the fly compression.
But still it should be checked each time.
Also having a dedicated field getter and setter simplifies code
* header.go Use shorter Response.setNonSpecial() and Request.setNonSpecial() methods instead of SetCanonical()
The change should improve performance because the setSpecialHeader() call is omitted.
As a downside on adding a new basic header field all putHeader() must be replaced with a direct getter and setter.
Diffstat (limited to 'header.go')
-rw-r--r-- | header.go | 69 |
1 files changed, 57 insertions, 12 deletions
@@ -39,8 +39,9 @@ type ResponseHeader struct { contentLengthBytes []byte secureErrorLogMessage bool - contentType []byte - server []byte + contentType []byte + contentEncoding []byte + server []byte h []argsKV trailer []argsKV @@ -103,7 +104,7 @@ func (h *ResponseHeader) SetContentRange(startPos, endPos, contentLength int) { b = AppendUint(b, contentLength) h.bufKV.value = b - h.SetCanonical(strContentRange, h.bufKV.value) + h.setNonSpecial(strContentRange, h.bufKV.value) } // SetByteRange sets 'Range: bytes=startPos-endPos' header. @@ -125,7 +126,7 @@ func (h *RequestHeader) SetByteRange(startPos, endPos int) { } h.bufKV.value = b - h.SetCanonical(strRange, h.bufKV.value) + h.setNonSpecial(strRange, h.bufKV.value) } // StatusCode returns response status code. @@ -167,7 +168,7 @@ func (h *ResponseHeader) SetProtocol(protocol []byte) { // SetLastModified sets 'Last-Modified' header to the given value. func (h *ResponseHeader) SetLastModified(t time.Time) { h.bufKV.value = AppendHTTPDate(h.bufKV.value[:0], t) - h.SetCanonical(strLastModified, h.bufKV.value) + h.setNonSpecial(strLastModified, h.bufKV.value) } // ConnectionClose returns true if 'Connection: close' header is set. @@ -325,6 +326,21 @@ func (h *ResponseHeader) SetContentTypeBytes(contentType []byte) { h.contentType = append(h.contentType[:0], contentType...) } +// ContentEncoding returns Content-Encoding header value. +func (h *ResponseHeader) ContentEncoding() []byte { + return h.contentEncoding +} + +// SetContentEncoding sets Content-Encoding header value. +func (h *ResponseHeader) SetContentEncoding(contentEncoding string) { + h.contentEncoding = append(h.contentEncoding[:0], contentEncoding...) +} + +// SetContentEncodingBytes sets Content-Encoding header value. +func (h *ResponseHeader) SetContentEncodingBytes(contentEncoding []byte) { + h.contentEncoding = append(h.contentEncoding[:0], contentEncoding...) +} + // Server returns Server header value. func (h *ResponseHeader) Server() []byte { return h.server @@ -580,7 +596,7 @@ func (h *RequestHeader) SetReferer(referer string) { // SetRefererBytes sets Referer header value. func (h *RequestHeader) SetRefererBytes(referer []byte) { - h.SetCanonical(strReferer, referer) + h.setNonSpecial(strReferer, referer) } // Method returns HTTP request method. @@ -937,6 +953,7 @@ func (h *ResponseHeader) resetSkipNormalize() { h.contentLengthBytes = h.contentLengthBytes[:0] h.contentType = h.contentType[:0] + h.contentEncoding = h.contentEncoding[:0] h.server = h.server[:0] h.h = h.h[:0] @@ -994,6 +1011,7 @@ func (h *ResponseHeader) CopyTo(dst *ResponseHeader) { dst.contentLength = h.contentLength dst.contentLengthBytes = append(dst.contentLengthBytes, h.contentLengthBytes...) dst.contentType = append(dst.contentType, h.contentType...) + dst.contentEncoding = append(dst.contentEncoding, h.contentEncoding...) dst.server = append(dst.server, h.server...) dst.h = copyArgs(dst.h, h.h) dst.cookies = copyArgs(dst.cookies, h.cookies) @@ -1035,6 +1053,10 @@ func (h *ResponseHeader) VisitAll(f func(key, value []byte)) { if len(contentType) > 0 { f(strContentType, contentType) } + contentEncoding := h.ContentEncoding() + if len(contentEncoding) > 0 { + f(strContentEncoding, contentEncoding) + } server := h.Server() if len(server) > 0 { f(strServer, server) @@ -1158,6 +1180,8 @@ func (h *ResponseHeader) del(key []byte) { switch string(key) { case HeaderContentType: h.contentType = h.contentType[:0] + case HeaderContentEncoding: + h.contentEncoding = h.contentEncoding[:0] case HeaderServer: h.server = h.server[:0] case HeaderSetCookie: @@ -1224,12 +1248,15 @@ func (h *ResponseHeader) setSpecialHeader(key, value []byte) bool { h.contentLengthBytes = append(h.contentLengthBytes[:0], value...) } return true + } else if caseInsensitiveCompare(strContentEncoding, key) { + h.SetContentEncodingBytes(value) + return true } else if caseInsensitiveCompare(strConnection, key) { if bytes.Equal(strClose, value) { h.SetConnectionClose() } else { h.ResetConnectionClose() - h.h = setArgBytes(h.h, key, value, argsHasValue) + h.setNonSpecial(key, value) } return true } @@ -1262,6 +1289,11 @@ func (h *ResponseHeader) setSpecialHeader(key, value []byte) bool { return false } +// setNonSpecial directly put into map i.e. not a basic header +func (h *ResponseHeader) setNonSpecial(key []byte, value []byte) { + h.h = setArgBytes(h.h, key, value, argsHasValue) +} + // setSpecialHeader handles special headers and return true when a header is processed. func (h *RequestHeader) setSpecialHeader(key, value []byte) bool { if len(key) == 0 { @@ -1284,7 +1316,7 @@ func (h *RequestHeader) setSpecialHeader(key, value []byte) bool { h.SetConnectionClose() } else { h.ResetConnectionClose() - h.h = setArgBytes(h.h, key, value, argsHasValue) + h.setNonSpecial(key, value) } return true } else if caseInsensitiveCompare(strCookie, key) { @@ -1315,6 +1347,11 @@ func (h *RequestHeader) setSpecialHeader(key, value []byte) bool { return false } +// setNonSpecial directly put into map i.e. not a basic header +func (h *RequestHeader) setNonSpecial(key []byte, value []byte) { + h.h = setArgBytes(h.h, key, value, argsHasValue) +} + // Add adds the given 'key: value' header. // // Multiple headers with the same key may be added with this function. @@ -1434,8 +1471,7 @@ func (h *ResponseHeader) SetCanonical(key, value []byte) { if h.setSpecialHeader(key, value) { return } - - h.h = setArgBytes(h.h, key, value, argsHasValue) + h.setNonSpecial(key, value) } // SetCookie sets the given response cookie. @@ -1646,8 +1682,7 @@ func (h *RequestHeader) SetCanonical(key, value []byte) { if h.setSpecialHeader(key, value) { return } - - h.h = setArgBytes(h.h, key, value, argsHasValue) + h.setNonSpecial(key, value) } // Peek returns header value for the given key. @@ -1696,6 +1731,8 @@ func (h *ResponseHeader) peek(key []byte) []byte { switch string(key) { case HeaderContentType: return h.ContentType() + case HeaderContentEncoding: + return h.ContentEncoding() case HeaderServer: return h.Server() case HeaderConnection: @@ -2151,6 +2188,10 @@ func (h *ResponseHeader) AppendBytes(dst []byte) []byte { dst = appendHeaderLine(dst, strContentType, contentType) } } + contentEncoding := h.ContentEncoding() + if len(contentEncoding) > 0 { + dst = appendHeaderLine(dst, strContentEncoding, contentEncoding) + } if len(h.contentLengthBytes) > 0 { dst = appendHeaderLine(dst, strContentLength, h.contentLengthBytes) @@ -2616,6 +2657,10 @@ func (h *ResponseHeader) parseHeaders(buf []byte) (int, error) { h.contentType = append(h.contentType[:0], s.value...) continue } + if caseInsensitiveCompare(s.key, strContentEncoding) { + h.contentEncoding = append(h.contentEncoding[:0], s.value...) + continue + } if caseInsensitiveCompare(s.key, strContentLength) { if h.contentLength != -1 { if h.contentLength, err = parseContentLength(s.value); err != nil { |