From 5d0cab036712539d50435904ded466bf6b7b0884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?W=C3=A8i=20C=C5=8Dngru=C3=AC?= Date: Thu, 2 Nov 2017 14:23:32 +0800 Subject: [PATCH] net/textproto: ignore initial lines with leading whitespaces in ReadMIMEHeader A header line with leading whitespaces is not valid in HTTP as per RFC7230. This change ignores these invalid lines in ReadMIMEHeader. Updates #22464 Change-Id: Iff9f00380d28a9617a55ff7888a76fba82001402 Reviewed-on: https://go-review.googlesource.com/75350 Reviewed-by: Brad Fitzpatrick --- src/net/http/readrequest_test.go | 20 ++++++++++++++++++++ src/net/http/response_test.go | 22 ++++++++++++++++++++++ src/net/textproto/reader.go | 8 ++++++++ src/net/textproto/reader_test.go | 19 +++++++++++++++++++ 4 files changed, 69 insertions(+) diff --git a/src/net/http/readrequest_test.go b/src/net/http/readrequest_test.go index 28a148b9ac..21c0e098bf 100644 --- a/src/net/http/readrequest_test.go +++ b/src/net/http/readrequest_test.go @@ -401,6 +401,26 @@ var reqTests = []reqTest{ noTrailer, noError, }, + + // leading whitespace in the first header. golang.org/issue/22464 + { + "GET / HTTP/1.1\r\n Foobar: ignored\r\nConnection: close\r\n\r\n", + &Request{ + Method: "GET", + URL: &url.URL{ + Path: "/", + }, + Header: Header{"Connection": {"close"}}, + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + RequestURI: "/", + Close: true, + }, + noBodyStr, + noTrailer, + noError, + }, } func TestReadRequest(t *testing.T) { diff --git a/src/net/http/response_test.go b/src/net/http/response_test.go index f1a50bd598..484a89e46d 100644 --- a/src/net/http/response_test.go +++ b/src/net/http/response_test.go @@ -555,6 +555,28 @@ some body`, }, "Your Authentication failed.\r\n", }, + + // leading whitespace in the first header. golang.org/issue/22464 + { + "HTTP/1.1 200 OK\r\n" + + " Content-type: text/html\r\n" + + "\tIgnore: foobar\r\n" + + "Foo: bar\r\n\r\n", + Response{ + Status: "200 OK", + StatusCode: 200, + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + Request: dummyReq("GET"), + Header: Header{ + "Foo": {"bar"}, + }, + Close: true, + ContentLength: -1, + }, + "", + }, } // tests successful calls to ReadResponse, and inspects the returned Response. diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go index e07d1d62e0..c5e0b7591e 100644 --- a/src/net/textproto/reader.go +++ b/src/net/textproto/reader.go @@ -476,6 +476,14 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) { } m := make(MIMEHeader, hint) + + for r.skipSpace() > 0 { + line, err := r.readLineSlice() + if len(line) == 0 || err != nil { + return m, err + } + } + for { kv, err := r.readContinuedLineSlice() if len(kv) == 0 { diff --git a/src/net/textproto/reader_test.go b/src/net/textproto/reader_test.go index 6cd98ed1b5..b26765e3cd 100644 --- a/src/net/textproto/reader_test.go +++ b/src/net/textproto/reader_test.go @@ -211,6 +211,25 @@ func TestReadMIMEHeaderNonCompliant(t *testing.T) { } } +func TestReadMIMEHeaderLeadingSpace(t *testing.T) { + tests := []struct { + input string + want MIMEHeader + }{ + {" Ignore: ignore\r\nFoo: foo\r\n\r\n", MIMEHeader{"Foo": {"foo"}}}, + {"\tIgnore: ignore\r\nFoo: foo\r\n\r\n", MIMEHeader{"Foo": {"foo"}}}, + {" Ignore1: ignore\r\n Ignore2: ignore\r\nFoo: foo\r\n\r\n", MIMEHeader{"Foo": {"foo"}}}, + {" Ignore1: ignore\r\n\r\n", MIMEHeader{}}, + } + for _, tt := range tests { + r := reader(tt.input) + m, err := r.ReadMIMEHeader() + if !reflect.DeepEqual(m, tt.want) || err != nil { + t.Errorf("ReadMIMEHeader(%q) = %v, %v; want %v", tt.input, m, err, tt.want) + } + } +} + // Test that continued lines are properly trimmed. Issue 11204. func TestReadMIMEHeaderTrimContinued(t *testing.T) { // In this header, \n and \r\n terminated lines are mixed on purpose.