apsis-book/tests/http_request.rs

70 lines
2.2 KiB
Rust

//! Tests for the request parser.
//!
//! They live here rather than inside the module so that `src/` holds no test
//! code, as it does in `apsis-rs`. An integration test is a separate crate and
//! reaches only what the library makes public, so the few internal items the
//! tests need are opened through `apsis_book::testkit`.
use apsis_book::http::request::*;
use std::io::Cursor;
#[test]
fn parses_a_get_request() {
let raw = b"GET /health?verbose=1 HTTP/1.1\r\nHost: localhost\r\nX-Test: a\r\n\r\n";
let request = read_request(&mut Cursor::new(raw), Limits::default()).unwrap();
assert_eq!(request.method, Method::Get);
assert_eq!(request.path, "/health");
assert_eq!(request.query.as_deref(), Some("verbose=1"));
assert_eq!(request.header("x-test"), Some("a"));
assert_eq!(request.header("X-Test"), Some("a"));
assert_eq!(
request.query_pairs().get("verbose").map(String::as_str),
Some("1")
);
}
#[test]
fn parses_a_post_body() {
let raw = b"POST /api/tools/x HTTP/1.1\r\nContent-Length: 5\r\n\r\nhello";
let request = read_request(&mut Cursor::new(raw), Limits::default()).unwrap();
assert_eq!(request.method, Method::Post);
assert_eq!(request.body_text(), Some("hello"));
}
#[test]
fn rejects_malformed_input() {
let cases: &[&[u8]] = &[
b"GET\r\n\r\n",
b"GET / HTTP/2.0\r\n\r\n",
b"GET / HTTP/1.1\r\nbroken\r\n\r\n",
b"GET / HTTP/1.1\r\nContent-Length: nope\r\n\r\n",
];
for case in cases {
assert!(read_request(&mut Cursor::new(*case), Limits::default()).is_err());
}
}
#[test]
fn decodes_percent_escapes() {
let raw = b"GET /search?q=a%20b+%E2%82%AC HTTP/1.1\r\n\r\n";
let request = read_request(&mut Cursor::new(raw), Limits::default()).unwrap();
assert_eq!(
request.query_pairs().get("q").map(String::as_str),
Some("a b €")
);
}
#[test]
fn rejects_an_oversized_body() {
let raw = b"POST /x HTTP/1.1\r\nContent-Length: 100\r\n\r\n";
let limits = Limits {
max_body_bytes: 4,
..Limits::default()
};
assert!(matches!(
read_request(&mut Cursor::new(raw), limits),
Err(RequestError::TooLarge(_))
));
}