128 lines
4.3 KiB
V
128 lines
4.3 KiB
V
module fasthttp
|
|
|
|
fn test_parse_http1_request_line_valid_request() {
|
|
buffer := 'GET /path/to/resource HTTP/1.1\r\n'.bytes()
|
|
mut req := HttpRequest{
|
|
buffer: buffer
|
|
}
|
|
|
|
parse_http1_request_line(mut req) or { panic(err) }
|
|
|
|
assert req.method.to_string(req.buffer) == 'GET'
|
|
assert req.path.to_string(req.buffer) == '/path/to/resource'
|
|
assert req.version.to_string(req.buffer) == 'HTTP/1.1'
|
|
}
|
|
|
|
fn test_parse_http1_request_line_invalid_request() {
|
|
buffer := 'INVALID REQUEST LINE'.bytes()
|
|
mut req := HttpRequest{
|
|
buffer: buffer
|
|
}
|
|
|
|
mut has_error := false
|
|
parse_http1_request_line(mut req) or {
|
|
has_error = true
|
|
assert err.msg() == 'Invalid HTTP request line: Missing CR'
|
|
}
|
|
assert has_error, 'Expected error for invalid request line'
|
|
}
|
|
|
|
fn test_decode_http_request_valid_request() {
|
|
buffer := 'POST /api/resource HTTP/1.0\r\n'.bytes()
|
|
req := decode_http_request(buffer) or { panic(err) }
|
|
|
|
assert req.method.to_string(req.buffer) == 'POST'
|
|
assert req.path.to_string(req.buffer) == '/api/resource'
|
|
assert req.version.to_string(req.buffer) == 'HTTP/1.0'
|
|
}
|
|
|
|
fn test_decode_http_request_invalid_request() {
|
|
buffer := 'INVALID REQUEST LINE'.bytes()
|
|
|
|
mut has_error := false
|
|
decode_http_request(buffer) or {
|
|
has_error = true
|
|
assert err.msg() == 'Invalid HTTP request line: Missing CR'
|
|
}
|
|
assert has_error, 'Expected error for invalid request'
|
|
}
|
|
|
|
fn test_decode_http_request_with_headers_and_body() {
|
|
raw := 'POST /submit HTTP/1.1\r\n' + 'Host: localhost\r\n' +
|
|
'Content-Type: application/json\r\n' + 'Content-Length: 18\r\n' + '\r\n' +
|
|
'{"status": "ok"}'
|
|
|
|
buffer := raw.bytes()
|
|
req := decode_http_request(buffer) or { panic(err) }
|
|
|
|
assert req.method.to_string(req.buffer) == 'POST'
|
|
assert req.path.to_string(req.buffer) == '/submit'
|
|
|
|
// Verify Header Fields block
|
|
// Should contain everything between the first \r\n and the \r\n\r\n
|
|
header_str := req.header_fields.to_string(req.buffer)
|
|
assert header_str == 'Host: localhost\r\nContent-Type: application/json\r\nContent-Length: 18'
|
|
|
|
// Verify Body
|
|
assert req.body.to_string(req.buffer) == '{"status": "ok"}'
|
|
}
|
|
|
|
fn test_decode_http_request_no_body() {
|
|
// A GET request usually ends with \r\n\r\n and no body
|
|
buffer := 'GET /index.html HTTP/1.1\r\nUser-Agent: V\r\n\r\n'.bytes()
|
|
req := decode_http_request(buffer) or { panic(err) }
|
|
|
|
assert req.header_fields.to_string(req.buffer) == 'User-Agent: V'
|
|
assert req.body.len == 0
|
|
}
|
|
|
|
fn test_decode_http_request_malformed_no_double_crlf() {
|
|
// Request that never finishes headers
|
|
buffer := 'GET / HTTP/1.1\r\nHost: example.com\r\n'.bytes()
|
|
req := decode_http_request(buffer) or { panic(err) }
|
|
|
|
// Based on our implementation, if no \r\n\r\n is found,
|
|
// body should be empty and headers go to the end.
|
|
assert req.body.len == 0
|
|
assert req.header_fields.to_string(req.buffer) == 'Host: example.com'
|
|
}
|
|
|
|
fn test_has_complete_body_without_body() {
|
|
buffer := 'GET / HTTP/1.1\r\nHost: example.com\r\n\r\n'.bytes()
|
|
assert has_complete_body(buffer.data, buffer.len)
|
|
}
|
|
|
|
fn test_has_complete_body_with_incomplete_content_length() {
|
|
buffer := 'POST /upload HTTP/1.1\r\nHost: example.com\r\nContent-Length: 5\r\n\r\n123'.bytes()
|
|
assert !has_complete_body(buffer.data, buffer.len)
|
|
}
|
|
|
|
fn test_has_complete_body_with_complete_content_length() {
|
|
buffer := 'POST /upload HTTP/1.1\r\nHost: example.com\r\nContent-Length: 5\r\n\r\n12345'.bytes()
|
|
assert has_complete_body(buffer.data, buffer.len)
|
|
}
|
|
|
|
fn test_has_complete_body_with_incomplete_chunked_body() {
|
|
buffer :=
|
|
'POST /upload HTTP/1.1\r\nHost: example.com\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n'.bytes()
|
|
assert !has_complete_body(buffer.data, buffer.len)
|
|
}
|
|
|
|
fn test_has_complete_body_with_complete_chunked_body() {
|
|
buffer :=
|
|
'POST /upload HTTP/1.1\r\nHost: example.com\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n0\r\n\r\n'.bytes()
|
|
assert has_complete_body(buffer.data, buffer.len)
|
|
}
|
|
|
|
fn test_has_complete_body_with_incomplete_chunk_data_containing_terminator_bytes() {
|
|
buffer :=
|
|
'POST /upload HTTP/1.1\r\nHost: example.com\r\nTransfer-Encoding: chunked\r\n\r\n20\r\nabc\r\n0\r\n\r\n'.bytes()
|
|
assert !has_complete_body(buffer.data, buffer.len)
|
|
}
|
|
|
|
fn test_has_complete_body_with_complete_chunk_data_containing_terminator_bytes() {
|
|
buffer :=
|
|
'POST /upload HTTP/1.1\r\nHost: example.com\r\nTransfer-Encoding: chunked\r\n\r\nd\r\nabc\r\n0\r\n\r\ndef\r\n0\r\n\r\n'.bytes()
|
|
assert has_complete_body(buffer.data, buffer.len)
|
|
}
|