Expose header parsing error variables (#2096)

This commit is contained in:
RW
2025-11-12 02:31:36 +01:00
committed by GitHub
parent e6c64e1d18
commit 2a82a57b9d
4 changed files with 43 additions and 35 deletions
+40 -32
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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)
}