From 51db961942fa90b16cbe7e77d10f39d24f081434 Mon Sep 17 00:00:00 2001 From: Urban Ishimwe Date: Fri, 15 Jan 2021 20:37:22 +0200 Subject: [PATCH] fix-#875 (#882) fix #875 --- proto/proto.go | 25 ++++++++++++++----------- proto/proto_test.go | 42 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 54 insertions(+), 13 deletions(-) diff --git a/proto/proto.go b/proto/proto.go index 3f2177d..d4b3847 100644 --- a/proto/proto.go +++ b/proto/proto.go @@ -195,7 +195,7 @@ func Body(payload []byte) []byte { // Path takes payload and retuns request path: Split(firstLine, ' ')[1] func Path(payload []byte) []byte { - if !HasTitle(payload) { + if !HasRequestTitle(payload) { return nil } start := bytes.IndexByte(payload, ' ') + 1 @@ -309,7 +309,12 @@ func Method(payload []byte) []byte { // Status returns response status. // It happens to be in same position as request payload path func Status(payload []byte) []byte { - return Path(payload) + if !HasResponseTitle(payload) { + return nil + } + start := bytes.IndexByte(payload, ' ') + 1 + // status code are in range 100-600 + return payload[start : start+3] } // Methods holds the http methods ordered in ascending order @@ -322,8 +327,8 @@ var Methods = [...]string{ const ( //MinRequestCount GET / HTTP/1.1\r\n MinRequestCount = 16 - // MinResponseCount HTTP/1.1 200 OK\r\n - MinResponseCount = 17 + // MinResponseCount HTTP/1.1 200\r\n + MinResponseCount = 14 // VersionLen HTTP/1.1 VersionLen = 8 ) @@ -346,17 +351,15 @@ func HasResponseTitle(payload []byte) bool { return false } status, ok := atoI(payload[VersionLen+1:VersionLen+4], 10) - if !ok || s[VersionLen+4] != ' ' { + if !ok { return false } - statusText := http.StatusText(status) - if statusText == "" { + // only validate status codes mentioned in rfc2616. + if len(http.StatusText(status)) == 0 { return false } - if titleLen+len(CRLF) > len(s) { - return false - } - return s[VersionLen+5:titleLen] == statusText + // handle cases from #875 + return payload[VersionLen+4] == ' ' || payload[VersionLen+4] == '\r' } // HasRequestTitle reports whether this payload has an HTTP/1 request title diff --git a/proto/proto_test.go b/proto/proto_test.go index 3c648ef..b37cbdc 100644 --- a/proto/proto_test.go +++ b/proto/proto_test.go @@ -136,6 +136,24 @@ func TestParseHeaders(t *testing.T) { if !reflect.DeepEqual(headers, expected) { t.Error("Headers do not properly parsed", headers) } + + // Response with Reason phrase + payload = [][]byte{[]byte("HTTP/1.1 200 OK\r\nContent-Length: 7\r\nHost: www.w3.org\r\nUser-Agent:Chrome\r\n\r\nbody")} + + headers = ParseHeaders(bytes.Join(payload, nil)) + + if !reflect.DeepEqual(headers, expected) { + t.Error("Headers do not properly parsed", headers) + } + + // Response without Reason phrase + payload = [][]byte{[]byte("HTTP/1.1 200\r\nContent-Length: 7\r\nHost: www.w3.org\r\nUser-Agent:Chrome\r\n\r\nbody")} + + headers = ParseHeaders(bytes.Join(payload, nil)) + + if !reflect.DeepEqual(headers, expected) { + t.Error("Headers do not properly parsed", headers) + } } // See https://github.com/dvyukov/go-fuzz and fuzz.go @@ -219,6 +237,25 @@ func TestPath(t *testing.T) { } } +func TestStatus(t *testing.T) { + var status, payload []byte + + payload = []byte("HTTP/1.1 200 OK\r\n") + if status = Status(payload); !bytes.Equal(status, []byte("200")) { + t.Error("Should find status 200 but:", string(status)) + } + + payload = []byte("HTTP/1.1 200\r\n") + if status = Status(payload); !bytes.Equal(status, []byte("200")) { + t.Error("1Should find status 200 but:", string(status)) + } + + payload = []byte("HTTP/1.1 404 Not Found\r\n") + if status = Status(payload); !bytes.Equal(status, []byte("404")) { + t.Error("2Should find status 404 but:", string(status)) + } +} + func TestSetPath(t *testing.T) { var payload, payloadAfter []byte @@ -318,9 +355,10 @@ func TestHasResponseTitle(t *testing.T) { "HTTP/1.1 100 Continue\r\n": true, "HTTP/1.1 \r\n": false, "HTTP/4.0 100Continue\r\n": false, + "HTTP/1.0 100Continue\r\n": false, "HTTP/1.0 10r Continue\r\n": false, - "HTTP/1.1 200\r\n": false, - "HTTP/1.1 200\r\nServer: Tengine\r\nContent-Length: 0\r\nConnection: close\r\n\r\n": false, + "HTTP/1.1 200\r\n": true, + "HTTP/1.1 200\r\nServer: Tengine\r\nContent-Length: 0\r\nConnection: close\r\n\r\n": true, } for k, v := range m { if HasResponseTitle([]byte(k)) != v {