diff --git a/header.go b/header.go index 3cfe82593a..c1265dca94 100644 --- a/header.go +++ b/header.go @@ -3296,7 +3296,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 @@ -3350,13 +3350,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 } @@ -3435,6 +3440,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] @@ -3443,10 +3449,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 {