From 1872b07d7ee74c2f3c0b5da6d02c9043b77017fb Mon Sep 17 00:00:00 2001 From: ksw2000 <13825170+ksw2000@users.noreply.github.com> Date: Mon, 22 Jul 2024 13:33:21 +0800 Subject: [PATCH] Fix RequestHeader parser (#1808) When FastHTTP receives a header value suffixed or prefixed with tabs, they should be stripped. --- header.go | 21 +++++++++++++++++---- header_test.go | 5 +++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/header.go b/header.go index fb9d4b30bb..3f0fa5a572 100644 --- a/header.go +++ b/header.go @@ -3298,7 +3298,7 @@ func (s *headerScanner) next() bool { s.key = s.b[:n] normalizeHeaderKey(s.key, s.disableNormalizing) n++ - for len(s.b) > n && s.b[n] == ' ' { + for len(s.b) > n && (s.b[n] == ' ' || s.b[n] == '\t') { n++ // the newline index is a relative index, and lines below trimmed `s.b` by `n`, // so the relative newline index also shifted forward. it's safe to decrease @@ -3352,13 +3352,18 @@ func (s *headerScanner) next() bool { if n > 0 && s.value[n-1] == rChar { n-- } - for n > 0 && s.value[n-1] == ' ' { + for n > 0 && (s.value[n-1] == ' ' || s.value[n-1] == '\t') { n-- } s.value = s.value[:n] if isMultiLineValue { s.value, s.b, s.hLen = normalizeHeaderValue(s.value, oldB, s.hLen) } + + for len(s.b) > 0 && (s.b[0] == ' ' || s.b[0] == '\t') { + s.b = s.b[1:] + } + return true } @@ -3437,6 +3442,7 @@ func normalizeHeaderValue(ov, ob []byte, headerLength int) (nv, nb []byte, nhl i } write := 0 shrunk := 0 + once := false lineStart := false for read := 0; read < length; read++ { c := ov[read] @@ -3445,10 +3451,17 @@ func normalizeHeaderValue(ov, ob []byte, headerLength int) (nv, nb []byte, nhl i shrunk++ if c == nChar { lineStart = true + once = false } continue - case lineStart && c == '\t': - c = ' ' + case lineStart && (c == '\t' || c == ' '): + if !once { + c = ' ' + once = true + } else { + shrunk++ + continue + } default: lineStart = false } diff --git a/header_test.go b/header_test.go index 89eea8346a..7517ad9fb9 100644 --- a/header_test.go +++ b/header_test.go @@ -67,6 +67,11 @@ func TestResponseHeaderMultiLineValue(t *testing.T) { "Foo: Bar\r\n" + "Multi-Line: one;\r\n two\r\n" + "Values: v1;\r\n v2; v3;\r\n v4;\tv5\r\n" + + // issue #1808 + "WithTabs: \t v1 \t\r\n" + + "WithTabs-Start: \t \t v1 \r\n" + + "WithTabs-End: v1 \t \t\t\t\r\n" + + "WithTabs-Multi-Line: \t v1 \t;\r\n \t v2 \t;\r\n\t v3\r\n" + "\r\n" header := new(ResponseHeader) if _, err := header.parse([]byte(s)); err != nil {