mirror of
https://github.com/buger/goreplay.git
synced 2024-04-21 12:32:02 +00:00
This PR does two primary things: - ensures that HasFullPayload returns false if the packet doesnt start with a valid request or response header. This was necessary because a chunked response would return true from HasFullPayload if it got contiguous packets including the last packet (with the trailer) before it got the first packet (with the header). - When the request payload is chunked across multiple packets, only correct for 100-Continue responses once. In requests with > 2 packets, the Ack number is incremented for each packet in the message, sometimes resulting in packets not being correlated with each other. This ensures that the message is corrected once and only once.
506 lines
18 KiB
Go
506 lines
18 KiB
Go
package proto
|
|
|
|
import (
|
|
"bytes"
|
|
"net/textproto"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func TestHeader(t *testing.T) {
|
|
var payload, val []byte
|
|
var headerStart int
|
|
|
|
// Value with space at start
|
|
payload = []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
|
|
if val = Header(payload, []byte("Content-Length")); !bytes.Equal(val, []byte("7")) {
|
|
t.Error("Should find header value")
|
|
}
|
|
|
|
// Value with space at end
|
|
payload = []byte("POST /post HTTP/1.1\r\nContent-Length: 7 \r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
|
|
if val = Header(payload, []byte("Content-Length")); !bytes.Equal(val, []byte("7")) {
|
|
t.Error("Should find header value without space after 7")
|
|
}
|
|
|
|
// Value without space at start
|
|
payload = []byte("POST /post HTTP/1.1\r\nContent-Length:7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
|
|
if val = Header(payload, []byte("Content-Length")); !bytes.Equal(val, []byte("7")) {
|
|
t.Error("Should find header value without space after :")
|
|
}
|
|
|
|
// Value is empty
|
|
payload = []byte("GET /p HTTP/1.1\r\nCookie:\r\nHost: www.w3.org\r\n\r\n")
|
|
|
|
if val = Header(payload, []byte("Cookie")); len(val) > 0 {
|
|
t.Error("Should return empty value")
|
|
}
|
|
|
|
// Header not found
|
|
if _, headerStart, _, _, _ = header(payload, []byte("Not-Found")); headerStart != -1 {
|
|
t.Error("Should not found header")
|
|
}
|
|
|
|
// Lower case headers
|
|
payload = []byte("POST /post HTTP/1.1\r\ncontent-length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
|
|
if val = Header(payload, []byte("Content-Length")); !bytes.Equal(val, []byte("7")) {
|
|
t.Error("Should find lower case 2 word header")
|
|
}
|
|
|
|
payload = []byte("POST /post HTTP/1.1\r\ncontent-length: 7\r\nhost: www.w3.org\r\n\r\na=1&b=2")
|
|
|
|
if val = Header(payload, []byte("host")); !bytes.Equal(val, []byte("www.w3.org")) {
|
|
t.Error("Should find lower case 1 word header")
|
|
}
|
|
|
|
payload = []byte("GT\r\nContent-Length: 10\r\n\r\n")
|
|
|
|
if val = Header(payload, []byte("Content-Length")); !bytes.Equal(val, []byte("10")) {
|
|
t.Error("Should find in partial payload")
|
|
}
|
|
}
|
|
|
|
func TestMIMEHeadersEndPos(t *testing.T) {
|
|
head := []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\n")
|
|
payload := []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
|
|
end := MIMEHeadersEndPos(payload)
|
|
|
|
if !bytes.Equal(payload[:end], head) {
|
|
t.Error("Wrong headers end position:", end, head, payload[:end])
|
|
}
|
|
}
|
|
|
|
func TestMIMEHeadersStartPos(t *testing.T) {
|
|
headers := []byte("Content-Length: 7\r\nHost: www.w3.org")
|
|
payload := []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
|
|
start := MIMEHeadersStartPos(payload)
|
|
end := MIMEHeadersEndPos(payload) - 4
|
|
|
|
if !bytes.Equal(payload[start:end], headers) {
|
|
t.Error("Wrong headers end position:", start, end, payload[start:end])
|
|
}
|
|
}
|
|
|
|
func TestSetHeader(t *testing.T) {
|
|
var payload, payloadAfter []byte
|
|
|
|
payload = []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
payloadAfter = []byte("POST /post HTTP/1.1\r\nContent-Length: 14\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
|
|
if payload = SetHeader(payload, []byte("Content-Length"), []byte("14")); !bytes.Equal(payload, payloadAfter) {
|
|
t.Error("Should update header if it exists", string(payload))
|
|
}
|
|
|
|
payload = []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
payloadAfter = []byte("POST /post HTTP/1.1\r\nUser-Agent: Gor\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
|
|
if payload = SetHeader(payload, []byte("User-Agent"), []byte("Gor")); !bytes.Equal(payload, payloadAfter) {
|
|
t.Error("Should add header if not found", string(payload))
|
|
}
|
|
invalidPayload := []byte("POST /post HTTP/1.1")
|
|
if invalidPayload = SetHeader(invalidPayload, []byte("User-Agent"), []byte("Gor")); !bytes.Equal(invalidPayload, []byte("POST /post HTTP/1.1")) {
|
|
t.Error("Should not modify payload if request is invalid", string(payload))
|
|
}
|
|
}
|
|
|
|
func TestDeleteHeader(t *testing.T) {
|
|
var payload, payloadAfter []byte
|
|
|
|
payload = []byte("POST /post HTTP/1.1\r\nUser-Agent: Gor\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
payloadAfter = []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
|
|
if payload = DeleteHeader(payload, []byte("User-Agent")); !bytes.Equal(payload, payloadAfter) {
|
|
t.Error("Should delete header if found", string(payload), string(payloadAfter))
|
|
}
|
|
|
|
//Whitespace at end of User-Agent
|
|
payload = []byte("POST /post HTTP/1.1\r\nUser-Agent: Gor \r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
payloadAfter = []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
|
|
if payload = DeleteHeader(payload, []byte("User-Agent")); !bytes.Equal(payload, payloadAfter) {
|
|
t.Error("Should delete header if found", string(payload), string(payloadAfter))
|
|
}
|
|
}
|
|
|
|
func TestParseHeaders(t *testing.T) {
|
|
payload := [][]byte{[]byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.or"), []byte("g\r\nUser-Ag"), []byte("ent:Chrome\r\n\r\n"), []byte("Fake-Header: asda")}
|
|
|
|
headers := ParseHeaders(bytes.Join(payload, nil))
|
|
|
|
expected := textproto.MIMEHeader{
|
|
"Content-Length": []string{"7"},
|
|
"Host": []string{"www.w3.org"},
|
|
"User-Agent": []string{"Chrome"},
|
|
}
|
|
|
|
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
|
|
func TestFuzzCrashers(t *testing.T) {
|
|
var crashers = []string{
|
|
"\n:00\n",
|
|
}
|
|
|
|
for _, f := range crashers {
|
|
ParseHeaders([]byte(f))
|
|
}
|
|
}
|
|
|
|
func TestParseHeadersWithComplexUserAgent(t *testing.T) {
|
|
// User-Agent could contain inside ':'
|
|
// Parser should wait for \r\n
|
|
payload := [][]byte{[]byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.or"), []byte("g\r\nUser-Ag"), []byte("ent:Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko\r\n\r\n"), []byte("Fake-Header: asda")}
|
|
|
|
headers := ParseHeaders(bytes.Join(payload, nil))
|
|
|
|
expected := map[string]string{
|
|
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko",
|
|
}
|
|
|
|
if expected["User-Agent"] != headers["User-Agent"][0] {
|
|
t.Errorf("Header 'User-Agent' expected '%s' and parsed: '%s'", expected["User-Agent"], headers["User-Agent"])
|
|
}
|
|
}
|
|
|
|
func TestParseHeadersWithOrigin(t *testing.T) {
|
|
// User-Agent could contain inside ':'
|
|
// Parser should wait for \r\n
|
|
payload := [][]byte{[]byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.or"), []byte("g\r\nReferrer: http://127.0.0.1:3000\r\nOrigi"), []byte("n: https://www.example.com\r\nUser-Ag"), []byte("ent:Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko\r\n\r\n"), []byte("in:https://www.example.com\r\n\r\n"), []byte("Fake-Header: asda")}
|
|
|
|
headers := ParseHeaders(bytes.Join(payload, nil))
|
|
|
|
expected := map[string]string{
|
|
"Origin": "https://www.example.com",
|
|
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko",
|
|
"Referrer": "http://127.0.0.1:3000",
|
|
}
|
|
|
|
if expected["Referrer"] != headers["Referrer"][0] {
|
|
t.Errorf("Header 'Referrer' expected '%s' and parsed: '%s'", expected["Referrer"], headers["Referrer"])
|
|
}
|
|
|
|
if expected["Origin"] != headers["Origin"][0] {
|
|
t.Errorf("Header 'Origin' expected '%s' and parsed: '%s'", expected["Origin"], headers["Origin"])
|
|
}
|
|
|
|
if expected["User-Agent"] != headers["User-Agent"][0] {
|
|
t.Errorf("Header 'User-Agent' expected '%s' and parsed: '%s'", expected["User-Agent"], headers["User-Agent"])
|
|
}
|
|
}
|
|
|
|
func TestPath(t *testing.T) {
|
|
var path, payload []byte
|
|
|
|
payload = []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
|
|
if path = Path(payload); !bytes.Equal(path, []byte("/post")) {
|
|
t.Error("Should find path", string(path))
|
|
}
|
|
|
|
payload = []byte("GET /get\r\n\r\nHost: www.w3.org\r\n\r\n")
|
|
|
|
if path = Path(payload); !bytes.Equal(path, nil) {
|
|
t.Error("1Should not find path", string(path))
|
|
}
|
|
|
|
payload = []byte("GET /get\n")
|
|
|
|
if path = Path(payload); !bytes.Equal(path, nil) {
|
|
t.Error("2Should not find path", string(path))
|
|
}
|
|
|
|
payload = []byte("GET /get")
|
|
|
|
if path = Path(payload); !bytes.Equal(path, nil) {
|
|
t.Error("3Should not find path", string(path))
|
|
}
|
|
}
|
|
|
|
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
|
|
|
|
payload = []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
payloadAfter = []byte("POST /new_path HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
|
|
if payload = SetPath(payload, []byte("/new_path")); !bytes.Equal(payload, payloadAfter) {
|
|
t.Error("Should replace path", string(payload))
|
|
}
|
|
|
|
}
|
|
|
|
func TestPathParam(t *testing.T) {
|
|
var payload []byte
|
|
|
|
payload = []byte("POST /post?param=test&user_id=1&d_type=1&type=2&d_type=3 HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
|
|
if val, _, _ := PathParam(payload, []byte("param")); !bytes.Equal(val, []byte("test")) {
|
|
t.Error("Should detect attribute", string(val))
|
|
}
|
|
|
|
if val, _, _ := PathParam(payload, []byte("user_id")); !bytes.Equal(val, []byte("1")) {
|
|
t.Error("Should detect attribute", string(val))
|
|
}
|
|
|
|
if val, _, _ := PathParam(payload, []byte("type")); !bytes.Equal(val, []byte("2")) {
|
|
t.Error("Should detect attribute", string(val))
|
|
}
|
|
|
|
if val, _, _ := PathParam(payload, []byte("d_type")); !bytes.Equal(val, []byte("1")) {
|
|
// this function is not designed for cases with duplicate param keys
|
|
t.Error("Should detect attribute", string(val))
|
|
}
|
|
}
|
|
|
|
func TestSetPathParam(t *testing.T) {
|
|
var payload, payloadAfter []byte
|
|
|
|
payload = []byte("POST /post?param=test&user_id=1 HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
payloadAfter = []byte("POST /post?param=new&user_id=1 HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
|
|
if payload = SetPathParam(payload, []byte("param"), []byte("new")); !bytes.Equal(payload, payloadAfter) {
|
|
t.Error("Should replace existing value", string(payload))
|
|
}
|
|
|
|
payload = []byte("POST /post?param=test&user_id=1 HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
payloadAfter = []byte("POST /post?param=test&user_id=2 HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
|
|
if payload = SetPathParam(payload, []byte("user_id"), []byte("2")); !bytes.Equal(payload, payloadAfter) {
|
|
t.Error("Should replace existing value", string(payload))
|
|
}
|
|
|
|
payload = []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
payloadAfter = []byte("POST /post?param=test HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
|
|
if payload = SetPathParam(payload, []byte("param"), []byte("test")); !bytes.Equal(payload, payloadAfter) {
|
|
t.Error("Should set param if url have no params", string(payload))
|
|
}
|
|
|
|
payload = []byte("POST /post?param=test HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
payloadAfter = []byte("POST /post?param=test&user_id=1 HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
|
|
if payload = SetPathParam(payload, []byte("user_id"), []byte("1")); !bytes.Equal(payload, payloadAfter) {
|
|
t.Error("Should set param at the end if url params", string(payload))
|
|
}
|
|
}
|
|
|
|
func TestSetHostHTTP10(t *testing.T) {
|
|
var payload, payloadAfter []byte
|
|
|
|
payload = []byte("POST http://example.com/post HTTP/1.0\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
payloadAfter = []byte("POST http://new.com/post HTTP/1.0\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
|
|
|
|
if payload = SetHost(payload, []byte("http://new.com"), []byte("new.com")); !bytes.Equal(payload, payloadAfter) {
|
|
t.Error("Should replace host", string(payload))
|
|
}
|
|
|
|
payload = []byte("POST /post HTTP/1.0\r\nContent-Length: 7\r\nHost: example.com\r\n\r\na=1&b=2")
|
|
payloadAfter = []byte("POST /post HTTP/1.0\r\nContent-Length: 7\r\nHost: new.com\r\n\r\na=1&b=2")
|
|
|
|
if payload = SetHost(payload, nil, []byte("new.com")); !bytes.Equal(payload, payloadAfter) {
|
|
t.Error("Should replace host", string(payload))
|
|
}
|
|
|
|
payload = []byte("POST /post HTTP/1.0\r\nContent-Length: 7\r\n\r\na=1&b=2")
|
|
|
|
if payload = SetHost(payload, nil, []byte("new.com")); !bytes.Equal(payload, payload) {
|
|
t.Error("Should replace host", string(payload))
|
|
}
|
|
}
|
|
|
|
func TestHasResponseTitle(t *testing.T) {
|
|
var m = map[string]bool{
|
|
"HTTP": false,
|
|
"": false,
|
|
"HTTP/1.1 100 Continue": false,
|
|
"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": 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 {
|
|
t.Errorf("%q should yield %v", k, v)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestHasRequestTitle(t *testing.T) {
|
|
var m = map[string]bool{
|
|
"POST /post HTTP/1.0\r\n": true,
|
|
"": false,
|
|
"POST /post HTTP/1.\r\n": false,
|
|
"POS /post HTTP/1.1\r\n": false,
|
|
"GET / HTTP/1.1\r\n": true,
|
|
"GET / HTTP/1.1\r": false,
|
|
"GET / HTTP/1.400\r\n": false,
|
|
}
|
|
for k, v := range m {
|
|
if HasRequestTitle([]byte(k)) != v {
|
|
t.Errorf("%q should yield %v", k, v)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCheckChunks(t *testing.T) {
|
|
var m = "4\r\nWiki\r\n5\r\npedia\r\nE\r\n in\r\n\r\nchunks.\r\n0\r\n\r\n"
|
|
chunkEnd, _ := CheckChunked([]byte(m))
|
|
expected := len(m)
|
|
if chunkEnd != expected {
|
|
t.Errorf("expected %d to equal %d", chunkEnd, expected)
|
|
}
|
|
|
|
m = "7\r\nMozia\r\n9\r\nDeveloper\r\n7\r\nNetwork\r\n0\r\n\r\n"
|
|
chunkEnd, _ = CheckChunked([]byte(m))
|
|
if chunkEnd != 0 {
|
|
t.Errorf("expected %d to equal %d", chunkEnd, 0)
|
|
}
|
|
|
|
// with trailers
|
|
m = "4\r\nWiki\r\n5\r\npedia\r\nE\r\n in\r\n\r\nchunks.\r\n0\r\n\r\nEXpires"
|
|
chunkEnd, _ = CheckChunked([]byte(m))
|
|
expected = len(m) - 7
|
|
if chunkEnd != expected {
|
|
t.Errorf("expected %d to equal %d", chunkEnd, expected)
|
|
}
|
|
|
|
// last chunk inside the body
|
|
// with trailers
|
|
m = "4\r\nWiki\r\n5\r\npedia\r\nE\r\n in\r\n\r\nchunks.\r\n3\r\n0\r\n\r\n0\r\n\r\nEXpires"
|
|
chunkEnd, _ = CheckChunked([]byte(m))
|
|
expected = len(m) - 7
|
|
if chunkEnd != expected {
|
|
t.Errorf("expected %d to equal %d", chunkEnd, expected)
|
|
}
|
|
|
|
// checks with chucks-extensions
|
|
m = "4\r\nWiki\r\n5\r\npedia\r\nE; name='quoted string'\r\n in\r\n\r\nchunks.\r\n3\r\n0\r\n\r\n0\r\n\r\nEXpires"
|
|
chunkEnd, _ = CheckChunked([]byte(m))
|
|
expected = len(m) - 7
|
|
if chunkEnd != expected {
|
|
t.Errorf("expected %d to equal %d", chunkEnd, expected)
|
|
}
|
|
}
|
|
|
|
func TestHasFullPayload(t *testing.T) {
|
|
var m string
|
|
var got, expected bool
|
|
|
|
got = HasFullPayload(nil,
|
|
[]byte("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n"),
|
|
[]byte("Transfer-Encoding: chunked\r\n\r\n"),
|
|
[]byte("7\r\nMozilla\r\n9\r\nDeveloper\r\n"),
|
|
[]byte("7\r\nNetwork\r\n0\r\n\r\n"))
|
|
expected = true
|
|
if got != expected {
|
|
t.Errorf("expected %v to equal %v", got, expected)
|
|
}
|
|
|
|
// check chunks with trailers
|
|
m = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\nTrailer: Expires\r\n\r\n7\r\nMozilla\r\n9\r\nDeveloper\r\n7\r\nNetwork\r\n0\r\n\r\nExpires: Wed, 21 Oct 2015 07:28:00 GMT\r\n\r\n"
|
|
got = HasFullPayload(nil, []byte(m))
|
|
expected = true
|
|
if got != expected {
|
|
t.Errorf("expected %v to equal %v", got, expected)
|
|
}
|
|
|
|
// check with missing trailers
|
|
m = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\nTrailer: Expires\r\n\r\n7\r\nMozilla\r\n9\r\nDeveloper\r\n7\r\nNetwork\r\n0\r\n\r\nExpires: Wed, 21 Oct 2015 07:28:00"
|
|
got = HasFullPayload(nil, []byte(m))
|
|
expected = false
|
|
if got != expected {
|
|
t.Errorf("expected %v to equal %v", got, expected)
|
|
}
|
|
|
|
// check with content-length
|
|
m = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 23\r\n\r\nMozillaDeveloperNetwork"
|
|
got = HasFullPayload(nil, []byte(m))
|
|
expected = true
|
|
if got != expected {
|
|
t.Errorf("expected %v to equal %v", got, expected)
|
|
}
|
|
|
|
// check missing total length
|
|
m = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 23\r\n\r\nMozillaDeveloperNet"
|
|
got = HasFullPayload(nil, []byte(m))
|
|
expected = false
|
|
if got != expected {
|
|
t.Errorf("expected %v to equal %v", got, expected)
|
|
}
|
|
|
|
// check with no body
|
|
m = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n"
|
|
got = HasFullPayload(nil, []byte(m))
|
|
expected = true
|
|
if got != expected {
|
|
t.Errorf("expected %v to equal %v", got, expected)
|
|
}
|
|
|
|
// check with trailer and no header
|
|
m = "Content-Type: text/plain\r\nContent-Length: 23\r\n\r\nMozillaDeveloperNetwork"
|
|
got = HasFullPayload(nil, []byte(m))
|
|
expected = false
|
|
if got != expected {
|
|
t.Errorf("expected %v to equal %v", got, expected)
|
|
}
|
|
}
|
|
|
|
func BenchmarkHasFullPayload(b *testing.B) {
|
|
data := []byte("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\n\r\n1e\r\n111111111111111111111111111111\r\n0\r\n\r\n")
|
|
for i := 0; i < b.N; i++ {
|
|
if !HasFullPayload(nil, data) {
|
|
b.Fail()
|
|
}
|
|
}
|
|
}
|