mirror of
https://github.com/valyala/fasthttp.git
synced 2026-06-14 15:56:44 +03:00
Expose header parsing error variables (#2096)
This commit is contained in:
@@ -463,7 +463,22 @@ func (h *header) AddTrailer(trailer string) error {
|
||||
return h.AddTrailerBytes(s2b(trailer))
|
||||
}
|
||||
|
||||
var ErrBadTrailer = errors.New("contain forbidden trailer")
|
||||
var (
|
||||
ErrBadTrailer = errors.New("contain forbidden trailer")
|
||||
ErrReadingResponseHeaders = errors.New("error when reading response headers")
|
||||
ErrReadingResponseTrailer = errors.New("error when reading response trailer")
|
||||
ErrResponseFirstLineMissingSpace = errors.New("cannot find whitespace in the first line of response")
|
||||
ErrUnexpectedStatusCodeChar = errors.New("unexpected char at the end of status code")
|
||||
ErrMissingRequestMethod = errors.New("cannot find http request method")
|
||||
ErrUnsupportedRequestMethod = errors.New("unsupported http request method")
|
||||
ErrExtraWhitespaceInRequestLine = errors.New("extra whitespace in request line")
|
||||
ErrEmptyRequestURI = errors.New("requestURI cannot be empty")
|
||||
ErrDuplicateContentLength = errors.New("duplicate Content-Length header")
|
||||
ErrUnsupportedTransferEncoding = errors.New("unsupported Transfer-Encoding")
|
||||
ErrNonNumericChars = errors.New("non-numeric chars found")
|
||||
ErrNeedMore = errors.New("need more data: cannot find trailing lf")
|
||||
ErrSmallReadBuffer = errors.New("small read buffer. Increase ReadBufferSize")
|
||||
)
|
||||
|
||||
// AddTrailerBytes add Trailer header value for chunked response
|
||||
// to indicate which headers will be sent after the body.
|
||||
@@ -2088,7 +2103,7 @@ func (h *ResponseHeader) Read(r *bufio.Reader) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if err != errNeedMore {
|
||||
if err != ErrNeedMore {
|
||||
h.resetSkipNormalize()
|
||||
return err
|
||||
}
|
||||
@@ -2113,11 +2128,11 @@ func (h *ResponseHeader) tryRead(r *bufio.Reader, n int) error {
|
||||
if err == bufio.ErrBufferFull {
|
||||
if h.secureErrorLogMessage {
|
||||
return &ErrSmallBuffer{
|
||||
error: errors.New("error when reading response headers"),
|
||||
error: ErrReadingResponseHeaders,
|
||||
}
|
||||
}
|
||||
return &ErrSmallBuffer{
|
||||
error: fmt.Errorf("error when reading response headers: %w", errSmallBuffer),
|
||||
error: fmt.Errorf("error when reading response headers: %w", ErrSmallReadBuffer),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2142,7 +2157,7 @@ func (h *header) ReadTrailer(r *bufio.Reader) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if err != errNeedMore {
|
||||
if err != ErrNeedMore {
|
||||
return err
|
||||
}
|
||||
n = r.Buffered() + 1
|
||||
@@ -2165,11 +2180,11 @@ func (h *header) tryReadTrailer(r *bufio.Reader, n int) error {
|
||||
if err == bufio.ErrBufferFull {
|
||||
if h.secureErrorLogMessage {
|
||||
return &ErrSmallBuffer{
|
||||
error: errors.New("error when reading response trailer"),
|
||||
error: ErrReadingResponseTrailer,
|
||||
}
|
||||
}
|
||||
return &ErrSmallBuffer{
|
||||
error: fmt.Errorf("error when reading response trailer: %w", errSmallBuffer),
|
||||
error: fmt.Errorf("error when reading response trailer: %w", ErrSmallReadBuffer),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2189,11 +2204,11 @@ func (h *header) tryReadTrailer(r *bufio.Reader, n int) error {
|
||||
}
|
||||
|
||||
func headerError(typ string, err, errParse error, b []byte, secureErrorLogMessage bool) error {
|
||||
if errParse != errNeedMore {
|
||||
if errParse != ErrNeedMore {
|
||||
return headerErrorMsg(typ, errParse, b, secureErrorLogMessage)
|
||||
}
|
||||
if err == nil {
|
||||
return errNeedMore
|
||||
return ErrNeedMore
|
||||
}
|
||||
|
||||
// Buggy servers may leave trailing CRLFs after http body.
|
||||
@@ -2206,7 +2221,7 @@ func headerError(typ string, err, errParse error, b []byte, secureErrorLogMessag
|
||||
return headerErrorMsg(typ, err, b, secureErrorLogMessage)
|
||||
}
|
||||
return &ErrSmallBuffer{
|
||||
error: headerErrorMsg(typ, errSmallBuffer, b, secureErrorLogMessage),
|
||||
error: headerErrorMsg(typ, ErrSmallReadBuffer, b, secureErrorLogMessage),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2234,7 +2249,7 @@ func (h *RequestHeader) readLoop(r *bufio.Reader, waitForMore bool) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if !waitForMore || err != errNeedMore {
|
||||
if !waitForMore || err != ErrNeedMore {
|
||||
h.resetSkipNormalize()
|
||||
return err
|
||||
}
|
||||
@@ -2257,7 +2272,7 @@ func (h *RequestHeader) tryRead(r *bufio.Reader, n int) error {
|
||||
// This is for go 1.6 bug. See https://github.com/golang/go/issues/14121 .
|
||||
if err == bufio.ErrBufferFull {
|
||||
return &ErrSmallBuffer{
|
||||
error: fmt.Errorf("error when reading request headers: %w (n=%d, r.Buffered()=%d)", errSmallBuffer, n, r.Buffered()),
|
||||
error: fmt.Errorf("error when reading request headers: %w (n=%d, r.Buffered()=%d)", ErrSmallReadBuffer, n, r.Buffered()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2744,7 +2759,7 @@ func (h *ResponseHeader) parseFirstLine(buf []byte) (int, error) {
|
||||
n := bytes.IndexByte(b, ' ')
|
||||
if n < 0 {
|
||||
if h.secureErrorLogMessage {
|
||||
return 0, errors.New("cannot find whitespace in the first line of response")
|
||||
return 0, ErrResponseFirstLineMissingSpace
|
||||
}
|
||||
return 0, fmt.Errorf("cannot find whitespace in the first line of response %q", buf)
|
||||
}
|
||||
@@ -2761,7 +2776,7 @@ func (h *ResponseHeader) parseFirstLine(buf []byte) (int, error) {
|
||||
}
|
||||
if len(b) > n && b[n] != ' ' {
|
||||
if h.secureErrorLogMessage {
|
||||
return 0, errors.New("unexpected char at the end of status code")
|
||||
return 0, ErrUnexpectedStatusCodeChar
|
||||
}
|
||||
return 0, fmt.Errorf("unexpected char at the end of status code. Response %q", buf)
|
||||
}
|
||||
@@ -2795,7 +2810,7 @@ func (h *RequestHeader) parseFirstLine(buf []byte) (int, error) {
|
||||
n := bytes.IndexByte(b, ' ')
|
||||
if n <= 0 {
|
||||
if h.secureErrorLogMessage {
|
||||
return 0, errors.New("cannot find http request method")
|
||||
return 0, ErrMissingRequestMethod
|
||||
}
|
||||
return 0, fmt.Errorf("cannot find http request method in %q", buf)
|
||||
}
|
||||
@@ -2803,7 +2818,7 @@ func (h *RequestHeader) parseFirstLine(buf []byte) (int, error) {
|
||||
|
||||
if !isValidMethod(h.method) {
|
||||
if h.secureErrorLogMessage {
|
||||
return 0, errors.New("unsupported http request method")
|
||||
return 0, ErrUnsupportedRequestMethod
|
||||
}
|
||||
return 0, fmt.Errorf("unsupported http request method %q in %q", h.method, buf)
|
||||
}
|
||||
@@ -2813,7 +2828,7 @@ func (h *RequestHeader) parseFirstLine(buf []byte) (int, error) {
|
||||
// Check for extra whitespace after method - only one space should separate method from URI
|
||||
if len(b) > 0 && b[0] == ' ' {
|
||||
if h.secureErrorLogMessage {
|
||||
return 0, errors.New("extra whitespace in request line")
|
||||
return 0, ErrExtraWhitespaceInRequestLine
|
||||
}
|
||||
return 0, fmt.Errorf("extra whitespace in request line %q", buf)
|
||||
}
|
||||
@@ -2824,7 +2839,7 @@ func (h *RequestHeader) parseFirstLine(buf []byte) (int, error) {
|
||||
return 0, fmt.Errorf("cannot find whitespace in the first line of request %q", buf)
|
||||
} else if n == 0 {
|
||||
if h.secureErrorLogMessage {
|
||||
return 0, errors.New("requestURI cannot be empty")
|
||||
return 0, ErrEmptyRequestURI
|
||||
}
|
||||
return 0, fmt.Errorf("requestURI cannot be empty in %q", buf)
|
||||
}
|
||||
@@ -2832,7 +2847,7 @@ func (h *RequestHeader) parseFirstLine(buf []byte) (int, error) {
|
||||
// Check for extra whitespace - only one space should separate URI from HTTP version
|
||||
if n+1 < len(b) && b[n+1] == ' ' {
|
||||
if h.secureErrorLogMessage {
|
||||
return 0, errors.New("extra whitespace in request line")
|
||||
return 0, ErrExtraWhitespaceInRequestLine
|
||||
}
|
||||
return 0, fmt.Errorf("extra whitespace in request line %q", buf)
|
||||
}
|
||||
@@ -2869,7 +2884,7 @@ func (h *RequestHeader) parseFirstLine(buf []byte) (int, error) {
|
||||
func readRawHeaders(dst, buf []byte) ([]byte, int, error) {
|
||||
n := bytes.IndexByte(buf, nChar)
|
||||
if n < 0 {
|
||||
return dst[:0], 0, errNeedMore
|
||||
return dst[:0], 0, ErrNeedMore
|
||||
}
|
||||
if (n == 1 && buf[0] == rChar) || n == 0 {
|
||||
// empty headers
|
||||
@@ -2883,7 +2898,7 @@ func readRawHeaders(dst, buf []byte) ([]byte, int, error) {
|
||||
b = b[m:]
|
||||
m = bytes.IndexByte(b, nChar)
|
||||
if m < 0 {
|
||||
return dst, 0, errNeedMore
|
||||
return dst, 0, ErrNeedMore
|
||||
}
|
||||
m++
|
||||
n += m
|
||||
@@ -3077,7 +3092,7 @@ func (h *RequestHeader) parseHeaders(buf []byte) (int, error) {
|
||||
if caseInsensitiveCompare(s.key, strContentLength) {
|
||||
if contentLengthSeen {
|
||||
h.connectionClose = true
|
||||
return 0, errors.New("duplicate Content-Length header")
|
||||
return 0, ErrDuplicateContentLength
|
||||
}
|
||||
contentLengthSeen = true
|
||||
|
||||
@@ -3110,7 +3125,7 @@ func (h *RequestHeader) parseHeaders(buf []byte) (int, error) {
|
||||
if !isIdentity && !isChunked {
|
||||
h.connectionClose = true
|
||||
if h.secureErrorLogMessage {
|
||||
return 0, errors.New("unsupported Transfer-Encoding")
|
||||
return 0, ErrUnsupportedTransferEncoding
|
||||
}
|
||||
return 0, fmt.Errorf("unsupported Transfer-Encoding: %q", s.value)
|
||||
}
|
||||
@@ -3169,15 +3184,13 @@ func (h *RequestHeader) collectCookies() {
|
||||
h.cookiesCollected = true
|
||||
}
|
||||
|
||||
var errNonNumericChars = errors.New("non-numeric chars found")
|
||||
|
||||
func parseContentLength(b []byte) (int, error) {
|
||||
v, n, err := parseUintBuf(b)
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf("cannot parse Content-Length: %w", err)
|
||||
}
|
||||
if n != len(b) {
|
||||
return -1, fmt.Errorf("cannot parse Content-Length: %w", errNonNumericChars)
|
||||
return -1, fmt.Errorf("cannot parse Content-Length: %w", ErrNonNumericChars)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
@@ -3227,7 +3240,7 @@ func hasHeaderValue(s, value []byte) bool {
|
||||
func nextLine(b []byte) ([]byte, []byte, error) {
|
||||
nNext := bytes.IndexByte(b, nChar)
|
||||
if nNext < 0 {
|
||||
return nil, nil, errNeedMore
|
||||
return nil, nil, ErrNeedMore
|
||||
}
|
||||
n := nNext
|
||||
if n > 0 && b[n-1] == rChar {
|
||||
@@ -3370,11 +3383,6 @@ func copyTrailer(dst, src [][]byte) [][]byte {
|
||||
return dst
|
||||
}
|
||||
|
||||
var (
|
||||
errNeedMore = errors.New("need more data: cannot find trailing lf")
|
||||
errSmallBuffer = errors.New("small read buffer. Increase ReadBufferSize")
|
||||
)
|
||||
|
||||
// ErrNothingRead is returned when a keep-alive connection is closed,
|
||||
// either because the remote closed it or because of a read timeout.
|
||||
type ErrNothingRead struct {
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ func (s *headerScanner) next() bool {
|
||||
|
||||
i := bytes.Index(s.b, strCRLFCRLF)
|
||||
if i < 0 {
|
||||
s.err = errNeedMore
|
||||
s.err = ErrNeedMore
|
||||
return false
|
||||
}
|
||||
i += 4
|
||||
|
||||
@@ -2314,7 +2314,7 @@ func (s *Server) serveConn(c net.Conn) error {
|
||||
// outgoing buffer first so it doesn't have to wait.
|
||||
if bw != nil && bw.Buffered() > 0 {
|
||||
err = ctx.Request.Header.readLoop(br, false)
|
||||
if err == errNeedMore {
|
||||
if err == ErrNeedMore {
|
||||
err = bw.Flush()
|
||||
if err != nil {
|
||||
break
|
||||
|
||||
+1
-1
@@ -500,7 +500,7 @@ func TestServerErrSmallBuffer(t *testing.T) {
|
||||
t.Fatal("missing 'Connection: close' response header")
|
||||
}
|
||||
|
||||
expectedErr := errSmallBuffer.Error()
|
||||
expectedErr := ErrSmallReadBuffer.Error()
|
||||
if !strings.Contains(serverErr.Error(), expectedErr) {
|
||||
t.Fatalf("unexpected log output: %v. Expecting %q", serverErr, expectedErr)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user