mod common;
use hyper::Method;
use mini_static::Server;
use std::fs;
use tempfile::TempDir;
const REJECTED_METHODS: [Method; 7] = [
Method::DELETE,
Method::POST,
Method::PUT,
Method::PATCH,
Method::OPTIONS,
Method::TRACE,
Method::CONNECT,
];
#[tokio::test]
async fn disallowed_methods_return_405_with_an_allow_header_and_nosniff() {
let root = TempDir::new().unwrap();
fs::write(root.path().join("file.txt"), b"secret content").unwrap();
let server = Server::new(root.path()).unwrap();
for method in REJECTED_METHODS {
let response = common::request(&server, &method, "/file.txt").await;
assert_eq!(response.status().as_u16(), 405, "{method} should be rejected");
assert_eq!(
response.headers().get("Allow").map(|v| v.to_str().unwrap()),
Some("GET, HEAD"),
"{method}'s 405 must advertise the methods that are allowed"
);
assert_eq!(
response
.headers()
.get("X-Content-Type-Options")
.map(|v| v.to_str().unwrap()),
Some("nosniff"),
"{method}'s 405 must still carry the nosniff header"
);
let body = common::body_bytes(response).await;
assert!(
!body.windows(6).any(|w| w == b"secret"),
"{method}'s 405 body must not contain the file's content"
);
}
}
#[tokio::test]
async fn get_and_head_succeed_for_an_existing_file() {
let root = TempDir::new().unwrap();
fs::write(root.path().join("file.txt"), b"content").unwrap();
let server = Server::new(root.path()).unwrap();
for method in [Method::GET, Method::HEAD] {
let response = common::request(&server, &method, "/file.txt").await;
assert_eq!(response.status().as_u16(), 200, "{method} on an existing file");
}
}
#[tokio::test]
async fn get_and_head_return_404_for_a_missing_file() {
let root = TempDir::new().unwrap();
let server = Server::new(root.path()).unwrap();
for method in [Method::GET, Method::HEAD] {
let response = common::request(&server, &method, "/missing.txt").await;
assert_eq!(response.status().as_u16(), 404, "{method} on a missing file");
}
}