mirror of https://github.com/fafhrd91/actix-web
Compare commits
2 Commits
4c05c87b11
...
03c65d93e5
Author | SHA1 | Date |
---|---|---|
|
03c65d93e5 | |
|
ec05381f6f |
|
@ -2,6 +2,12 @@
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Add `header::CLEAR_SITE_DATA` constant.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
- Update `brotli` dependency to `7`.
|
- Update `brotli` dependency to `7`.
|
||||||
- Minimum supported Rust version (MSRV) is now 1.75.
|
- Minimum supported Rust version (MSRV) is now 1.75.
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,14 @@ pub const CACHE_STATUS: HeaderName = HeaderName::from_static("cache-status");
|
||||||
// TODO(breaking): replace with http's version
|
// TODO(breaking): replace with http's version
|
||||||
pub const CDN_CACHE_CONTROL: HeaderName = HeaderName::from_static("cdn-cache-control");
|
pub const CDN_CACHE_CONTROL: HeaderName = HeaderName::from_static("cdn-cache-control");
|
||||||
|
|
||||||
|
/// Response header field that sends a signal to the user agent that it ought to remove all data of
|
||||||
|
/// a certain set of types.
|
||||||
|
///
|
||||||
|
/// See the [W3C Clear-Site-Data spec] for full semantics.
|
||||||
|
///
|
||||||
|
/// [W3C Clear-Site-Data spec]: https://www.w3.org/TR/clear-site-data/#header
|
||||||
|
pub const CLEAR_SITE_DATA: HeaderName = HeaderName::from_static("clear-site-data");
|
||||||
|
|
||||||
/// Response header that prevents a document from loading any cross-origin resources that don't
|
/// Response header that prevents a document from loading any cross-origin resources that don't
|
||||||
/// explicitly grant the document permission (using [CORP] or [CORS]).
|
/// explicitly grant the document permission (using [CORP] or [CORS]).
|
||||||
///
|
///
|
||||||
|
|
|
@ -42,9 +42,9 @@ pub use self::{
|
||||||
as_name::AsHeaderName,
|
as_name::AsHeaderName,
|
||||||
// re-export list is explicit so that any updates to `http` do not conflict with this set
|
// re-export list is explicit so that any updates to `http` do not conflict with this set
|
||||||
common::{
|
common::{
|
||||||
CACHE_STATUS, CDN_CACHE_CONTROL, CROSS_ORIGIN_EMBEDDER_POLICY, CROSS_ORIGIN_OPENER_POLICY,
|
CACHE_STATUS, CDN_CACHE_CONTROL, CLEAR_SITE_DATA, CROSS_ORIGIN_EMBEDDER_POLICY,
|
||||||
CROSS_ORIGIN_RESOURCE_POLICY, PERMISSIONS_POLICY, X_FORWARDED_FOR, X_FORWARDED_HOST,
|
CROSS_ORIGIN_OPENER_POLICY, CROSS_ORIGIN_RESOURCE_POLICY, PERMISSIONS_POLICY,
|
||||||
X_FORWARDED_PROTO,
|
X_FORWARDED_FOR, X_FORWARDED_HOST, X_FORWARDED_PROTO,
|
||||||
},
|
},
|
||||||
into_pair::TryIntoHeaderPair,
|
into_pair::TryIntoHeaderPair,
|
||||||
into_value::TryIntoHeaderValue,
|
into_value::TryIntoHeaderValue,
|
||||||
|
|
|
@ -163,6 +163,7 @@ serde = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde_urlencoded = "0.7"
|
serde_urlencoded = "0.7"
|
||||||
smallvec = "1.6.1"
|
smallvec = "1.6.1"
|
||||||
|
tracing = "0.1.30"
|
||||||
socket2 = "0.5"
|
socket2 = "0.5"
|
||||||
time = { version = "0.3", default-features = false, features = ["formatting"] }
|
time = { version = "0.3", default-features = false, features = ["formatting"] }
|
||||||
url = "2.1"
|
url = "2.1"
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
//! Shows a few of ways to use the `from_fn` middleware.
|
||||||
|
|
||||||
|
use std::{collections::HashMap, io, rc::Rc, time::Duration};
|
||||||
|
|
||||||
|
use actix_web::{
|
||||||
|
body::MessageBody,
|
||||||
|
dev::{Service, ServiceRequest, ServiceResponse, Transform},
|
||||||
|
http::header::{self, HeaderValue, Range},
|
||||||
|
middleware::{from_fn, Logger, Next},
|
||||||
|
web::{self, Header, Query},
|
||||||
|
App, Error, HttpResponse, HttpServer,
|
||||||
|
};
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
|
async fn noop<B>(req: ServiceRequest, next: Next<B>) -> Result<ServiceResponse<B>, Error> {
|
||||||
|
next.call(req).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn print_range_header<B>(
|
||||||
|
range_header: Option<Header<Range>>,
|
||||||
|
req: ServiceRequest,
|
||||||
|
next: Next<B>,
|
||||||
|
) -> Result<ServiceResponse<B>, Error> {
|
||||||
|
if let Some(Header(range)) = range_header {
|
||||||
|
println!("Range: {range}");
|
||||||
|
} else {
|
||||||
|
println!("No Range header");
|
||||||
|
}
|
||||||
|
|
||||||
|
next.call(req).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn mutate_body_type(
|
||||||
|
req: ServiceRequest,
|
||||||
|
next: Next<impl MessageBody + 'static>,
|
||||||
|
) -> Result<ServiceResponse<impl MessageBody>, Error> {
|
||||||
|
let res = next.call(req).await?;
|
||||||
|
Ok(res.map_into_left_body::<()>())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn mutate_body_type_with_extractors(
|
||||||
|
string_body: String,
|
||||||
|
query: Query<HashMap<String, String>>,
|
||||||
|
req: ServiceRequest,
|
||||||
|
next: Next<impl MessageBody + 'static>,
|
||||||
|
) -> Result<ServiceResponse<impl MessageBody>, Error> {
|
||||||
|
println!("body is: {string_body}");
|
||||||
|
println!("query string: {query:?}");
|
||||||
|
|
||||||
|
let res = next.call(req).await?;
|
||||||
|
|
||||||
|
Ok(res.map_body(move |_, _| string_body))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn timeout_10secs(
|
||||||
|
req: ServiceRequest,
|
||||||
|
next: Next<impl MessageBody + 'static>,
|
||||||
|
) -> Result<ServiceResponse<impl MessageBody>, Error> {
|
||||||
|
match tokio::time::timeout(Duration::from_secs(10), next.call(req)).await {
|
||||||
|
Ok(res) => res,
|
||||||
|
Err(_err) => Err(actix_web::error::ErrorRequestTimeout("")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MyMw(bool);
|
||||||
|
|
||||||
|
impl MyMw {
|
||||||
|
async fn mw_cb(
|
||||||
|
&self,
|
||||||
|
req: ServiceRequest,
|
||||||
|
next: Next<impl MessageBody + 'static>,
|
||||||
|
) -> Result<ServiceResponse<impl MessageBody>, Error> {
|
||||||
|
let mut res = match self.0 {
|
||||||
|
true => req.into_response("short-circuited").map_into_right_body(),
|
||||||
|
false => next.call(req).await?.map_into_left_body(),
|
||||||
|
};
|
||||||
|
|
||||||
|
res.headers_mut()
|
||||||
|
.insert(header::WARNING, HeaderValue::from_static("42"));
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_middleware<S, B>(
|
||||||
|
self,
|
||||||
|
) -> impl Transform<
|
||||||
|
S,
|
||||||
|
ServiceRequest,
|
||||||
|
Response = ServiceResponse<impl MessageBody>,
|
||||||
|
Error = Error,
|
||||||
|
InitError = (),
|
||||||
|
>
|
||||||
|
where
|
||||||
|
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
|
||||||
|
B: MessageBody + 'static,
|
||||||
|
{
|
||||||
|
let this = Rc::new(self);
|
||||||
|
from_fn(move |req, next| {
|
||||||
|
let this = Rc::clone(&this);
|
||||||
|
async move { Self::mw_cb(&this, req, next).await }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_web::main]
|
||||||
|
async fn main() -> io::Result<()> {
|
||||||
|
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
||||||
|
|
||||||
|
let bind = ("127.0.0.1", 8080);
|
||||||
|
info!("staring server at http://{}:{}", &bind.0, &bind.1);
|
||||||
|
|
||||||
|
HttpServer::new(|| {
|
||||||
|
App::new()
|
||||||
|
.wrap(from_fn(noop))
|
||||||
|
.wrap(from_fn(print_range_header))
|
||||||
|
.wrap(from_fn(mutate_body_type))
|
||||||
|
.wrap(from_fn(mutate_body_type_with_extractors))
|
||||||
|
.wrap(from_fn(timeout_10secs))
|
||||||
|
// switch bool to true to observe early response
|
||||||
|
.wrap(MyMw(false).into_middleware())
|
||||||
|
.wrap(Logger::default())
|
||||||
|
.default_service(web::to(HttpResponse::Ok))
|
||||||
|
})
|
||||||
|
.workers(1)
|
||||||
|
.bind(bind)?
|
||||||
|
.run()
|
||||||
|
.await
|
||||||
|
}
|
3
justfile
3
justfile
|
@ -36,6 +36,9 @@ check-min:
|
||||||
check-default:
|
check-default:
|
||||||
cargo hack --workspace check
|
cargo hack --workspace check
|
||||||
|
|
||||||
|
# Run Clippy over workspace.
|
||||||
|
check toolchain="": && (clippy toolchain)
|
||||||
|
|
||||||
# Run Clippy over workspace.
|
# Run Clippy over workspace.
|
||||||
clippy toolchain="":
|
clippy toolchain="":
|
||||||
cargo {{ toolchain }} clippy --workspace --all-targets {{ all_crate_features }}
|
cargo {{ toolchain }} clippy --workspace --all-targets {{ all_crate_features }}
|
||||||
|
|
Loading…
Reference in New Issue