Set ConnectionClose for non-http/1.1 requests/responses. Do not support Connection: keep-alive for http/1.0 intentionally, since it will complicate the code without measurable benefits

This commit is contained in:
Aliaksandr Valialkin
2015-11-13 12:27:47 +02:00
parent 15cd28e255
commit 16632cbaa4
2 changed files with 65 additions and 3 deletions
+10 -1
View File
@@ -781,11 +781,15 @@ func (h *ResponseHeader) parseFirstLine(buf []byte) (b []byte, err error) {
}
}
// skip protocol
// parse protocol
n := bytes.IndexByte(b, ' ')
if n < 0 {
return nil, fmt.Errorf("cannot find whitespace in the first line of response %q", buf)
}
if !bytes.Equal(b[:n], strHTTP11) {
// Non-http/1.1 response. Close connection after it.
h.ConnectionClose = true
}
b = b[n+1:]
// parse status code
@@ -819,9 +823,14 @@ func (h *RequestHeader) parseFirstLine(buf []byte) (b []byte, err error) {
// parse requestURI
n = bytes.LastIndexByte(b, ' ')
if n < 0 {
// no http protocol found. Close connection after the request.
h.ConnectionClose = true
n = len(b)
} else if n == 0 {
return nil, fmt.Errorf("RequestURI cannot be empty in %q", buf)
} else if !bytes.Equal(b[n+1:], strHTTP11) {
// non-http/1.1 protocol. Close connection after the request.
h.ConnectionClose = true
}
h.RequestURI = append(h.RequestURI[:0], b[:n]...)
+55 -2
View File
@@ -10,6 +10,56 @@ import (
"testing"
)
func TestResponseHeaderHTTPVer(t *testing.T) {
// non-http/1.1
testResponseHeaderHTTPVer(t, "HTTP/1.0 200 OK\r\nContent-Type: aaa\r\nContent-Length: 123\r\n\r\n", true)
testResponseHeaderHTTPVer(t, "HTTP/0.9 200 OK\r\nContent-Type: aaa\r\nContent-Length: 123\r\n\r\n", true)
testResponseHeaderHTTPVer(t, "foobar 200 OK\r\nContent-Type: aaa\r\nContent-Length: 123\r\n\r\n", true)
// http/1.1
testResponseHeaderHTTPVer(t, "HTTP/1.1 200 OK\r\nContent-Type: aaa\r\nContent-Length: 123\r\n\r\n", false)
}
func TestRequestHeaderHTTPVer(t *testing.T) {
// non-http/1.1
testRequestHeaderHTTPVer(t, "GET / HTTP/1.0\r\nHost: aa.com\r\n\r\n", true)
testRequestHeaderHTTPVer(t, "GET / HTTP/0.9\r\nHost: aa.com\r\n\r\n", true)
testRequestHeaderHTTPVer(t, "GET / foobar\r\nHost: aa.com\r\n\r\n", true)
// empty http version
testRequestHeaderHTTPVer(t, "GET /\r\nHost: aaa.com\r\n\r\n", true)
testRequestHeaderHTTPVer(t, "GET / \r\nHost: aaa.com\r\n\r\n", true)
// http/1.1
testRequestHeaderHTTPVer(t, "GET / HTTP/1.1\r\nHost: a.com\r\n\r\n", false)
}
func testResponseHeaderHTTPVer(t *testing.T, s string, connectionClose bool) {
var h ResponseHeader
r := bytes.NewBufferString(s)
br := bufio.NewReader(r)
if err := h.Read(br); err != nil {
t.Fatalf("unexpected error: %s. response=%q", err, s)
}
if h.ConnectionClose != connectionClose {
t.Fatalf("unexpected connectionClose %v. Expecting %v. response=%q", h.ConnectionClose, connectionClose, s)
}
}
func testRequestHeaderHTTPVer(t *testing.T, s string, connectionClose bool) {
var h RequestHeader
r := bytes.NewBufferString(s)
br := bufio.NewReader(r)
if err := h.Read(br); err != nil {
t.Fatalf("unexpected error: %s. request=%q", err, s)
}
if h.ConnectionClose != connectionClose {
t.Fatalf("unexpected connectionClose %v. Expecting %v. request=%q", h.ConnectionClose, connectionClose, s)
}
}
func TestResponseHeaderCopyTo(t *testing.T) {
var h ResponseHeader
@@ -719,13 +769,16 @@ func TestRequestHeaderReadSuccess(t *testing.T) {
// ancient http protocol
testRequestHeaderReadSuccess(t, h, "GET /bar HTTP/1.0\r\nHost: gole\r\n\r\npppp",
0, "/bar", "gole", "", "", "pppp")
if h.ConnectionClose {
t.Fatalf("unexpected connection: close header")
if !h.ConnectionClose {
t.Fatalf("expecting connectionClose for ancient http protocol")
}
// complex headers with body
testRequestHeaderReadSuccess(t, h, "GET /aabar HTTP/1.1\r\nAAA: bbb\r\nHost: ole.com\r\nAA: bb\r\n\r\nzzz",
0, "/aabar", "ole.com", "", "", "zzz")
if h.ConnectionClose {
t.Fatalf("unexpected connection: close")
}
// lf instead of crlf
testRequestHeaderReadSuccess(t, h, "GET /foo/bar HTTP/1.1\nHost: google.com\n\n",