mirror of
https://github.com/fafhrd91/actix-web
synced 2025-07-06 19:00:18 +02:00
Compare commits
2 Commits
web-v4.8.0
...
error-resp
Author | SHA1 | Date | |
---|---|---|---|
eb10b74751 | |||
98c99f3bc2 |
10
.cargo/config.toml
Normal file
10
.cargo/config.toml
Normal file
@ -0,0 +1,10 @@
|
||||
[alias]
|
||||
lint = "clippy --workspace --all-targets -- -Dclippy::todo"
|
||||
lint-all = "clippy --workspace --all-features --all-targets -- -Dclippy::todo"
|
||||
|
||||
# lib checking
|
||||
ci-check-min = "hack --workspace check --no-default-features"
|
||||
ci-check-default = "hack --workspace check"
|
||||
ci-check-default-tests = "check --workspace --tests"
|
||||
ci-check-all-feature-powerset="hack --workspace --feature-powerset --depth=4 --skip=__compress,experimental-io-uring check"
|
||||
ci-check-all-feature-powerset-linux="hack --workspace --feature-powerset --depth=4 --skip=__compress check"
|
26
.github/workflows/ci-post-merge.yml
vendored
26
.github/workflows/ci-post-merge.yml
vendored
@ -44,20 +44,20 @@ jobs:
|
||||
echo "RUSTFLAGS=-C target-feature=+crt-static" >> $GITHUB_ENV
|
||||
|
||||
- name: Install Rust (${{ matrix.version.name }})
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.9.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.8.0
|
||||
with:
|
||||
toolchain: ${{ matrix.version.version }}
|
||||
|
||||
- name: Install just, cargo-hack, cargo-nextest, cargo-ci-cache-clean
|
||||
uses: taiki-e/install-action@v2.39.1
|
||||
uses: taiki-e/install-action@v2.34.0
|
||||
with:
|
||||
tool: just,cargo-hack,cargo-nextest,cargo-ci-cache-clean
|
||||
|
||||
- name: check minimal
|
||||
run: just check-min
|
||||
run: cargo ci-check-min
|
||||
|
||||
- name: check default
|
||||
run: just check-default
|
||||
run: cargo ci-check-default
|
||||
|
||||
- name: tests
|
||||
timeout-minutes: 60
|
||||
@ -76,16 +76,16 @@ jobs:
|
||||
- name: Free Disk Space
|
||||
run: ./scripts/free-disk-space.sh
|
||||
|
||||
- name: Setup mold linker
|
||||
uses: rui314/setup-mold@v1
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.9.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.8.0
|
||||
|
||||
- name: Install just, cargo-hack
|
||||
uses: taiki-e/install-action@v2.39.1
|
||||
- name: Install cargo-hack
|
||||
uses: taiki-e/install-action@v2.34.0
|
||||
with:
|
||||
tool: just,cargo-hack
|
||||
tool: cargo-hack
|
||||
|
||||
- name: Check feature combinations
|
||||
run: just check-feature-combinations
|
||||
- name: check feature combinations
|
||||
run: cargo ci-check-all-feature-powerset
|
||||
|
||||
- name: check feature combinations
|
||||
run: cargo ci-check-all-feature-powerset-linux
|
||||
|
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
@ -59,12 +59,12 @@ jobs:
|
||||
uses: rui314/setup-mold@v1
|
||||
|
||||
- name: Install Rust (${{ matrix.version.name }})
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.9.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.8.0
|
||||
with:
|
||||
toolchain: ${{ matrix.version.version }}
|
||||
|
||||
- name: Install just, cargo-hack, cargo-nextest, cargo-ci-cache-clean
|
||||
uses: taiki-e/install-action@v2.39.1
|
||||
uses: taiki-e/install-action@v2.34.0
|
||||
with:
|
||||
tool: just,cargo-hack,cargo-nextest,cargo-ci-cache-clean
|
||||
|
||||
@ -73,10 +73,10 @@ jobs:
|
||||
run: just downgrade-for-msrv
|
||||
|
||||
- name: check minimal
|
||||
run: just check-min
|
||||
run: cargo ci-check-min
|
||||
|
||||
- name: check default
|
||||
run: just check-default
|
||||
run: cargo ci-check-default
|
||||
|
||||
- name: tests
|
||||
timeout-minutes: 60
|
||||
@ -92,7 +92,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.9.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.8.0
|
||||
with:
|
||||
toolchain: nightly
|
||||
|
||||
@ -108,12 +108,12 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust (nightly)
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.9.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.8.0
|
||||
with:
|
||||
toolchain: nightly
|
||||
|
||||
- name: Install just
|
||||
uses: taiki-e/install-action@v2.39.1
|
||||
uses: taiki-e/install-action@v2.34.0
|
||||
with:
|
||||
tool: just
|
||||
|
||||
|
17
.github/workflows/coverage.yml
vendored
17
.github/workflows/coverage.yml
vendored
@ -17,22 +17,21 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust (nightly)
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.9.0
|
||||
- name: Install Rust
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.8.0
|
||||
with:
|
||||
toolchain: nightly
|
||||
components: llvm-tools
|
||||
components: llvm-tools-preview
|
||||
|
||||
- name: Install just, cargo-llvm-cov, cargo-nextest
|
||||
uses: taiki-e/install-action@v2.39.1
|
||||
- name: Install just,cargo-llvm-cov
|
||||
uses: taiki-e/install-action@v2.34.0
|
||||
with:
|
||||
tool: just,cargo-llvm-cov,cargo-nextest
|
||||
tool: just,cargo-llvm-cov
|
||||
|
||||
- name: Generate code coverage
|
||||
run: just test-coverage-codecov
|
||||
run: cargo llvm-cov --workspace --all-features --codecov --output-path codecov.json
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v4.5.0
|
||||
uses: codecov/codecov-action@v4.4.1
|
||||
with:
|
||||
files: codecov.json
|
||||
fail_ci_if_error: true
|
||||
|
35
.github/workflows/lint.yml
vendored
35
.github/workflows/lint.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust (nightly)
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.9.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.8.0
|
||||
with:
|
||||
toolchain: nightly
|
||||
components: rustfmt
|
||||
@ -36,7 +36,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.9.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.8.0
|
||||
with:
|
||||
components: clippy
|
||||
|
||||
@ -55,7 +55,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust (nightly)
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.9.0
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.8.0
|
||||
with:
|
||||
toolchain: nightly
|
||||
components: rust-docs
|
||||
@ -65,29 +65,6 @@ jobs:
|
||||
RUSTDOCFLAGS: -D warnings
|
||||
run: cargo +nightly doc --no-deps --workspace --all-features
|
||||
|
||||
check-external-types:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust (nightly-2024-05-01)
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.9.0
|
||||
with:
|
||||
toolchain: nightly-2024-05-01
|
||||
|
||||
- name: Install just
|
||||
uses: taiki-e/install-action@v2.39.1
|
||||
with:
|
||||
tool: just
|
||||
|
||||
- name: Install cargo-check-external-types
|
||||
uses: taiki-e/cache-cargo-install-action@v2.0.1
|
||||
with:
|
||||
tool: cargo-check-external-types
|
||||
|
||||
- name: check external types
|
||||
run: just check-external-types-all +nightly-2024-05-01
|
||||
|
||||
public-api-diff:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@ -99,13 +76,13 @@ jobs:
|
||||
- name: Checkout PR branch
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust (nightly-2024-06-07)
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.9.0
|
||||
- name: Install Rust
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.8.0
|
||||
with:
|
||||
toolchain: nightly-2024-06-07
|
||||
|
||||
- name: Install cargo-public-api
|
||||
uses: taiki-e/install-action@v2.39.1
|
||||
uses: taiki-e/install-action@v2.34.0
|
||||
with:
|
||||
tool: cargo-public-api
|
||||
|
||||
|
@ -13,14 +13,9 @@ categories = ["asynchronous", "web-programming::http-server"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2021"
|
||||
|
||||
[package.metadata.cargo_check_external_types]
|
||||
allowed_external_types = [
|
||||
"actix_http::*",
|
||||
"actix_service::*",
|
||||
"actix_web::*",
|
||||
"http::*",
|
||||
"mime::*",
|
||||
]
|
||||
[lib]
|
||||
name = "actix_files"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
experimental-io-uring = ["actix-web/experimental-io-uring", "tokio-uring"]
|
||||
|
@ -18,17 +18,9 @@ edition = "2021"
|
||||
[package.metadata.docs.rs]
|
||||
features = []
|
||||
|
||||
[package.metadata.cargo_check_external_types]
|
||||
allowed_external_types = [
|
||||
"actix_codec::*",
|
||||
"actix_http::*",
|
||||
"actix_server::*",
|
||||
"awc::*",
|
||||
"bytes::*",
|
||||
"futures_core::*",
|
||||
"http::*",
|
||||
"tokio::*",
|
||||
]
|
||||
[lib]
|
||||
name = "actix_http_test"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
@ -1,5 +1,7 @@
|
||||
# `actix-http-test`
|
||||
|
||||
> Various helpers for Actix applications to use during testing.
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
[](https://crates.io/crates/actix-http-test)
|
||||
@ -12,9 +14,3 @@
|
||||
[](https://discord.gg/NWpN5mmg3x)
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- cargo-rdme start -->
|
||||
|
||||
Various helpers for Actix applications to use during testing.
|
||||
|
||||
<!-- cargo-rdme end -->
|
||||
|
@ -2,8 +2,6 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
## 3.8.0
|
||||
|
||||
### Added
|
||||
|
||||
- Add `error::InvalidStatusCode` re-export.
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "actix-http"
|
||||
version = "3.8.0"
|
||||
version = "3.7.0"
|
||||
authors = [
|
||||
"Nikolay Kim <fafhrd91@gmail.com>",
|
||||
"Rob Ede <robjtede@icloud.com>",
|
||||
@ -34,72 +34,51 @@ features = [
|
||||
"compress-zstd",
|
||||
]
|
||||
|
||||
[package.metadata.cargo_check_external_types]
|
||||
allowed_external_types = [
|
||||
"actix_codec::*",
|
||||
"actix_service::*",
|
||||
"actix_tls::*",
|
||||
"actix_utils::*",
|
||||
"bytes::*",
|
||||
"bytestring::*",
|
||||
"encoding_rs::*",
|
||||
"futures_core::*",
|
||||
"h2::*",
|
||||
"http::*",
|
||||
"httparse::*",
|
||||
"language_tags::*",
|
||||
"mime::*",
|
||||
"openssl::*",
|
||||
"rustls::*",
|
||||
"tokio_util::*",
|
||||
"tokio::*",
|
||||
]
|
||||
[lib]
|
||||
name = "actix_http"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
# HTTP/2 protocol support
|
||||
http2 = ["dep:h2"]
|
||||
http2 = ["h2"]
|
||||
|
||||
# WebSocket protocol implementation
|
||||
ws = [
|
||||
"dep:local-channel",
|
||||
"dep:base64",
|
||||
"dep:rand",
|
||||
"dep:sha1",
|
||||
"local-channel",
|
||||
"base64",
|
||||
"rand",
|
||||
"sha1",
|
||||
]
|
||||
|
||||
# TLS via OpenSSL
|
||||
openssl = ["__tls", "actix-tls/accept", "actix-tls/openssl"]
|
||||
openssl = ["actix-tls/accept", "actix-tls/openssl"]
|
||||
|
||||
# TLS via Rustls v0.20
|
||||
rustls = ["__tls", "rustls-0_20"]
|
||||
rustls = ["rustls-0_20"]
|
||||
|
||||
# TLS via Rustls v0.20
|
||||
rustls-0_20 = ["__tls", "actix-tls/accept", "actix-tls/rustls-0_20"]
|
||||
rustls-0_20 = ["actix-tls/accept", "actix-tls/rustls-0_20"]
|
||||
|
||||
# TLS via Rustls v0.21
|
||||
rustls-0_21 = ["__tls", "actix-tls/accept", "actix-tls/rustls-0_21"]
|
||||
rustls-0_21 = ["actix-tls/accept", "actix-tls/rustls-0_21"]
|
||||
|
||||
# TLS via Rustls v0.22
|
||||
rustls-0_22 = ["__tls", "actix-tls/accept", "actix-tls/rustls-0_22"]
|
||||
rustls-0_22 = ["actix-tls/accept", "actix-tls/rustls-0_22"]
|
||||
|
||||
# TLS via Rustls v0.23
|
||||
rustls-0_23 = ["__tls", "actix-tls/accept", "actix-tls/rustls-0_23"]
|
||||
rustls-0_23 = ["actix-tls/accept", "actix-tls/rustls-0_23"]
|
||||
|
||||
# Compression codecs
|
||||
compress-brotli = ["__compress", "dep:brotli"]
|
||||
compress-gzip = ["__compress", "dep:flate2"]
|
||||
compress-zstd = ["__compress", "dep:zstd"]
|
||||
compress-brotli = ["__compress", "brotli"]
|
||||
compress-gzip = ["__compress", "flate2"]
|
||||
compress-zstd = ["__compress", "zstd"]
|
||||
|
||||
# Internal (PRIVATE!) features used to aid testing and checking feature status.
|
||||
# Don't rely on these whatsoever. They are semver-exempt and may disappear at anytime.
|
||||
__compress = []
|
||||
|
||||
# Internal (PRIVATE!) features used to aid checking feature status.
|
||||
# Don't rely on these whatsoever. They may disappear at anytime.
|
||||
__tls = []
|
||||
|
||||
[dependencies]
|
||||
actix-service = "2"
|
||||
actix-codec = "0.5"
|
||||
|
@ -5,11 +5,11 @@
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
[](https://crates.io/crates/actix-http)
|
||||
[](https://docs.rs/actix-http/3.8.0)
|
||||
[](https://docs.rs/actix-http/3.7.0)
|
||||

|
||||

|
||||
<br />
|
||||
[](https://deps.rs/crate/actix-http/3.8.0)
|
||||
[](https://deps.rs/crate/actix-http/3.7.0)
|
||||
[](https://crates.io/crates/actix-http)
|
||||
[](https://discord.gg/NWpN5mmg3x)
|
||||
|
||||
|
@ -6,10 +6,10 @@
|
||||
//! | ------------------- | ------------------------------------------- |
|
||||
//! | `http2` | HTTP/2 support via [h2]. |
|
||||
//! | `openssl` | TLS support via [OpenSSL]. |
|
||||
//! | `rustls-0_20` | TLS support via rustls 0.20. |
|
||||
//! | `rustls-0_21` | TLS support via rustls 0.21. |
|
||||
//! | `rustls-0_22` | TLS support via rustls 0.22. |
|
||||
//! | `rustls-0_23` | TLS support via [rustls] 0.23. |
|
||||
//! | `rustls` | TLS support via [rustls] 0.20. |
|
||||
//! | `rustls-0_21` | TLS support via [rustls] 0.21. |
|
||||
//! | `rustls-0_22` | TLS support via [rustls] 0.22. |
|
||||
//! | `rustls-0_23` | TLS support via [rustls] 0.23. |
|
||||
//! | `compress-brotli` | Payload compression support: Brotli. |
|
||||
//! | `compress-gzip` | Payload compression support: Deflate, Gzip. |
|
||||
//! | `compress-zstd` | Payload compression support: Zstd. |
|
||||
@ -61,7 +61,13 @@ pub mod ws;
|
||||
|
||||
#[allow(deprecated)]
|
||||
pub use self::payload::PayloadStream;
|
||||
#[cfg(feature = "__tls")]
|
||||
#[cfg(any(
|
||||
feature = "openssl",
|
||||
feature = "rustls-0_20",
|
||||
feature = "rustls-0_21",
|
||||
feature = "rustls-0_22",
|
||||
feature = "rustls-0_23",
|
||||
))]
|
||||
pub use self::service::TlsAcceptorConfig;
|
||||
pub use self::{
|
||||
builder::HttpServiceBuilder,
|
||||
|
@ -241,13 +241,25 @@ where
|
||||
}
|
||||
|
||||
/// Configuration options used when accepting TLS connection.
|
||||
#[cfg(feature = "__tls")]
|
||||
#[cfg(any(
|
||||
feature = "openssl",
|
||||
feature = "rustls-0_20",
|
||||
feature = "rustls-0_21",
|
||||
feature = "rustls-0_22",
|
||||
feature = "rustls-0_23",
|
||||
))]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TlsAcceptorConfig {
|
||||
pub(crate) handshake_timeout: Option<std::time::Duration>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "__tls")]
|
||||
#[cfg(any(
|
||||
feature = "openssl",
|
||||
feature = "rustls-0_20",
|
||||
feature = "rustls-0_21",
|
||||
feature = "rustls-0_22",
|
||||
feature = "rustls-0_23",
|
||||
))]
|
||||
impl TlsAcceptorConfig {
|
||||
/// Set TLS handshake timeout duration.
|
||||
pub fn handshake_timeout(self, dur: std::time::Duration) -> Self {
|
||||
|
@ -16,21 +16,6 @@ edition = "2021"
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
all-features = true
|
||||
|
||||
[package.metadata.cargo_check_external_types]
|
||||
allowed_external_types = [
|
||||
"actix_http::*",
|
||||
"actix_multipart_derive::*",
|
||||
"actix_utils::*",
|
||||
"actix_web::*",
|
||||
"bytes::*",
|
||||
"futures_core::*",
|
||||
"mime::*",
|
||||
"serde_json::*",
|
||||
"serde_plain::*",
|
||||
"serde::*",
|
||||
"tempfile::*",
|
||||
]
|
||||
|
||||
[features]
|
||||
default = ["tempfile", "derive"]
|
||||
derive = ["actix-multipart-derive"]
|
||||
|
@ -1,5 +1,7 @@
|
||||
# `actix-multipart`
|
||||
|
||||
> Multipart form support for Actix Web.
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
[](https://crates.io/crates/actix-multipart)
|
||||
@ -13,11 +15,18 @@
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- cargo-rdme start -->
|
||||
## Example
|
||||
|
||||
Multipart form support for Actix Web.
|
||||
Dependencies:
|
||||
|
||||
## Examples
|
||||
```toml
|
||||
[dependencies]
|
||||
actix-multipart = "0.6"
|
||||
actix-web = "4.5"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
```
|
||||
|
||||
Code:
|
||||
|
||||
```rust
|
||||
use actix_web::{post, App, HttpServer, Responder};
|
||||
@ -54,10 +63,6 @@ async fn main() -> std::io::Result<()> {
|
||||
}
|
||||
```
|
||||
|
||||
<!-- cargo-rdme end -->
|
||||
|
||||
[More available in the examples repo →](https://github.com/actix/examples/tree/master/forms/multipart)
|
||||
|
||||
Curl request :
|
||||
|
||||
```bash
|
||||
@ -66,3 +71,7 @@ curl -v --request POST \
|
||||
-F 'json={"name": "Cargo.lock"};type=application/json' \
|
||||
-F file=@./Cargo.lock
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
https://github.com/actix/examples/tree/master/forms/multipart
|
||||
|
@ -33,14 +33,6 @@ pub trait FieldReader<'t>: Sized + Any {
|
||||
type Future: Future<Output = Result<Self, MultipartError>>;
|
||||
|
||||
/// The form will call this function to handle the field.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// When reading the `field` payload using its `Stream` implementation, polling (manually or via
|
||||
/// `next()`/`try_next()`) may panic after the payload is exhausted. If this is a problem for
|
||||
/// your implementation of this method, you should [`fuse()`] the `Field` first.
|
||||
///
|
||||
/// [`fuse()`]: futures_util::stream::StreamExt::fuse()
|
||||
fn read_field(req: &'t HttpRequest, field: Field, limits: &'t mut Limits) -> Self::Future;
|
||||
}
|
||||
|
||||
@ -404,20 +396,11 @@ mod tests {
|
||||
use actix_http::encoding::Decoder;
|
||||
use actix_multipart_rfc7578::client::multipart;
|
||||
use actix_test::TestServer;
|
||||
use actix_web::{
|
||||
dev::Payload, http::StatusCode, web, App, HttpRequest, HttpResponse, Resource, Responder,
|
||||
};
|
||||
use actix_web::{dev::Payload, http::StatusCode, web, App, HttpResponse, Responder};
|
||||
use awc::{Client, ClientResponse};
|
||||
use futures_core::future::LocalBoxFuture;
|
||||
use futures_util::TryStreamExt as _;
|
||||
|
||||
use super::MultipartForm;
|
||||
use crate::{
|
||||
form::{
|
||||
bytes::Bytes, tempfile::TempFile, text::Text, FieldReader, Limits, MultipartFormConfig,
|
||||
},
|
||||
Field, MultipartError,
|
||||
};
|
||||
use crate::form::{bytes::Bytes, tempfile::TempFile, text::Text, MultipartFormConfig};
|
||||
|
||||
pub async fn send_form(
|
||||
srv: &TestServer,
|
||||
@ -751,49 +734,4 @@ mod tests {
|
||||
let response = send_form(&srv, form, "/").await;
|
||||
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: Connect(Disconnected)")]
|
||||
#[actix_web::test]
|
||||
async fn field_try_next_panic() {
|
||||
#[derive(Debug)]
|
||||
struct NullSink;
|
||||
|
||||
impl<'t> FieldReader<'t> for NullSink {
|
||||
type Future = LocalBoxFuture<'t, Result<Self, MultipartError>>;
|
||||
|
||||
fn read_field(
|
||||
_: &'t HttpRequest,
|
||||
mut field: Field,
|
||||
_limits: &'t mut Limits,
|
||||
) -> Self::Future {
|
||||
Box::pin(async move {
|
||||
// exhaust field stream
|
||||
while let Some(_chunk) = field.try_next().await? {}
|
||||
|
||||
// poll again, crash
|
||||
let _post = field.try_next().await;
|
||||
|
||||
Ok(Self)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(MultipartForm)]
|
||||
struct NullSinkForm {
|
||||
foo: NullSink,
|
||||
}
|
||||
|
||||
async fn null_sink(_form: MultipartForm<NullSinkForm>) -> impl Responder {
|
||||
"unreachable"
|
||||
}
|
||||
|
||||
let srv = actix_test::start(|| App::new().service(Resource::new("/").post(null_sink)));
|
||||
|
||||
let mut form = multipart::Form::default();
|
||||
form.add_text("foo", "data is not important to this test");
|
||||
|
||||
// panics with Err(Connect(Disconnected)) due to form NullSink panic
|
||||
let _res = send_form(&srv, form, "/").await;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
//! Multipart form support for Actix Web.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use actix_web::{post, App, HttpServer, Responder};
|
||||
//!
|
||||
|
@ -465,12 +465,7 @@ impl Stream for Field {
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
let this = self.get_mut();
|
||||
let mut inner = this.inner.borrow_mut();
|
||||
if let Some(mut buffer) = inner
|
||||
.payload
|
||||
.as_ref()
|
||||
.expect("Field should not be polled after completion")
|
||||
.get_mut(&this.safety)
|
||||
{
|
||||
if let Some(mut buffer) = inner.payload.as_ref().unwrap().get_mut(&this.safety) {
|
||||
// check safety and poll read payload to buffer.
|
||||
buffer.poll_stream(cx)?;
|
||||
} else if !this.safety.is_clean() {
|
||||
@ -501,7 +496,6 @@ impl fmt::Debug for Field {
|
||||
}
|
||||
|
||||
struct InnerField {
|
||||
/// Payload is initialized as Some and is `take`n when the field stream finishes.
|
||||
payload: Option<PayloadRef>,
|
||||
boundary: String,
|
||||
eof: bool,
|
||||
@ -649,12 +643,7 @@ impl InnerField {
|
||||
return Poll::Ready(None);
|
||||
}
|
||||
|
||||
let result = if let Some(mut payload) = self
|
||||
.payload
|
||||
.as_ref()
|
||||
.expect("Field should not be polled after completion")
|
||||
.get_mut(s)
|
||||
{
|
||||
let result = if let Some(mut payload) = self.payload.as_ref().unwrap().get_mut(s) {
|
||||
if !self.eof {
|
||||
let res = if let Some(ref mut len) = self.length {
|
||||
InnerField::read_len(&mut payload, len)
|
||||
@ -685,10 +674,8 @@ impl InnerField {
|
||||
};
|
||||
|
||||
if let Poll::Ready(None) = result {
|
||||
// drop payload buffer and make future un-poll-able
|
||||
let _ = self.payload.take();
|
||||
self.payload.take();
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
@ -12,11 +12,9 @@ repository = "https://github.com/actix/actix-web"
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2021"
|
||||
|
||||
[package.metadata.cargo_check_external_types]
|
||||
allowed_external_types = [
|
||||
"http::*",
|
||||
"serde::*",
|
||||
]
|
||||
[lib]
|
||||
name = "actix_router"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
default = ["http", "unicode"]
|
||||
|
@ -18,22 +18,6 @@ categories = [
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2021"
|
||||
|
||||
[package.metadata.cargo_check_external_types]
|
||||
allowed_external_types = [
|
||||
"actix_codec::*",
|
||||
"actix_http_test::*",
|
||||
"actix_http::*",
|
||||
"actix_service::*",
|
||||
"actix_web::*",
|
||||
"awc::*",
|
||||
"bytes::*",
|
||||
"futures_core::*",
|
||||
"http::*",
|
||||
"openssl::*",
|
||||
"rustls::*",
|
||||
"tokio::*",
|
||||
]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
|
@ -1,45 +0,0 @@
|
||||
# `actix-test`
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
[](https://crates.io/crates/actix-test)
|
||||
[](https://docs.rs/actix-test/0.1.5)
|
||||

|
||||

|
||||
<br />
|
||||
[](https://deps.rs/crate/actix-test/0.1.5)
|
||||
[](https://crates.io/crates/actix-test)
|
||||
[](https://discord.gg/NWpN5mmg3x)
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- cargo-rdme start -->
|
||||
|
||||
Integration testing tools for Actix Web applications.
|
||||
|
||||
The main integration testing tool is [`TestServer`]. It spawns a real HTTP server on an unused port and provides methods that use a real HTTP client. Therefore, it is much closer to real-world cases than using `init_service`, which skips HTTP encoding and decoding.
|
||||
|
||||
## Examples
|
||||
|
||||
```rust
|
||||
use actix_web::{get, web, test, App, HttpResponse, Error, Responder};
|
||||
|
||||
#[get("/")]
|
||||
async fn my_handler() -> Result<impl Responder, Error> {
|
||||
Ok(HttpResponse::Ok())
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_example() {
|
||||
let srv = actix_test::start(||
|
||||
App::new().service(my_handler)
|
||||
);
|
||||
|
||||
let req = srv.get("/");
|
||||
let res = req.send().await.unwrap();
|
||||
|
||||
assert!(res.status().is_success());
|
||||
}
|
||||
```
|
||||
|
||||
<!-- cargo-rdme end -->
|
@ -5,7 +5,6 @@
|
||||
//! real-world cases than using `init_service`, which skips HTTP encoding and decoding.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! ```
|
||||
//! use actix_web::{get, web, test, App, HttpResponse, Error, Responder};
|
||||
//!
|
||||
|
@ -9,15 +9,9 @@ repository = "https://github.com/actix/actix-web"
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2021"
|
||||
|
||||
[package.metadata.cargo_check_external_types]
|
||||
allowed_external_types = [
|
||||
"actix::*",
|
||||
"actix_http::*",
|
||||
"actix_web::*",
|
||||
"bytes::*",
|
||||
"bytestring::*",
|
||||
"futures_core::*",
|
||||
]
|
||||
[lib]
|
||||
name = "actix_web_actors"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
actix = { version = ">=0.12, <0.14", default-features = false }
|
||||
|
@ -2,18 +2,9 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
## 4.8.0
|
||||
|
||||
### Added
|
||||
|
||||
- Add `web::Html` responder.
|
||||
- Add `HttpRequest::full_url()` method to get the complete URL of the request.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Always remove port from return value of `ConnectionInfo::realip_remote_addr()` when handling IPv6 addresses. from the `Forwarded` header.
|
||||
- The `UrlencodedError::ContentType` variant (relevant to the `Form` extractor) now uses the 415 (Media Type Unsupported) status code in it's `ResponseError` implementation.
|
||||
- Apply `HttpServer::max_connection_rate()` setting when using rustls v0.22 or v0.23.
|
||||
- `ConnectionInfo::realip_remote_addr()` now handles IPv6 addresses from `Forwarded` header correctly. Previously, it sometimes returned the forwarded port as well.
|
||||
|
||||
## 4.7.0
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "actix-web"
|
||||
version = "4.8.0"
|
||||
version = "4.7.0"
|
||||
description = "Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust"
|
||||
authors = [
|
||||
"Nikolay Kim <fafhrd91@gmail.com>",
|
||||
@ -35,31 +35,9 @@ features = [
|
||||
"secure-cookies",
|
||||
]
|
||||
|
||||
[package.metadata.cargo_check_external_types]
|
||||
allowed_external_types = [
|
||||
"actix_http::*",
|
||||
"actix_router::*",
|
||||
"actix_rt::*",
|
||||
"actix_server::*",
|
||||
"actix_service::*",
|
||||
"actix_utils::*",
|
||||
"actix_web_codegen::*",
|
||||
"bytes::*",
|
||||
"cookie::*",
|
||||
"cookie",
|
||||
"futures_core::*",
|
||||
"http::*",
|
||||
"language_tags::*",
|
||||
"mime::*",
|
||||
"openssl::*",
|
||||
"rustls::*",
|
||||
"serde_json::*",
|
||||
"serde_urlencoded::*",
|
||||
"serde::*",
|
||||
"serde::*",
|
||||
"tokio::*",
|
||||
"url::*",
|
||||
]
|
||||
[lib]
|
||||
name = "actix_web"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
default = [
|
||||
@ -93,18 +71,18 @@ secure-cookies = ["cookies", "cookie/secure"]
|
||||
http2 = ["actix-http/http2"]
|
||||
|
||||
# TLS via OpenSSL
|
||||
openssl = ["__tls", "http2", "actix-http/openssl", "actix-tls/accept", "actix-tls/openssl"]
|
||||
openssl = ["http2", "actix-http/openssl", "actix-tls/accept", "actix-tls/openssl"]
|
||||
|
||||
# TLS via Rustls v0.20
|
||||
rustls = ["rustls-0_20"]
|
||||
# TLS via Rustls v0.20
|
||||
rustls-0_20 = ["__tls", "http2", "actix-http/rustls-0_20", "actix-tls/accept", "actix-tls/rustls-0_20"]
|
||||
rustls-0_20 = ["http2", "actix-http/rustls-0_20", "actix-tls/accept", "actix-tls/rustls-0_20"]
|
||||
# TLS via Rustls v0.21
|
||||
rustls-0_21 = ["__tls", "http2", "actix-http/rustls-0_21", "actix-tls/accept", "actix-tls/rustls-0_21"]
|
||||
rustls-0_21 = ["http2", "actix-http/rustls-0_21", "actix-tls/accept", "actix-tls/rustls-0_21"]
|
||||
# TLS via Rustls v0.22
|
||||
rustls-0_22 = ["__tls", "http2", "actix-http/rustls-0_22", "actix-tls/accept", "actix-tls/rustls-0_22"]
|
||||
rustls-0_22 = ["http2", "actix-http/rustls-0_22", "actix-tls/accept", "actix-tls/rustls-0_22"]
|
||||
# TLS via Rustls v0.23
|
||||
rustls-0_23 = ["__tls", "http2", "actix-http/rustls-0_23", "actix-tls/accept", "actix-tls/rustls-0_23"]
|
||||
rustls-0_23 = ["http2", "actix-http/rustls-0_23", "actix-tls/accept", "actix-tls/rustls-0_23"]
|
||||
|
||||
# Full unicode support
|
||||
unicode = ["dep:regex", "actix-router/unicode"]
|
||||
@ -113,10 +91,6 @@ unicode = ["dep:regex", "actix-router/unicode"]
|
||||
# Don't rely on these whatsoever. They may disappear at anytime.
|
||||
__compress = []
|
||||
|
||||
# Internal (PRIVATE!) features used to aid checking feature status.
|
||||
# Don't rely on these whatsoever. They may disappear at anytime.
|
||||
__tls = []
|
||||
|
||||
# io-uring feature only available for Linux OSes.
|
||||
experimental-io-uring = ["actix-server/io-uring"]
|
||||
|
||||
|
@ -8,10 +8,10 @@
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
[](https://crates.io/crates/actix-web)
|
||||
[](https://docs.rs/actix-web/4.8.0)
|
||||
[](https://docs.rs/actix-web/4.7.0)
|
||||

|
||||

|
||||
[](https://deps.rs/crate/actix-web/4.8.0)
|
||||
[](https://deps.rs/crate/actix-web/4.7.0)
|
||||
<br />
|
||||
[](https://github.com/actix/actix-web/actions/workflows/ci.yml)
|
||||
[](https://codecov.io/gh/actix/actix-web)
|
||||
@ -109,4 +109,4 @@ This project is licensed under either of the following licenses, at your option:
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Contribution to the `actix/actix-web` repo is organized under the terms of the Contributor Covenant. The Actix team promises to intervene to uphold that code of conduct.
|
||||
Contribution to the actix-web repo is organized under the terms of the Contributor Covenant. The Actix team promises to intervene to uphold that code of conduct.
|
||||
|
@ -234,6 +234,7 @@ where
|
||||
///
|
||||
/// * *Resource* is an entry in resource table which corresponds to requested URL.
|
||||
/// * *Scope* is a set of resources with common root path.
|
||||
/// * "StaticFiles" is a service for static files support
|
||||
pub fn service<F>(mut self, factory: F) -> Self
|
||||
where
|
||||
F: HttpServiceFactory + 'static,
|
||||
|
@ -6,7 +6,7 @@ use crate::{HttpResponse, ResponseError};
|
||||
|
||||
/// General purpose Actix Web error.
|
||||
///
|
||||
/// An Actix Web error is used to carry errors from `std::error` through actix in a convenient way.
|
||||
/// An Actix Web error is used to carry errors from `std::error` through Actix in a convenient way.
|
||||
/// It can be created through converting errors with `into()`.
|
||||
///
|
||||
/// Whenever it is created from an external object a response error is created for it that can be
|
||||
@ -14,6 +14,7 @@ use crate::{HttpResponse, ResponseError};
|
||||
/// you can always get a `ResponseError` reference from it.
|
||||
pub struct Error {
|
||||
cause: Box<dyn ResponseError>,
|
||||
response_mappers: Vec<Box<dyn Fn(HttpResponse) -> HttpResponse>>,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
@ -29,7 +30,20 @@ impl Error {
|
||||
|
||||
/// Shortcut for creating an `HttpResponse`.
|
||||
pub fn error_response(&self) -> HttpResponse {
|
||||
self.cause.error_response()
|
||||
let mut res = self.cause.error_response();
|
||||
|
||||
for mapper in &self.response_mappers {
|
||||
res = (mapper)(res);
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub fn add_mapper<F, B>(&mut self, mapper: F)
|
||||
where
|
||||
F: Fn(HttpResponse) -> HttpResponse + 'static,
|
||||
{
|
||||
self.response_mappers.push(Box::new(mapper))
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,6 +70,7 @@ impl<T: ResponseError + 'static> From<T> for Error {
|
||||
fn from(err: T) -> Error {
|
||||
Error {
|
||||
cause: Box::new(err),
|
||||
response_mappers: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +100,6 @@ impl ResponseError for UrlencodedError {
|
||||
match self {
|
||||
Self::Overflow { .. } => StatusCode::PAYLOAD_TOO_LARGE,
|
||||
Self::UnknownLength => StatusCode::LENGTH_REQUIRED,
|
||||
Self::ContentType => StatusCode::UNSUPPORTED_MEDIA_TYPE,
|
||||
Self::Payload(err) => err.status_code(),
|
||||
_ => StatusCode::BAD_REQUEST,
|
||||
}
|
||||
@ -233,7 +232,7 @@ mod tests {
|
||||
let resp = UrlencodedError::UnknownLength.error_response();
|
||||
assert_eq!(resp.status(), StatusCode::LENGTH_REQUIRED);
|
||||
let resp = UrlencodedError::ContentType.error_response();
|
||||
assert_eq!(resp.status(), StatusCode::UNSUPPORTED_MEDIA_TYPE);
|
||||
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -27,8 +27,7 @@ fn bare_address(val: &str) -> &str {
|
||||
val.split("]:")
|
||||
.next()
|
||||
.map(|s| s.trim_start_matches('[').trim_end_matches(']'))
|
||||
// this indicates that the IPv6 address is malformed so shouldn't
|
||||
// usually happen, but if it does, just return the original input
|
||||
// This shouldn't *actually* ever happen
|
||||
.unwrap_or(val)
|
||||
} else {
|
||||
val.split(':').next().unwrap_or(val)
|
||||
|
@ -91,35 +91,6 @@ impl HttpRequest {
|
||||
&self.head().uri
|
||||
}
|
||||
|
||||
/// Returns request's original full URL.
|
||||
///
|
||||
/// Reconstructed URL is best-effort, using [`connection_info`](HttpRequest::connection_info())
|
||||
/// to get forwarded scheme & host.
|
||||
///
|
||||
/// ```
|
||||
/// use actix_web::test::TestRequest;
|
||||
/// let req = TestRequest::with_uri("http://10.1.2.3:8443/api?id=4&name=foo")
|
||||
/// .insert_header(("host", "example.com"))
|
||||
/// .to_http_request();
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// req.full_url().as_str(),
|
||||
/// "http://example.com/api?id=4&name=foo",
|
||||
/// );
|
||||
/// ```
|
||||
pub fn full_url(&self) -> url::Url {
|
||||
let info = self.connection_info();
|
||||
let scheme = info.scheme();
|
||||
let host = info.host();
|
||||
let path_and_query = self
|
||||
.uri()
|
||||
.path_and_query()
|
||||
.map(|paq| paq.as_str())
|
||||
.unwrap_or("/");
|
||||
|
||||
url::Url::parse(&format!("{scheme}://{host}{path_and_query}")).unwrap()
|
||||
}
|
||||
|
||||
/// Read the Request method.
|
||||
#[inline]
|
||||
pub fn method(&self) -> &Method {
|
||||
@ -992,27 +963,4 @@ mod tests {
|
||||
|
||||
assert!(format!("{:?}", req).contains(location_header));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_full_url() {
|
||||
let req = TestRequest::with_uri("/api?id=4&name=foo").to_http_request();
|
||||
assert_eq!(
|
||||
req.full_url().as_str(),
|
||||
"http://localhost:8080/api?id=4&name=foo",
|
||||
);
|
||||
|
||||
let req = TestRequest::with_uri("https://example.com/api?id=4&name=foo").to_http_request();
|
||||
assert_eq!(
|
||||
req.full_url().as_str(),
|
||||
"https://example.com/api?id=4&name=foo",
|
||||
);
|
||||
|
||||
let req = TestRequest::with_uri("http://10.1.2.3:8443/api?id=4&name=foo")
|
||||
.insert_header(("host", "example.com"))
|
||||
.to_http_request();
|
||||
assert_eq!(
|
||||
req.full_url().as_str(),
|
||||
"http://example.com/api?id=4&name=foo",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -213,6 +213,7 @@ where
|
||||
///
|
||||
/// * *Resource* is an entry in resource table which corresponds to requested URL.
|
||||
/// * *Scope* is a set of resources with common root path.
|
||||
/// * "StaticFiles" is a service for static files support
|
||||
///
|
||||
/// ```
|
||||
/// use actix_web::{web, App, HttpRequest};
|
||||
|
@ -7,7 +7,13 @@ use std::{
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
#[cfg(feature = "__tls")]
|
||||
#[cfg(any(
|
||||
feature = "openssl",
|
||||
feature = "rustls-0_20",
|
||||
feature = "rustls-0_21",
|
||||
feature = "rustls-0_22",
|
||||
feature = "rustls-0_23",
|
||||
))]
|
||||
use actix_http::TlsAcceptorConfig;
|
||||
use actix_http::{body::MessageBody, Extensions, HttpService, KeepAlive, Request, Response};
|
||||
use actix_server::{Server, ServerBuilder};
|
||||
@ -184,7 +190,7 @@ where
|
||||
/// By default max connections is set to a 256.
|
||||
#[allow(unused_variables)]
|
||||
pub fn max_connection_rate(self, num: usize) -> Self {
|
||||
#[cfg(feature = "__tls")]
|
||||
#[cfg(any(feature = "rustls-0_20", feature = "rustls-0_21", feature = "openssl"))]
|
||||
actix_tls::accept::max_concurrent_tls_connect(num);
|
||||
self
|
||||
}
|
||||
@ -237,7 +243,13 @@ where
|
||||
/// time, the connection is closed.
|
||||
///
|
||||
/// By default, the handshake timeout is 3 seconds.
|
||||
#[cfg(feature = "__tls")]
|
||||
#[cfg(any(
|
||||
feature = "openssl",
|
||||
feature = "rustls-0_20",
|
||||
feature = "rustls-0_21",
|
||||
feature = "rustls-0_22",
|
||||
feature = "rustls-0_23",
|
||||
))]
|
||||
pub fn tls_handshake_timeout(self, dur: Duration) -> Self {
|
||||
self.config
|
||||
.lock()
|
||||
|
@ -1,66 +0,0 @@
|
||||
//! Semantic HTML responder. See [`Html`].
|
||||
|
||||
use crate::{
|
||||
http::{
|
||||
header::{self, ContentType, TryIntoHeaderValue},
|
||||
StatusCode,
|
||||
},
|
||||
HttpRequest, HttpResponse, Responder,
|
||||
};
|
||||
|
||||
/// Semantic HTML responder.
|
||||
///
|
||||
/// When used as a responder, creates a 200 OK response, sets the correct HTML content type, and
|
||||
/// uses the string passed to [`Html::new()`] as the body.
|
||||
///
|
||||
/// ```
|
||||
/// # use actix_web::web::Html;
|
||||
/// Html::new("<p>Hello, World!</p>")
|
||||
/// # ;
|
||||
/// ```
|
||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||
pub struct Html(String);
|
||||
|
||||
impl Html {
|
||||
/// Constructs a new `Html` responder.
|
||||
pub fn new(html: impl Into<String>) -> Self {
|
||||
Self(html.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl Responder for Html {
|
||||
type Body = String;
|
||||
|
||||
fn respond_to(self, _req: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||
let mut res = HttpResponse::with_body(StatusCode::OK, self.0);
|
||||
res.headers_mut().insert(
|
||||
header::CONTENT_TYPE,
|
||||
ContentType::html().try_into_value().unwrap(),
|
||||
);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::test::TestRequest;
|
||||
|
||||
#[test]
|
||||
fn responder() {
|
||||
let req = TestRequest::default().to_http_request();
|
||||
|
||||
let res = Html::new("<p>Hello, World!</p>");
|
||||
let res = res.respond_to(&req);
|
||||
|
||||
assert!(res.status().is_success());
|
||||
assert!(res
|
||||
.headers()
|
||||
.get(header::CONTENT_TYPE)
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.starts_with("text/html"));
|
||||
assert!(res.body().starts_with("<p>"));
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@
|
||||
mod either;
|
||||
mod form;
|
||||
mod header;
|
||||
mod html;
|
||||
mod json;
|
||||
mod path;
|
||||
mod payload;
|
||||
@ -14,7 +13,6 @@ pub use self::{
|
||||
either::Either,
|
||||
form::{Form, FormConfig, UrlEncoded},
|
||||
header::Header,
|
||||
html::Html,
|
||||
json::{Json, JsonBody, JsonConfig},
|
||||
path::{Path, PathConfig},
|
||||
payload::{Payload, PayloadConfig},
|
||||
|
@ -15,6 +15,10 @@ repository = "https://github.com/actix/actix-web"
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "awc"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
features = [
|
||||
@ -29,27 +33,6 @@ features = [
|
||||
"compress-zstd",
|
||||
]
|
||||
|
||||
[package.metadata.cargo_check_external_types]
|
||||
allowed_external_types = [
|
||||
"actix_codec::*",
|
||||
"actix_http::*",
|
||||
"actix_rt::*",
|
||||
"actix_service::*",
|
||||
"actix_tls::*",
|
||||
"bytes::*",
|
||||
"cookie::*",
|
||||
"cookie",
|
||||
"futures_core::*",
|
||||
"h2::*",
|
||||
"http::*",
|
||||
"openssl::*",
|
||||
"rustls::*",
|
||||
"serde_json::*",
|
||||
"serde_urlencoded::*",
|
||||
"serde::*",
|
||||
"tokio::*",
|
||||
]
|
||||
|
||||
[features]
|
||||
default = ["compress-brotli", "compress-gzip", "compress-zstd", "cookies"]
|
||||
|
||||
@ -151,7 +134,7 @@ rcgen = "0.13"
|
||||
rustls-pemfile = "2"
|
||||
tokio = { version = "1.24.2", features = ["rt-multi-thread", "macros"] }
|
||||
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
|
||||
|
||||
[[example]]
|
||||
name = "client"
|
||||
|
79
justfile
79
justfile
@ -22,7 +22,7 @@ non_linux_all_features_list := ```
|
||||
cargo metadata --format-version=1 \
|
||||
| jq '.packages[] | select(.source == null) | .features | keys' \
|
||||
| jq -r --slurp \
|
||||
--arg exclusions "__tls,__compress,tokio-uring,io-uring,experimental-io-uring" \
|
||||
--arg exclusions "tokio-uring,io-uring,experimental-io-uring" \
|
||||
'add | unique | . - ($exclusions | split(",")) | join(",")'
|
||||
```
|
||||
|
||||
@ -32,14 +32,6 @@ all_crate_features := if os() == "linux" {
|
||||
"--features='" + non_linux_all_features_list + "'"
|
||||
}
|
||||
|
||||
[private]
|
||||
check-min:
|
||||
cargo hack --workspace check --no-default-features
|
||||
|
||||
[private]
|
||||
check-default:
|
||||
cargo hack --workspace check
|
||||
|
||||
# Run Clippy over workspace.
|
||||
clippy toolchain="":
|
||||
cargo {{ toolchain }} clippy --workspace --all-targets {{ all_crate_features }}
|
||||
@ -61,32 +53,9 @@ test-docs toolchain="": && doc
|
||||
# Test workspace.
|
||||
test-all toolchain="": (test toolchain) (test-docs toolchain)
|
||||
|
||||
# Test workspace and collect coverage info.
|
||||
[private]
|
||||
test-coverage toolchain="":
|
||||
cargo {{ toolchain }} llvm-cov nextest --no-report {{ all_crate_features }}
|
||||
cargo {{ toolchain }} llvm-cov --doc --no-report {{ all_crate_features }}
|
||||
|
||||
# Test workspace and generate Codecov report.
|
||||
test-coverage-codecov toolchain="": (test-coverage toolchain)
|
||||
cargo {{ toolchain }} llvm-cov report --doctests --codecov --output-path=codecov.json
|
||||
|
||||
# Test workspace and generate LCOV report.
|
||||
test-coverage-lcov toolchain="": (test-coverage toolchain)
|
||||
cargo {{ toolchain }} llvm-cov report --doctests --lcov --output-path=lcov.info
|
||||
|
||||
# Document crates in workspace.
|
||||
doc *args: && doc-set-workspace-crates
|
||||
RUSTDOCFLAGS="--cfg=docsrs -Dwarnings" cargo +nightly doc --workspace {{ all_crate_features }} {{ args }}
|
||||
|
||||
[private]
|
||||
doc-set-workspace-crates:
|
||||
#!/usr/bin/env bash
|
||||
(
|
||||
echo "window.ALL_CRATES ="
|
||||
cargo metadata --format-version=1 | jq '[.packages[] | select(.source == null) | .name]'
|
||||
echo ";"
|
||||
) > "$(cargo metadata --format-version=1 | jq -r '.target_directory')/doc/crates.js"
|
||||
doc *args:
|
||||
RUSTDOCFLAGS="--cfg=docsrs -Dwarnings" cargo +nightly doc --no-deps --workspace {{ all_crate_features }} {{ args }}
|
||||
|
||||
# Document crates in workspace and watch for changes.
|
||||
doc-watch:
|
||||
@ -96,46 +65,4 @@ doc-watch:
|
||||
# Update READMEs from crate root documentation.
|
||||
update-readmes: && fmt
|
||||
cd ./actix-files && cargo rdme --force
|
||||
cd ./actix-http-test && cargo rdme --force
|
||||
cd ./actix-router && cargo rdme --force
|
||||
cd ./actix-multipart && cargo rdme --force
|
||||
cd ./actix-test && cargo rdme --force
|
||||
|
||||
feature_combo_skip_list := if os() == "linux" {
|
||||
"__tls,__compress"
|
||||
} else {
|
||||
"__tls,__compress,experimental-io-uring"
|
||||
}
|
||||
|
||||
# Checks compatibility of feature combinations.
|
||||
check-feature-combinations:
|
||||
cargo hack --workspace \
|
||||
--feature-powerset --depth=4 \
|
||||
--skip={{ feature_combo_skip_list }} \
|
||||
check
|
||||
|
||||
# Check for unintentional external type exposure on all crates in workspace.
|
||||
check-external-types-all toolchain="+nightly":
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
exit=0
|
||||
for f in $(find . -mindepth 2 -maxdepth 2 -name Cargo.toml | grep -vE "\-codegen/|\-derive/|\-macros/"); do
|
||||
if ! just check-external-types-manifest "$f" {{toolchain}}; then exit=1; fi
|
||||
echo
|
||||
echo
|
||||
done
|
||||
exit $exit
|
||||
|
||||
# Check for unintentional external type exposure on all crates in workspace.
|
||||
check-external-types-all-table toolchain="+nightly":
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
for f in $(find . -mindepth 2 -maxdepth 2 -name Cargo.toml | grep -vE "\-codegen/|\-derive/|\-macros/"); do
|
||||
echo
|
||||
echo "Checking for $f"
|
||||
just check-external-types-manifest "$f" {{toolchain}} --output-format=markdown-table
|
||||
done
|
||||
|
||||
# Check for unintentional external type exposure on a crate.
|
||||
check-external-types-manifest manifest_path toolchain="+nightly" *extra_args="":
|
||||
cargo {{toolchain}} check-external-types --manifest-path "{{manifest_path}}" {{extra_args}}
|
||||
|
Reference in New Issue
Block a user