112 lines
2.9 KiB
Go
112 lines
2.9 KiB
Go
|
|
package request
|
||
|
|
|
||
|
|
import (
|
||
|
|
"io"
|
||
|
|
"testing"
|
||
|
|
|
||
|
|
"github.com/stretchr/testify/assert"
|
||
|
|
"github.com/stretchr/testify/require"
|
||
|
|
)
|
||
|
|
|
||
|
|
type chunkReader struct {
|
||
|
|
data string
|
||
|
|
numBytesPerRead int
|
||
|
|
pos int
|
||
|
|
}
|
||
|
|
|
||
|
|
// Read reads up to len(p) or numBytesPerRead bytes from the string per call
|
||
|
|
// its useful for simulating reading a variable number of bytes per chunk from a network connection
|
||
|
|
func (cr *chunkReader) Read(p []byte) (n int, err error) {
|
||
|
|
if cr.pos >= len(cr.data) {
|
||
|
|
return 0, io.EOF
|
||
|
|
}
|
||
|
|
endIndex := cr.pos + cr.numBytesPerRead
|
||
|
|
if endIndex > len(cr.data) {
|
||
|
|
endIndex = len(cr.data)
|
||
|
|
}
|
||
|
|
n = copy(p, cr.data[cr.pos:endIndex])
|
||
|
|
cr.pos += n
|
||
|
|
|
||
|
|
return n, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestRequestLineParse(t *testing.T) {
|
||
|
|
// Test: Good GET Request line
|
||
|
|
reader := &chunkReader{
|
||
|
|
data: "GET / HTTP/1.1\r\nHost: localhost:42069\r\nUser-Agent: curl/7.81.0\r\nAccept: */*\r\n\r\n",
|
||
|
|
numBytesPerRead: 3,
|
||
|
|
}
|
||
|
|
r, err := RequestFromReader(reader)
|
||
|
|
require.NoError(t, err)
|
||
|
|
require.NotNil(t, r)
|
||
|
|
assert.Equal(t, "GET", r.RequestLine.Method)
|
||
|
|
assert.Equal(t, "/", r.RequestLine.RequestTarget)
|
||
|
|
assert.Equal(t, "1.1", r.RequestLine.HttpVersion)
|
||
|
|
|
||
|
|
// Test: Good GET Request line with path
|
||
|
|
reader = &chunkReader{
|
||
|
|
data: "GET /coffee HTTP/1.1\r\nHost: localhost:42069\r\nUser-Agent: curl/7.81.0\r\nAccept: */*\r\n\r\n",
|
||
|
|
numBytesPerRead: 1,
|
||
|
|
}
|
||
|
|
r, err = RequestFromReader(reader)
|
||
|
|
require.NoError(t, err)
|
||
|
|
require.NotNil(t, r)
|
||
|
|
assert.Equal(t, "GET", r.RequestLine.Method)
|
||
|
|
assert.Equal(t, "/coffee", r.RequestLine.RequestTarget)
|
||
|
|
assert.Equal(t, "1.1", r.RequestLine.HttpVersion)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestParseHeaders(t *testing.T) {
|
||
|
|
// Test: Standard Headers
|
||
|
|
reader := &chunkReader{
|
||
|
|
data: "GET / HTTP/1.1\r\nHost: localhost:42069\r\nUser-Agent: curl/7.81.0\r\nAccept: */*\r\n\r\n",
|
||
|
|
numBytesPerRead: 3,
|
||
|
|
}
|
||
|
|
r, err := RequestFromReader(reader)
|
||
|
|
require.NoError(t, err)
|
||
|
|
require.NotNil(t, r)
|
||
|
|
|
||
|
|
host, _ := r.Headers.Get("host")
|
||
|
|
assert.Equal(t, "localhost:42069", host)
|
||
|
|
user, _ := r.Headers.Get("user-agent")
|
||
|
|
assert.Equal(t, "curl/7.81.0", user)
|
||
|
|
accept, _ := r.Headers.Get("accept")
|
||
|
|
assert.Equal(t, "*/*", accept)
|
||
|
|
|
||
|
|
// Test: Malformed Header
|
||
|
|
reader = &chunkReader{
|
||
|
|
data: "GET / HTTP/1.1\r\nHost localhost:42069\r\n\r\n",
|
||
|
|
numBytesPerRead: 3,
|
||
|
|
}
|
||
|
|
r, err = RequestFromReader(reader)
|
||
|
|
require.Error(t, err)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestParseBody(t *testing.T) {
|
||
|
|
// Test: Standard Body
|
||
|
|
reader := &chunkReader{
|
||
|
|
data: "POST /submit HTTP/1.1\r\n" +
|
||
|
|
"Host: localhost:42069\r\n" +
|
||
|
|
"Content-Length: 13\r\n" +
|
||
|
|
"\r\n" +
|
||
|
|
"hello world!\n",
|
||
|
|
numBytesPerRead: 3,
|
||
|
|
}
|
||
|
|
r, err := RequestFromReader(reader)
|
||
|
|
require.NoError(t, err)
|
||
|
|
require.NotNil(t, r)
|
||
|
|
assert.Equal(t, "hello world!\n", string(r.Body))
|
||
|
|
|
||
|
|
// Test: Body shorter than reported content length
|
||
|
|
reader = &chunkReader{
|
||
|
|
data: "POST /submit HTTP/1.1\r\n" +
|
||
|
|
"Host: localhost:42069\r\n" +
|
||
|
|
"Content-Length: 20\r\n" +
|
||
|
|
"\r\n" +
|
||
|
|
"partial content",
|
||
|
|
numBytesPerRead: 3,
|
||
|
|
}
|
||
|
|
r, err = RequestFromReader(reader)
|
||
|
|
require.Error(t, err)
|
||
|
|
}
|