2021-08-07 17:09:45 +02:00
|
|
|
#![allow(clippy::blacklisted_name)]
|
|
|
|
|
|
2021-08-21 15:01:30 +02:00
|
|
|
use crate::BoxError;
|
2021-07-22 13:23:50 +02:00
|
|
|
use crate::{
|
2021-09-19 11:38:34 +02:00
|
|
|
extract::{self, Path},
|
2021-08-18 00:04:15 +02:00
|
|
|
handler::{any, delete, get, on, patch, post, Handler},
|
2021-08-19 21:16:44 +02:00
|
|
|
response::IntoResponse,
|
2021-08-19 21:24:32 +02:00
|
|
|
routing::MethodFilter,
|
2021-08-19 22:37:48 +02:00
|
|
|
service, Router,
|
2021-07-22 13:23:50 +02:00
|
|
|
};
|
2021-06-09 08:14:20 +02:00
|
|
|
use bytes::Bytes;
|
2021-08-15 20:27:13 +02:00
|
|
|
use http::{
|
|
|
|
|
header::{HeaderMap, AUTHORIZATION},
|
|
|
|
|
Request, Response, StatusCode, Uri,
|
|
|
|
|
};
|
2021-09-19 11:38:34 +02:00
|
|
|
use hyper::Body;
|
2021-05-31 12:22:16 +02:00
|
|
|
use serde::Deserialize;
|
|
|
|
|
use serde_json::json;
|
2021-08-21 15:18:05 +02:00
|
|
|
use std::future::Ready;
|
2021-06-01 17:17:10 +02:00
|
|
|
use std::{
|
2021-08-06 16:17:57 +08:00
|
|
|
collections::HashMap,
|
2021-07-22 15:00:33 +02:00
|
|
|
convert::Infallible,
|
2021-08-21 15:18:05 +02:00
|
|
|
future::ready,
|
2021-07-31 21:05:53 +02:00
|
|
|
task::{Context, Poll},
|
2021-06-01 17:17:10 +02:00
|
|
|
time::Duration,
|
|
|
|
|
};
|
2021-09-19 11:38:34 +02:00
|
|
|
use tower::service_fn;
|
2021-08-21 15:01:30 +02:00
|
|
|
use tower_service::Service;
|
2021-05-31 12:22:16 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
pub(crate) use helpers::*;
|
|
|
|
|
|
2021-08-15 20:27:13 +02:00
|
|
|
mod get_to_head;
|
2021-08-08 14:30:51 +02:00
|
|
|
mod handle_error;
|
2021-09-19 11:38:34 +02:00
|
|
|
mod helpers;
|
2021-08-02 22:40:33 +02:00
|
|
|
mod nest;
|
2021-08-07 17:09:45 +02:00
|
|
|
mod or;
|
2021-08-02 22:40:33 +02:00
|
|
|
|
2021-05-31 12:22:16 +02:00
|
|
|
#[tokio::test]
|
|
|
|
|
async fn hello_world() {
|
2021-06-04 01:00:48 +02:00
|
|
|
async fn root(_: Request<Body>) -> &'static str {
|
|
|
|
|
"Hello, World!"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn foo(_: Request<Body>) -> &'static str {
|
|
|
|
|
"foo"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn users_create(_: Request<Body>) -> &'static str {
|
|
|
|
|
"users#create"
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-19 22:37:48 +02:00
|
|
|
let app = Router::new()
|
|
|
|
|
.route("/", get(root).post(foo))
|
|
|
|
|
.route("/users", post(users_create));
|
2021-05-31 12:22:16 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let client = TestClient::new(app);
|
2021-05-31 12:22:16 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/").send().await;
|
|
|
|
|
let body = res.text().await;
|
2021-05-31 12:22:16 +02:00
|
|
|
assert_eq!(body, "Hello, World!");
|
2021-06-04 01:00:48 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.post("/").send().await;
|
|
|
|
|
let body = res.text().await;
|
2021-06-04 01:00:48 +02:00
|
|
|
assert_eq!(body, "foo");
|
|
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.post("/users").send().await;
|
|
|
|
|
let body = res.text().await;
|
2021-06-04 01:00:48 +02:00
|
|
|
assert_eq!(body, "users#create");
|
2021-05-31 12:22:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn consume_body() {
|
2021-08-19 22:37:48 +02:00
|
|
|
let app = Router::new().route("/", get(|body: String| async { body }));
|
2021-05-31 12:22:16 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let client = TestClient::new(app);
|
|
|
|
|
let res = client.get("/").body("foo").send().await;
|
|
|
|
|
let body = res.text().await;
|
2021-05-31 12:22:16 +02:00
|
|
|
|
|
|
|
|
assert_eq!(body, "foo");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn deserialize_body() {
|
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
|
|
|
struct Input {
|
|
|
|
|
foo: String,
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-19 22:37:48 +02:00
|
|
|
let app = Router::new().route(
|
2021-06-04 01:00:48 +02:00
|
|
|
"/",
|
2021-06-09 09:03:09 +02:00
|
|
|
post(|input: extract::Json<Input>| async { input.0.foo }),
|
2021-06-04 01:00:48 +02:00
|
|
|
);
|
2021-05-31 12:22:16 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let client = TestClient::new(app);
|
|
|
|
|
let res = client.post("/").json(&json!({ "foo": "bar" })).send().await;
|
|
|
|
|
let body = res.text().await;
|
2021-05-31 12:22:16 +02:00
|
|
|
|
|
|
|
|
assert_eq!(body, "bar");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn consume_body_to_json_requires_json_content_type() {
|
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
|
|
|
struct Input {
|
|
|
|
|
foo: String,
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-19 22:37:48 +02:00
|
|
|
let app = Router::new().route(
|
2021-06-04 01:00:48 +02:00
|
|
|
"/",
|
2021-07-22 13:23:50 +02:00
|
|
|
post(|input: extract::Json<Input>| async { input.0.foo }),
|
2021-06-04 01:00:48 +02:00
|
|
|
);
|
2021-05-31 12:22:16 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let client = TestClient::new(app);
|
|
|
|
|
let res = client.post("/").body(r#"{ "foo": "bar" }"#).send().await;
|
2021-05-31 12:22:16 +02:00
|
|
|
|
2021-05-31 22:54:21 +02:00
|
|
|
let status = res.status();
|
2021-09-19 11:38:34 +02:00
|
|
|
dbg!(res.text().await);
|
2021-05-31 22:54:21 +02:00
|
|
|
|
|
|
|
|
assert_eq!(status, StatusCode::BAD_REQUEST);
|
2021-05-31 12:22:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn body_with_length_limit() {
|
|
|
|
|
use std::iter::repeat;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
|
|
|
struct Input {
|
|
|
|
|
foo: String,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const LIMIT: u64 = 8;
|
|
|
|
|
|
2021-08-19 22:37:48 +02:00
|
|
|
let app = Router::new().route(
|
2021-06-04 01:00:48 +02:00
|
|
|
"/",
|
2021-06-09 09:03:09 +02:00
|
|
|
post(|_body: extract::ContentLengthLimit<Bytes, LIMIT>| async {}),
|
2021-06-04 01:00:48 +02:00
|
|
|
);
|
2021-05-31 12:22:16 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let client = TestClient::new(app);
|
2021-05-31 12:22:16 +02:00
|
|
|
let res = client
|
2021-09-19 11:38:34 +02:00
|
|
|
.post("/")
|
2021-05-31 12:22:16 +02:00
|
|
|
.body(repeat(0_u8).take((LIMIT - 1) as usize).collect::<Vec<_>>())
|
|
|
|
|
.send()
|
2021-09-19 11:38:34 +02:00
|
|
|
.await;
|
2021-05-31 12:22:16 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
|
|
|
|
|
|
let res = client
|
2021-09-19 11:38:34 +02:00
|
|
|
.post("/")
|
2021-05-31 12:22:16 +02:00
|
|
|
.body(repeat(0_u8).take(LIMIT as usize).collect::<Vec<_>>())
|
|
|
|
|
.send()
|
2021-09-19 11:38:34 +02:00
|
|
|
.await;
|
2021-05-31 12:22:16 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
|
|
|
|
|
|
let res = client
|
2021-09-19 11:38:34 +02:00
|
|
|
.post("/")
|
2021-05-31 12:22:16 +02:00
|
|
|
.body(repeat(0_u8).take((LIMIT + 1) as usize).collect::<Vec<_>>())
|
|
|
|
|
.send()
|
2021-09-19 11:38:34 +02:00
|
|
|
.await;
|
2021-05-31 12:22:16 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::PAYLOAD_TOO_LARGE);
|
|
|
|
|
|
|
|
|
|
let res = client
|
2021-09-19 11:38:34 +02:00
|
|
|
.post("/")
|
2021-05-31 12:22:16 +02:00
|
|
|
.body(reqwest::Body::wrap_stream(futures_util::stream::iter(
|
|
|
|
|
vec![Ok::<_, std::io::Error>(bytes::Bytes::new())],
|
|
|
|
|
)))
|
|
|
|
|
.send()
|
2021-09-19 11:38:34 +02:00
|
|
|
.await;
|
2021-05-31 12:22:16 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::LENGTH_REQUIRED);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-31 14:04:05 +02:00
|
|
|
#[tokio::test]
|
|
|
|
|
async fn routing() {
|
2021-08-19 22:37:48 +02:00
|
|
|
let app = Router::new()
|
|
|
|
|
.route(
|
|
|
|
|
"/users",
|
|
|
|
|
get(|_: Request<Body>| async { "users#index" })
|
|
|
|
|
.post(|_: Request<Body>| async { "users#create" }),
|
|
|
|
|
)
|
|
|
|
|
.route("/users/:id", get(|_: Request<Body>| async { "users#show" }))
|
|
|
|
|
.route(
|
|
|
|
|
"/users/:id/action",
|
|
|
|
|
get(|_: Request<Body>| async { "users#action" }),
|
|
|
|
|
);
|
2021-05-31 14:04:05 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let client = TestClient::new(app);
|
2021-05-31 14:04:05 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/").send().await;
|
2021-05-31 14:04:05 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
|
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/users").send().await;
|
2021-05-31 14:04:05 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
2021-09-19 11:38:34 +02:00
|
|
|
assert_eq!(res.text().await, "users#index");
|
2021-05-31 14:04:05 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.post("/users").send().await;
|
2021-05-31 14:04:05 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
2021-09-19 11:38:34 +02:00
|
|
|
assert_eq!(res.text().await, "users#create");
|
2021-05-31 14:04:05 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/users/1").send().await;
|
2021-05-31 14:04:05 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
2021-09-19 11:38:34 +02:00
|
|
|
assert_eq!(res.text().await, "users#show");
|
2021-05-31 14:04:05 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/users/1/action").send().await;
|
2021-05-31 14:04:05 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
2021-09-19 11:38:34 +02:00
|
|
|
assert_eq!(res.text().await, "users#action");
|
2021-05-31 14:04:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn extracting_url_params() {
|
2021-08-19 22:37:48 +02:00
|
|
|
let app = Router::new().route(
|
2021-06-04 01:00:48 +02:00
|
|
|
"/users/:id",
|
2021-09-19 11:38:34 +02:00
|
|
|
get(|Path(id): Path<i32>| async move {
|
2021-06-09 09:03:09 +02:00
|
|
|
assert_eq!(id, 42);
|
|
|
|
|
})
|
2021-09-19 11:38:34 +02:00
|
|
|
.post(|Path(params_map): Path<HashMap<String, i32>>| async move {
|
|
|
|
|
assert_eq!(params_map.get("id").unwrap(), &1337);
|
|
|
|
|
}),
|
2021-06-04 01:00:48 +02:00
|
|
|
);
|
2021-05-31 12:22:16 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let client = TestClient::new(app);
|
2021-05-31 14:04:05 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/users/42").send().await;
|
2021-05-31 14:04:05 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.post("/users/1337").send().await;
|
2021-05-31 14:04:05 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
|
}
|
2021-05-31 12:22:16 +02:00
|
|
|
|
2021-06-13 13:06:33 +02:00
|
|
|
#[tokio::test]
|
|
|
|
|
async fn extracting_url_params_multiple_times() {
|
2021-08-19 22:37:48 +02:00
|
|
|
let app = Router::new().route(
|
2021-06-13 13:06:33 +02:00
|
|
|
"/users/:id",
|
2021-08-06 16:17:57 +08:00
|
|
|
get(|_: extract::Path<i32>, _: extract::Path<String>| async {}),
|
2021-06-13 13:06:33 +02:00
|
|
|
);
|
|
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let client = TestClient::new(app);
|
2021-06-13 13:06:33 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/users/42").send().await;
|
2021-06-13 13:06:33 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-31 16:28:26 +02:00
|
|
|
#[tokio::test]
|
|
|
|
|
async fn boxing() {
|
2021-08-19 22:37:48 +02:00
|
|
|
let app = Router::new()
|
|
|
|
|
.route(
|
|
|
|
|
"/",
|
|
|
|
|
on(MethodFilter::GET, |_: Request<Body>| async {
|
|
|
|
|
"hi from GET"
|
|
|
|
|
})
|
|
|
|
|
.on(MethodFilter::POST, |_: Request<Body>| async {
|
|
|
|
|
"hi from POST"
|
|
|
|
|
}),
|
|
|
|
|
)
|
|
|
|
|
.layer(tower_http::compression::CompressionLayer::new())
|
|
|
|
|
.boxed();
|
2021-05-31 16:28:26 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let client = TestClient::new(app);
|
2021-05-31 16:28:26 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/").send().await;
|
2021-05-31 16:28:26 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
2021-09-19 11:38:34 +02:00
|
|
|
assert_eq!(res.text().await, "hi from GET");
|
2021-05-31 16:28:26 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.post("/").send().await;
|
2021-05-31 16:28:26 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
2021-09-19 11:38:34 +02:00
|
|
|
assert_eq!(res.text().await, "hi from POST");
|
2021-05-31 16:28:26 +02:00
|
|
|
}
|
2021-05-31 12:22:16 +02:00
|
|
|
|
2021-06-06 15:19:54 +02:00
|
|
|
#[tokio::test]
|
|
|
|
|
async fn routing_between_services() {
|
|
|
|
|
use std::convert::Infallible;
|
|
|
|
|
use tower::service_fn;
|
|
|
|
|
|
|
|
|
|
async fn handle(_: Request<Body>) -> &'static str {
|
|
|
|
|
"handler"
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-19 22:37:48 +02:00
|
|
|
let app = Router::new()
|
|
|
|
|
.route(
|
|
|
|
|
"/one",
|
|
|
|
|
service::get(service_fn(|_: Request<Body>| async {
|
|
|
|
|
Ok::<_, Infallible>(Response::new(Body::from("one get")))
|
|
|
|
|
}))
|
|
|
|
|
.post(service_fn(|_: Request<Body>| async {
|
|
|
|
|
Ok::<_, Infallible>(Response::new(Body::from("one post")))
|
|
|
|
|
}))
|
|
|
|
|
.on(
|
|
|
|
|
MethodFilter::PUT,
|
|
|
|
|
service_fn(|_: Request<Body>| async {
|
|
|
|
|
Ok::<_, Infallible>(Response::new(Body::from("one put")))
|
|
|
|
|
}),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
.route("/two", service::on(MethodFilter::GET, any(handle)));
|
2021-06-06 15:19:54 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let client = TestClient::new(app);
|
2021-06-06 15:19:54 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/one").send().await;
|
2021-06-06 15:19:54 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
2021-09-19 11:38:34 +02:00
|
|
|
assert_eq!(res.text().await, "one get");
|
2021-06-06 15:19:54 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.post("/one").send().await;
|
2021-06-06 15:19:54 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
2021-09-19 11:38:34 +02:00
|
|
|
assert_eq!(res.text().await, "one post");
|
2021-06-06 15:19:54 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.put("/one").send().await;
|
2021-06-06 15:19:54 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
2021-09-19 11:38:34 +02:00
|
|
|
assert_eq!(res.text().await, "one put");
|
2021-06-06 15:19:54 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/two").send().await;
|
2021-06-06 15:19:54 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
2021-09-19 11:38:34 +02:00
|
|
|
assert_eq!(res.text().await, "handler");
|
2021-06-06 15:19:54 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-01 11:23:56 +02:00
|
|
|
#[tokio::test]
|
|
|
|
|
async fn middleware_on_single_route() {
|
|
|
|
|
use tower::ServiceBuilder;
|
|
|
|
|
use tower_http::{compression::CompressionLayer, trace::TraceLayer};
|
|
|
|
|
|
|
|
|
|
async fn handle(_: Request<Body>) -> &'static str {
|
|
|
|
|
"Hello, World!"
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-19 22:37:48 +02:00
|
|
|
let app = Router::new().route(
|
2021-06-04 01:00:48 +02:00
|
|
|
"/",
|
|
|
|
|
get(handle.layer(
|
|
|
|
|
ServiceBuilder::new()
|
|
|
|
|
.layer(TraceLayer::new_for_http())
|
|
|
|
|
.layer(CompressionLayer::new())
|
|
|
|
|
.into_inner(),
|
|
|
|
|
)),
|
|
|
|
|
);
|
2021-06-01 11:23:56 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let client = TestClient::new(app);
|
2021-06-01 11:23:56 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/").send().await;
|
|
|
|
|
let body = res.text().await;
|
2021-06-01 11:23:56 +02:00
|
|
|
|
|
|
|
|
assert_eq!(body, "Hello, World!");
|
|
|
|
|
}
|
2021-06-01 08:32:58 +02:00
|
|
|
|
2021-07-06 09:40:25 +02:00
|
|
|
#[tokio::test]
|
|
|
|
|
async fn service_in_bottom() {
|
2021-09-19 11:38:34 +02:00
|
|
|
async fn handler(_req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
|
2021-07-06 09:40:25 +02:00
|
|
|
Ok(Response::new(hyper::Body::empty()))
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-19 22:37:48 +02:00
|
|
|
let app = Router::new().route("/", service::get(service_fn(handler)));
|
2021-07-06 09:40:25 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
TestClient::new(app);
|
2021-07-06 09:40:25 +02:00
|
|
|
}
|
|
|
|
|
|
2021-07-09 23:38:59 +02:00
|
|
|
#[tokio::test]
|
|
|
|
|
async fn test_extractor_middleware() {
|
|
|
|
|
struct RequireAuth;
|
|
|
|
|
|
|
|
|
|
#[async_trait::async_trait]
|
|
|
|
|
impl<B> extract::FromRequest<B> for RequireAuth
|
|
|
|
|
where
|
|
|
|
|
B: Send,
|
|
|
|
|
{
|
|
|
|
|
type Rejection = StatusCode;
|
|
|
|
|
|
2021-08-18 00:04:15 +02:00
|
|
|
async fn from_request(req: &mut extract::RequestParts<B>) -> Result<Self, Self::Rejection> {
|
2021-07-09 23:38:59 +02:00
|
|
|
if let Some(auth) = req
|
|
|
|
|
.headers()
|
2021-07-22 13:23:50 +02:00
|
|
|
.expect("headers already extracted")
|
2021-07-09 23:38:59 +02:00
|
|
|
.get("authorization")
|
|
|
|
|
.and_then(|v| v.to_str().ok())
|
|
|
|
|
{
|
|
|
|
|
if auth == "secret" {
|
|
|
|
|
return Ok(Self);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Err(StatusCode::UNAUTHORIZED)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn handler() {}
|
|
|
|
|
|
2021-08-19 22:37:48 +02:00
|
|
|
let app = Router::new().route(
|
2021-07-09 23:38:59 +02:00
|
|
|
"/",
|
|
|
|
|
get(handler.layer(extract::extractor_middleware::<RequireAuth>())),
|
|
|
|
|
);
|
|
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let client = TestClient::new(app);
|
2021-07-09 23:38:59 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/").send().await;
|
2021-07-09 23:38:59 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
|
|
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/").header(AUTHORIZATION, "secret").send().await;
|
2021-07-09 23:38:59 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-31 21:05:53 +02:00
|
|
|
#[tokio::test]
|
|
|
|
|
async fn wrong_method_handler() {
|
2021-08-19 22:37:48 +02:00
|
|
|
let app = Router::new()
|
|
|
|
|
.route("/", get(|| async {}).post(|| async {}))
|
|
|
|
|
.route("/foo", patch(|| async {}));
|
2021-07-31 21:05:53 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let client = TestClient::new(app);
|
2021-07-31 21:05:53 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.patch("/").send().await;
|
2021-07-31 21:05:53 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED);
|
|
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.patch("/foo").send().await;
|
2021-07-31 21:05:53 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.post("/foo").send().await;
|
2021-07-31 21:05:53 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED);
|
|
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/bar").send().await;
|
2021-07-31 21:05:53 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn wrong_method_service() {
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
|
struct Svc;
|
|
|
|
|
|
|
|
|
|
impl<R> Service<R> for Svc {
|
|
|
|
|
type Response = Response<http_body::Empty<Bytes>>;
|
|
|
|
|
type Error = Infallible;
|
|
|
|
|
type Future = Ready<Result<Self::Response, Self::Error>>;
|
|
|
|
|
|
|
|
|
|
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
|
|
|
Poll::Ready(Ok(()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn call(&mut self, _req: R) -> Self::Future {
|
2021-08-21 15:18:05 +02:00
|
|
|
ready(Ok(Response::new(http_body::Empty::new())))
|
2021-07-31 21:05:53 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-19 22:37:48 +02:00
|
|
|
let app = Router::new()
|
|
|
|
|
.route("/", service::get(Svc).post(Svc))
|
|
|
|
|
.route("/foo", service::patch(Svc));
|
2021-07-31 21:05:53 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let client = TestClient::new(app);
|
2021-07-31 21:05:53 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.patch("/").send().await;
|
2021-07-31 21:05:53 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED);
|
|
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.patch("/foo").send().await;
|
2021-07-31 21:05:53 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.post("/foo").send().await;
|
2021-07-31 21:05:53 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED);
|
|
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/bar").send().await;
|
2021-07-31 21:05:53 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-09 15:29:31 +02:00
|
|
|
#[tokio::test]
|
|
|
|
|
async fn multiple_methods_for_one_handler() {
|
|
|
|
|
async fn root(_: Request<Body>) -> &'static str {
|
|
|
|
|
"Hello, World!"
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-19 22:37:48 +02:00
|
|
|
let app = Router::new().route("/", on(MethodFilter::GET | MethodFilter::POST, root));
|
2021-08-09 15:29:31 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let client = TestClient::new(app);
|
2021-08-09 15:29:31 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/").send().await;
|
2021-08-09 15:29:31 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.post("/").send().await;
|
2021-08-09 15:29:31 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-19 21:16:44 +02:00
|
|
|
#[tokio::test]
|
|
|
|
|
async fn handler_into_service() {
|
|
|
|
|
async fn handle(body: String) -> impl IntoResponse {
|
|
|
|
|
format!("you said: {}", body)
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let client = TestClient::new(handle.into_service());
|
2021-08-19 21:16:44 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.post("/").body("hi there!").send().await;
|
2021-08-19 21:16:44 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
2021-09-19 11:38:34 +02:00
|
|
|
assert_eq!(res.text().await, "you said: hi there!");
|
2021-08-19 21:16:44 +02:00
|
|
|
}
|
|
|
|
|
|
2021-08-21 01:00:12 +02:00
|
|
|
#[tokio::test]
|
|
|
|
|
async fn when_multiple_routes_match() {
|
|
|
|
|
let app = Router::new()
|
|
|
|
|
.route("/", post(|| async {}))
|
|
|
|
|
.route("/", get(|| async {}))
|
|
|
|
|
.route("/foo", get(|| async {}))
|
|
|
|
|
.nest("/foo", Router::new().route("/bar", get(|| async {})));
|
|
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let client = TestClient::new(app);
|
2021-08-21 01:00:12 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/").send().await;
|
2021-08-21 01:00:12 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.post("/").send().await;
|
2021-08-21 01:00:12 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/foo/bar").send().await;
|
2021-08-21 01:00:12 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/foo").send().await;
|
2021-08-24 20:27:06 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn captures_dont_match_empty_segments() {
|
|
|
|
|
let app = Router::new().route("/:key", get(|| async {}));
|
|
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let client = TestClient::new(app);
|
2021-08-24 20:27:06 +02:00
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/").send().await;
|
2021-08-24 20:27:06 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
|
|
|
|
|
2021-09-19 11:38:34 +02:00
|
|
|
let res = client.get("/foo").send().await;
|
2021-08-21 01:00:12 +02:00
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-22 11:33:38 +02:00
|
|
|
pub(crate) fn assert_send<T: Send>() {}
|
|
|
|
|
pub(crate) fn assert_sync<T: Sync>() {}
|
2021-08-22 14:41:51 +02:00
|
|
|
pub(crate) fn assert_unpin<T: Unpin>() {}
|
2021-08-26 20:59:55 +02:00
|
|
|
|
|
|
|
|
pub(crate) struct NotSendSync(*const ());
|