Allow all HTTP methods to have body (#479)

HTTP specification in section 4.3 (Message Body) states:

"A message-body MUST NOT be included in a request if the specification of the
request method (section 5.1.1)"

Section 5.1.1 has links to the description of each method (sections 9.2
to 9.9). None of those sections prohibit the transfer of a message body,
it just points out how each method should be treated server-side.
This commit is contained in:
Aggelos Avgerinos
2017-08-22 19:28:21 +05:00
committed by Leonid Bugaev
parent 17f6c59061
commit d309650589
2 changed files with 31 additions and 61 deletions
+23 -54
View File
@@ -239,31 +239,26 @@ func (t *TCPMessage) checkIfComplete() {
return
}
// If one GET, OPTIONS, or HEAD request
if t.methodType == httpMethodWithoutBody {
switch t.bodyType {
case httpBodyEmpty:
t.complete = true
} else {
switch t.bodyType {
case httpBodyEmpty:
case httpBodyContentLength:
if t.contentLength == 0 || t.contentLength == t.BodySize() {
t.complete = true
case httpBodyContentLength:
if t.contentLength == 0 || t.contentLength == t.BodySize() {
t.complete = true
}
case httpBodyChunked:
lastPacket := t.packets[len(t.packets)-1]
if bytes.LastIndex(lastPacket.Data, bChunkEnd) != -1 {
t.complete = true
}
default:
if len(t.packets) == 0 {
return
}
}
case httpBodyChunked:
lastPacket := t.packets[len(t.packets)-1]
if bytes.LastIndex(lastPacket.Data, bChunkEnd) != -1 {
t.complete = true
}
default:
if len(t.packets) == 0 {
return
}
last := t.packets[len(t.packets)-1]
if last.IsFIN {
t.complete = true
}
last := t.packets[len(t.packets)-1]
if last.IsFIN {
t.complete = true
}
}
}
@@ -271,19 +266,11 @@ func (t *TCPMessage) checkIfComplete() {
type httpMethodType uint8
const (
httpMethodNotSet httpMethodType = 0
httpMethodWithBody httpMethodType = 1
httpMethodWithoutBody httpMethodType = 2
httpMethodNotFound httpMethodType = 3
httpMethodNotSet httpMethodType = 0
httpMethodKnown httpMethodType = 1
httpMethodNotFound httpMethodType = 2
)
var methodsWithBody = [][]byte{
[]byte("POST"),
[]byte("PUT"),
[]byte("PATCH"),
[]byte("CONNECT"),
}
func (t *TCPMessage) updateMethodType() {
// if there is cache
if t.methodType != httpMethodNotSet && t.methodType != httpMethodNotFound {
@@ -300,11 +287,7 @@ func (t *TCPMessage) updateMethodType() {
}
if t.IsIncoming {
var method []byte
if mIdx := bytes.IndexByte(d[:8], ' '); mIdx != -1 {
method = d[:mIdx]
// Check that after method we have absolute or relative path
switch d[mIdx+1] {
case '/', 'h', '*':
@@ -317,21 +300,14 @@ func (t *TCPMessage) updateMethodType() {
return
}
for _, m := range methodsWithBody {
if len(m) == len(method) && bytes.Equal(m, method) {
t.methodType = httpMethodWithBody
return
}
}
t.methodType = httpMethodWithoutBody
t.methodType = httpMethodKnown
} else {
if !bytes.Equal(d[:6], []byte("HTTP/1")) {
t.methodType = httpMethodNotFound
return
}
t.methodType = httpMethodWithBody
t.methodType = httpMethodKnown
}
}
@@ -379,10 +355,7 @@ func (t *TCPMessage) updateBodyType() {
switch t.methodType {
case httpMethodNotFound:
return
case httpMethodWithoutBody:
t.bodyType = httpBodyEmpty
return
case httpMethodWithBody:
case httpMethodKnown:
if len(lengthB) > 0 {
t.contentLength, _ = strconv.Atoi(string(lengthB))
@@ -424,10 +397,6 @@ func (t *TCPMessage) check100Continue() {
return
}
if t.methodType != httpMethodWithBody {
return
}
if t.seqMissing || t.headerPacket == -1 {
return
}
+8 -7
View File
@@ -170,16 +170,16 @@ func TestTCPMessageMethodType(t *testing.T) {
payload string
expectedMethodType httpMethodType
}{
{true, "GET / HTTP/1.1\r\n\r\n", httpMethodWithoutBody},
{true, "GET * HTTP/1.1\r\n\r\n", httpMethodWithoutBody},
{true, "UNKNOWN / HTTP/1.1\r\n\r\n", httpMethodWithoutBody},
{true, "GET http://example.com HTTP/1.1\r\n\r\n", httpMethodWithoutBody},
{true, "POST / HTTP/1.1\r\n\r\n", httpMethodWithBody},
{true, "PUT / HTTP/1.1\r\n\r\n", httpMethodWithBody},
{true, "GET / HTTP/1.1\r\n\r\n", httpMethodKnown},
{true, "GET * HTTP/1.1\r\n\r\n", httpMethodKnown},
{true, "UNKNOWN / HTTP/1.1\r\n\r\n", httpMethodKnown},
{true, "GET http://example.com HTTP/1.1\r\n\r\n", httpMethodKnown},
{true, "POST / HTTP/1.1\r\n\r\n", httpMethodKnown},
{true, "PUT / HTTP/1.1\r\n\r\n", httpMethodKnown},
{true, "GET zxc HTTP/1.1\r\n\r\n", httpMethodNotFound},
{true, "GET / HTTP\r\n\r\n", httpMethodNotFound},
{true, "VERYLONGMETHOD / HTTP/1.1\r\n\r\n", httpMethodNotFound},
{false, "HTTP/1.1 200 OK\r\n\r\n", httpMethodWithBody},
{false, "HTTP/1.1 200 OK\r\n\r\n", httpMethodKnown},
{false, "HTTP /1.1 200 OK\r\n\r\n", httpMethodNotFound},
}
@@ -199,6 +199,7 @@ func TestTCPMessageBodyType(t *testing.T) {
expectedBodyType httpBodyType
}{
{true, "GET / HTTP/1.1\r\n\r\n", httpBodyEmpty},
{true, "GET / HTTP/1.1\r\nContent-Length: 2\r\n\r\nab", httpBodyContentLength},
{true, "POST / HTTP/1.1\r\n\r\n", httpBodyEmpty},
{true, "POST / HTTP/1.1\r\nUser-Agent: zxc\r\n\r\n", httpBodyEmpty},
{false, "HTTP/1.1 200 OK\r\n\r\n", httpBodyEmpty},