Merge branch 'master' into foldhash

This commit is contained in:
Rob Ede 2024-12-29 15:26:32 +00:00 committed by GitHub
commit ea2537cc03
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 254 additions and 75 deletions

View File

@ -49,7 +49,7 @@ jobs:
toolchain: ${{ matrix.version.version }} toolchain: ${{ matrix.version.version }}
- name: Install just, cargo-hack, cargo-nextest, cargo-ci-cache-clean - name: Install just, cargo-hack, cargo-nextest, cargo-ci-cache-clean
uses: taiki-e/install-action@v2.44.24 uses: taiki-e/install-action@v2.46.20
with: with:
tool: just,cargo-hack,cargo-nextest,cargo-ci-cache-clean tool: just,cargo-hack,cargo-nextest,cargo-ci-cache-clean
@ -83,7 +83,7 @@ jobs:
uses: actions-rust-lang/setup-rust-toolchain@v1.10.1 uses: actions-rust-lang/setup-rust-toolchain@v1.10.1
- name: Install just, cargo-hack - name: Install just, cargo-hack
uses: taiki-e/install-action@v2.44.24 uses: taiki-e/install-action@v2.46.20
with: with:
tool: just,cargo-hack tool: just,cargo-hack

View File

@ -64,7 +64,7 @@ jobs:
toolchain: ${{ matrix.version.version }} toolchain: ${{ matrix.version.version }}
- name: Install just, cargo-hack, cargo-nextest, cargo-ci-cache-clean - name: Install just, cargo-hack, cargo-nextest, cargo-ci-cache-clean
uses: taiki-e/install-action@v2.44.24 uses: taiki-e/install-action@v2.46.20
with: with:
tool: just,cargo-hack,cargo-nextest,cargo-ci-cache-clean tool: just,cargo-hack,cargo-nextest,cargo-ci-cache-clean
@ -113,7 +113,7 @@ jobs:
toolchain: nightly toolchain: nightly
- name: Install just - name: Install just
uses: taiki-e/install-action@v2.44.24 uses: taiki-e/install-action@v2.46.20
with: with:
tool: just tool: just

View File

@ -24,7 +24,7 @@ jobs:
components: llvm-tools components: llvm-tools
- name: Install just, cargo-llvm-cov, cargo-nextest - name: Install just, cargo-llvm-cov, cargo-nextest
uses: taiki-e/install-action@v2.44.24 uses: taiki-e/install-action@v2.46.20
with: with:
tool: just,cargo-llvm-cov,cargo-nextest tool: just,cargo-llvm-cov,cargo-nextest
@ -32,7 +32,7 @@ jobs:
run: just test-coverage-codecov run: just test-coverage-codecov
- name: Upload coverage to Codecov - name: Upload coverage to Codecov
uses: codecov/codecov-action@v4.6.0 uses: codecov/codecov-action@v5.1.2
with: with:
files: codecov.json files: codecov.json
fail_ci_if_error: true fail_ci_if_error: true

View File

@ -66,18 +66,18 @@ jobs:
run: cargo +nightly doc --no-deps --workspace --all-features run: cargo +nightly doc --no-deps --workspace --all-features
check-external-types: check-external-types:
if: false # disable until https://github.com/awslabs/cargo-check-external-types/pull/177 is marged if: false # rustdoc mismatch currently
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install Rust (nightly-2024-05-01) - name: Install Rust (${{ vars.RUST_VERSION_EXTERNAL_TYPES }})
uses: actions-rust-lang/setup-rust-toolchain@v1.10.1 uses: actions-rust-lang/setup-rust-toolchain@v1.10.1
with: with:
toolchain: nightly-2024-05-01 toolchain: ${{ vars.RUST_VERSION_EXTERNAL_TYPES }}
- name: Install just - name: Install just
uses: taiki-e/install-action@v2.44.24 uses: taiki-e/install-action@v2.46.20
with: with:
tool: just tool: just
@ -87,31 +87,4 @@ jobs:
tool: cargo-check-external-types tool: cargo-check-external-types
- name: check external types - name: check external types
run: just check-external-types-all +nightly-2024-05-01 run: just check-external-types-all +${{ vars.RUST_VERSION_EXTERNAL_TYPES }}
public-api-diff:
runs-on: ubuntu-latest
steps:
- name: Checkout main branch
uses: actions/checkout@v4
with:
ref: ${{ github.base_ref }}
- name: Checkout PR branch
uses: actions/checkout@v4
- name: Install Rust (nightly-2024-09-30)
uses: actions-rust-lang/setup-rust-toolchain@v1.10.1
with:
toolchain: nightly-2024-09-30
- name: Install cargo-public-api
uses: taiki-e/install-action@v2.44.24
with:
tool: cargo-public-api
- name: Generate API diff
run: |
for f in $(find -mindepth 2 -maxdepth 2 -name Cargo.toml); do
cargo public-api --manifest-path "$f" --simplified diff ${{ github.event.pull_request.base.sha }}..${{ github.sha }}
done

View File

@ -2,6 +2,13 @@
## Unreleased ## Unreleased
### Added
- Add `header::CLEAR_SITE_DATA` constant.
### Changed
- Update `brotli` dependency to `7`.
- Minimum supported Rust version (MSRV) is now 1.75. - Minimum supported Rust version (MSRV) is now 1.75.
## 3.9.0 ## 3.9.0

View File

@ -139,7 +139,7 @@ sha1 = { version = "0.10", optional = true }
actix-tls = { version = "3.4", default-features = false, optional = true } actix-tls = { version = "3.4", default-features = false, optional = true }
# compress-* # compress-*
brotli = { version = "6", optional = true } brotli = { version = "7", optional = true }
flate2 = { version = "1.0.13", optional = true } flate2 = { version = "1.0.13", optional = true }
zstd = { version = "0.13", optional = true } zstd = { version = "0.13", optional = true }

View File

@ -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]).
/// ///

View File

@ -837,7 +837,7 @@ impl<'a> Drain<'a> {
} }
} }
impl<'a> Iterator for Drain<'a> { impl Iterator for Drain<'_> {
type Item = (Option<HeaderName>, HeaderValue); type Item = (Option<HeaderName>, HeaderValue);
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {

View File

@ -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,

View File

@ -61,7 +61,7 @@ pub fn write_content_length<B: BufMut>(n: u64, buf: &mut B, camel_case: bool) {
/// perform a remaining length check before writing. /// perform a remaining length check before writing.
pub(crate) struct MutWriter<'a, B>(pub(crate) &'a mut B); pub(crate) struct MutWriter<'a, B>(pub(crate) &'a mut B);
impl<'a, B> io::Write for MutWriter<'a, B> impl<B> io::Write for MutWriter<'_, B>
where where
B: BufMut, B: BufMut,
{ {

View File

@ -103,7 +103,7 @@ pub trait HttpMessage: Sized {
} }
} }
impl<'a, T> HttpMessage for &'a mut T impl<T> HttpMessage for &mut T
where where
T: HttpMessage, T: HttpMessage,
{ {

View File

@ -19,7 +19,7 @@ impl ResourcePath for String {
} }
} }
impl<'a> ResourcePath for &'a str { impl ResourcePath for &str {
fn path(&self) -> &str { fn path(&self) -> &str {
self self
} }

View File

@ -136,7 +136,7 @@ async fn routes_overlapping_inaccessible_test(req: HttpRequest) -> impl Responde
} }
#[get("/custom_resource_name", name = "custom")] #[get("/custom_resource_name", name = "custom")]
async fn custom_resource_name_test<'a>(req: HttpRequest) -> impl Responder { async fn custom_resource_name_test(req: HttpRequest) -> impl Responder {
assert!(req.url_for_static("custom").is_ok()); assert!(req.url_for_static("custom").is_ok());
assert!(req.url_for_static("custom_resource_name_test").is_err()); assert!(req.url_for_static("custom_resource_name_test").is_err());
HttpResponse::Ok() HttpResponse::Ok()

View File

@ -2,8 +2,9 @@
## Unreleased ## Unreleased
- On Windows, an error is now returned from `HttpServer::bind()` (or TLS variants) when binding to a socket that's already in use.
- Update `brotli` dependency to `7`.
- Minimum supported Rust version (MSRV) is now 1.75. - Minimum supported Rust version (MSRV) is now 1.75.
- On Windows platforms, produce an error when invoking `HttpServer::bind` on a socket that's already in use. See [issue 2958](https://github.com/actix/actix-web/issues/2958).
## 4.9.0 ## 4.9.0

View File

@ -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"
@ -172,7 +173,7 @@ actix-files = "0.6"
actix-test = { version = "0.1", features = ["openssl", "rustls-0_23"] } actix-test = { version = "0.1", features = ["openssl", "rustls-0_23"] }
awc = { version = "3", features = ["openssl"] } awc = { version = "3", features = ["openssl"] }
brotli = "6" brotli = "7"
const-str = "0.5" const-str = "0.5"
core_affinity = "0.8" core_affinity = "0.8"
criterion = { version = "0.5", features = ["html_reports"] } criterion = { version = "0.5", features = ["html_reports"] }

View File

@ -14,7 +14,7 @@
[![Dependency Status](https://deps.rs/crate/actix-web/4.9.0/status.svg)](https://deps.rs/crate/actix-web/4.9.0) [![Dependency Status](https://deps.rs/crate/actix-web/4.9.0/status.svg)](https://deps.rs/crate/actix-web/4.9.0)
<br /> <br />
[![CI](https://github.com/actix/actix-web/actions/workflows/ci.yml/badge.svg)](https://github.com/actix/actix-web/actions/workflows/ci.yml) [![CI](https://github.com/actix/actix-web/actions/workflows/ci.yml/badge.svg)](https://github.com/actix/actix-web/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/actix/actix-web/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-web) [![codecov](https://codecov.io/gh/actix/actix-web/graph/badge.svg?token=dSwOnp9QCv)](https://codecov.io/gh/actix/actix-web)
![downloads](https://img.shields.io/crates/d/actix-web.svg) ![downloads](https://img.shields.io/crates/d/actix-web.svg)
[![Chat on Discord](https://img.shields.io/discord/771444961383153695?label=chat&logo=discord)](https://discord.gg/NWpN5mmg3x) [![Chat on Discord](https://img.shields.io/discord/771444961383153695?label=chat&logo=discord)](https://discord.gg/NWpN5mmg3x)

View File

@ -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
}

View File

@ -10,7 +10,7 @@ use bytes::BufMut;
/// perform a remaining length check before writing. /// perform a remaining length check before writing.
pub(crate) struct MutWriter<'a, B>(pub(crate) &'a mut B); pub(crate) struct MutWriter<'a, B>(pub(crate) &'a mut B);
impl<'a, B> io::Write for MutWriter<'a, B> impl<B> io::Write for MutWriter<'_, B>
where where
B: BufMut, B: BufMut,
{ {

View File

@ -704,7 +704,7 @@ impl FormatText {
/// Converter to get a String from something that writes to a Formatter. /// Converter to get a String from something that writes to a Formatter.
pub(crate) struct FormatDisplay<'a>(&'a dyn Fn(&mut fmt::Formatter<'_>) -> Result<(), fmt::Error>); pub(crate) struct FormatDisplay<'a>(&'a dyn Fn(&mut fmt::Formatter<'_>) -> Result<(), fmt::Error>);
impl<'a> fmt::Display for FormatDisplay<'a> { impl fmt::Display for FormatDisplay<'_> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
(self.0)(fmt) (self.0)(fmt)
} }

View File

@ -193,7 +193,7 @@ where
/// ///
/// One thread pool is set up **per worker**; not shared across workers. /// One thread pool is set up **per worker**; not shared across workers.
/// ///
/// By default set to 512 divided by the number of workers. /// By default, set to 512 divided by [available parallelism](std::thread::available_parallelism()).
pub fn worker_max_blocking_threads(mut self, num: usize) -> Self { pub fn worker_max_blocking_threads(mut self, num: usize) -> Self {
self.builder = self.builder.worker_max_blocking_threads(num); self.builder = self.builder.worker_max_blocking_threads(num);
self self

View File

@ -662,6 +662,7 @@ where
/// ``` /// ```
#[macro_export] #[macro_export]
macro_rules! services { macro_rules! services {
() => {()};
($($x:expr),+ $(,)?) => { ($($x:expr),+ $(,)?) => {
($($x,)+) ($($x,)+)
} }
@ -870,4 +871,40 @@ mod tests {
let req = test::TestRequest::default().to_request(); let req = test::TestRequest::default().to_request();
let _res = test::call_service(&app, req).await; let _res = test::call_service(&app, req).await;
} }
#[test]
fn define_services_macro_with_multiple_arguments() {
let result = services!(1, 2, 3);
assert_eq!(result, (1, 2, 3));
}
#[test]
fn define_services_macro_with_single_argument() {
let result = services!(1);
assert_eq!(result, (1,));
}
#[test]
fn define_services_macro_with_no_arguments() {
let result = services!();
let () = result;
}
#[test]
fn define_services_macro_with_trailing_comma() {
let result = services!(1, 2, 3,);
assert_eq!(result, (1, 2, 3));
}
#[test]
fn define_services_macro_with_comments_in_arguments() {
let result = services!(
1, // First comment
2, // Second comment
3 // Third comment
);
// Assert that comments are ignored and it correctly returns a tuple.
assert_eq!(result, (1, 2, 3));
}
} }

View File

@ -332,7 +332,7 @@ impl<T: DeserializeOwned> JsonBody<T> {
(true, Ok(Some(mime))) => { (true, Ok(Some(mime))) => {
mime.subtype() == mime::JSON mime.subtype() == mime::JSON
|| mime.suffix() == Some(mime::JSON) || mime.suffix() == Some(mime::JSON)
|| ctype_fn.map_or(false, |predicate| predicate(mime)) || ctype_fn.is_some_and(|predicate| predicate(mime))
} }
// if content-type is expected but not parsable as mime type, bail // if content-type is expected but not parsable as mime type, bail

View File

@ -2,6 +2,7 @@
## Unreleased ## Unreleased
- Update `brotli` dependency to `7`.
- Prevent panics on connection pool drop when Tokio runtime is shutdown early. - Prevent panics on connection pool drop when Tokio runtime is shutdown early.
- Minimum supported Rust version (MSRV) is now 1.75. - Minimum supported Rust version (MSRV) is now 1.75.

View File

@ -141,7 +141,7 @@ actix-tls = { version = "3.4", features = ["openssl", "rustls-0_23"] }
actix-utils = "3" actix-utils = "3"
actix-web = { version = "4", features = ["openssl"] } actix-web = { version = "4", features = ["openssl"] }
brotli = "6" brotli = "7"
const-str = "0.5" const-str = "0.5"
env_logger = "0.11" env_logger = "0.11"
flate2 = "1.0.13" flate2 = "1.0.13"
@ -153,9 +153,9 @@ tokio = { version = "1.24.2", features = ["rt-multi-thread", "macros"] }
zstd = "0.13" zstd = "0.13"
tls-rustls-0_23 = { package = "rustls", version = "0.23" } # add rustls 0.23 with default features to make aws_lc_rs work in tests tls-rustls-0_23 = { package = "rustls", version = "0.23" } # add rustls 0.23 with default features to make aws_lc_rs work in tests
[lints]
workspace = true
[[example]] [[example]]
name = "client" name = "client"
required-features = ["rustls-0_23-webpki-roots"] required-features = ["rustls-0_23-webpki-roots"]
[lints]
workspace = true

View File

@ -1,25 +1,39 @@
use std::error::Error as StdError; //! Demonstrates construction and usage of a TLS-capable HTTP client.
extern crate tls_rustls_0_23 as rustls;
use std::{error::Error as StdError, sync::Arc};
use actix_tls::connect::rustls_0_23::webpki_roots_cert_store;
use rustls::ClientConfig;
/// If we want to make requests to addresses starting with `https`, we need to enable the rustls feature of awc
/// `awc = { version = "3.5.0", features = ["rustls"] }`
#[actix_rt::main] #[actix_rt::main]
async fn main() -> Result<(), Box<dyn StdError>> { async fn main() -> Result<(), Box<dyn StdError>> {
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
// construct request builder let mut config = ClientConfig::builder()
let client = awc::Client::new(); .with_root_certificates(webpki_roots_cert_store())
.with_no_client_auth();
let protos = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
config.alpn_protocols = protos;
// construct request builder with TLS support
let client = awc::Client::builder()
.connector(awc::Connector::new().rustls_0_23(Arc::new(config)))
.finish();
// configure request // configure request
let request = client let request = client
.get("https://www.rust-lang.org/") .get("https://www.rust-lang.org/")
.append_header(("User-Agent", "Actix-web")); .append_header(("User-Agent", "awc/3.0"));
println!("Request: {:?}", request); println!("Request: {request:?}");
let mut response = request.send().await?; let mut response = request.send().await?;
// server response head // server response head
println!("Response: {:?}", response); println!("Response: {response:?}");
// read response body // read response body
let body = response.body().await?; let body = response.body().await?;

View File

@ -511,7 +511,8 @@ where
let h2 = sock let h2 = sock
.ssl() .ssl()
.selected_alpn_protocol() .selected_alpn_protocol()
.map_or(false, |protos| protos.windows(2).any(|w| w == H2)); .is_some_and(|protos| protos.windows(2).any(|w| w == H2));
if h2 { if h2 {
(Box::new(sock), Protocol::Http2) (Box::new(sock), Protocol::Http2)
} else { } else {
@ -550,7 +551,8 @@ where
.get_ref() .get_ref()
.1 .1
.alpn_protocol() .alpn_protocol()
.map_or(false, |protos| protos.windows(2).any(|w| w == H2)); .is_some_and(|protos| protos.windows(2).any(|w| w == H2));
if h2 { if h2 {
(Box::new(sock), Protocol::Http2) (Box::new(sock), Protocol::Http2)
} else { } else {
@ -584,7 +586,8 @@ where
.get_ref() .get_ref()
.1 .1
.alpn_protocol() .alpn_protocol()
.map_or(false, |protos| protos.windows(2).any(|w| w == H2)); .is_some_and(|protos| protos.windows(2).any(|w| w == H2));
if h2 { if h2 {
(Box::new(sock), Protocol::Http2) (Box::new(sock), Protocol::Http2)
} else { } else {
@ -621,7 +624,8 @@ where
.get_ref() .get_ref()
.1 .1
.alpn_protocol() .alpn_protocol()
.map_or(false, |protos| protos.windows(2).any(|w| w == H2)); .is_some_and(|protos| protos.windows(2).any(|w| w == H2));
if h2 { if h2 {
(Box::new(sock), Protocol::Http2) (Box::new(sock), Protocol::Http2)
} else { } else {
@ -655,7 +659,8 @@ where
.get_ref() .get_ref()
.1 .1
.alpn_protocol() .alpn_protocol()
.map_or(false, |protos| protos.windows(2).any(|w| w == H2)); .is_some_and(|protos| protos.windows(2).any(|w| w == H2));
if h2 { if h2 {
(Box::new(sock), Protocol::Http2) (Box::new(sock), Protocol::Http2)
} else { } else {

View File

@ -444,7 +444,7 @@ struct Host<'a> {
port: Option<http::uri::Port<&'a str>>, port: Option<http::uri::Port<&'a str>>,
} }
impl<'a> fmt::Display for Host<'a> { impl fmt::Display for Host<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.hostname)?; f.write_str(self.hostname)?;

View File

@ -12,6 +12,7 @@ fmt:
downgrade-for-msrv: downgrade-for-msrv:
cargo update -p=parse-size --precise=1.0.0 cargo update -p=parse-size --precise=1.0.0
cargo update -p=clap --precise=4.4.18 cargo update -p=clap --precise=4.4.18
cargo update -p=divan --precise=0.1.15
msrv := ``` msrv := ```
cargo metadata --format-version=1 \ cargo metadata --format-version=1 \
@ -36,6 +37,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 }}
@ -47,8 +51,8 @@ test-msrv: downgrade-for-msrv (test msrv_rustup)
test toolchain="": test toolchain="":
cargo {{ toolchain }} test --lib --tests -p=actix-web-codegen --all-features cargo {{ toolchain }} test --lib --tests -p=actix-web-codegen --all-features
cargo {{ toolchain }} test --lib --tests -p=actix-multipart-derive --all-features cargo {{ toolchain }} test --lib --tests -p=actix-multipart-derive --all-features
cargo {{ toolchain }} nextest run -p=actix-router --no-default-features cargo {{ toolchain }} nextest run --no-tests=warn -p=actix-router --no-default-features
cargo {{ toolchain }} nextest run --workspace --exclude=actix-web-codegen --exclude=actix-multipart-derive {{ all_crate_features }} --filter-expr="not test(test_reading_deflate_encoding_large_random_rustls)" cargo {{ toolchain }} nextest run --no-tests=warn --workspace --exclude=actix-web-codegen --exclude=actix-multipart-derive {{ all_crate_features }} --filter-expr="not test(test_reading_deflate_encoding_large_random_rustls)"
# Test workspace docs. # Test workspace docs.
test-docs toolchain="": && doc test-docs toolchain="": && doc
@ -60,7 +64,7 @@ test-all toolchain="": (test toolchain) (test-docs toolchain)
# Test workspace and collect coverage info. # Test workspace and collect coverage info.
[private] [private]
test-coverage toolchain="": test-coverage toolchain="":
cargo {{ toolchain }} llvm-cov nextest --no-report {{ all_crate_features }} cargo {{ toolchain }} llvm-cov nextest --no-tests=warn --no-report {{ all_crate_features }}
cargo {{ toolchain }} llvm-cov --doc --no-report {{ all_crate_features }} cargo {{ toolchain }} llvm-cov --doc --no-report {{ all_crate_features }}
# Test workspace and generate Codecov report. # Test workspace and generate Codecov report.