mirror of https://github.com/fafhrd91/actix-web
Compare commits
No commits in common. "82b4ee217198ba71a221e79841c476a44ee16a36" and "f985a8dc3bff170ad3454ecc89a43b6a836cda15" have entirely different histories.
82b4ee2171
...
f985a8dc3b
|
|
@ -44,12 +44,12 @@ jobs:
|
||||||
echo "RUSTFLAGS=-C target-feature=+crt-static" >> $GITHUB_ENV
|
echo "RUSTFLAGS=-C target-feature=+crt-static" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Install Rust (${{ matrix.version.name }})
|
- name: Install Rust (${{ matrix.version.name }})
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@02be93da58aa71fb456aa9c43b301149248829d8 # v1.15.1
|
uses: actions-rust-lang/setup-rust-toolchain@2fcdc490d667999e01ddbbf0f2823181beef6b39 # v1.15.0
|
||||||
with:
|
with:
|
||||||
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@efd8b64311f7a0a9b888ed13d0df78ec9184c163 # v2.62.11
|
uses: taiki-e/install-action@0e09747a63ae497bf945b3dcaf38fef0050d0109 # v2.62.0
|
||||||
with:
|
with:
|
||||||
tool: just,cargo-hack,cargo-nextest,cargo-ci-cache-clean
|
tool: just,cargo-hack,cargo-nextest,cargo-ci-cache-clean
|
||||||
|
|
||||||
|
|
@ -80,10 +80,10 @@ jobs:
|
||||||
uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1
|
uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1
|
||||||
|
|
||||||
- name: Install Rust
|
- name: Install Rust
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@02be93da58aa71fb456aa9c43b301149248829d8 # v1.15.1
|
uses: actions-rust-lang/setup-rust-toolchain@2fcdc490d667999e01ddbbf0f2823181beef6b39 # v1.15.0
|
||||||
|
|
||||||
- name: Install just, cargo-hack
|
- name: Install just, cargo-hack
|
||||||
uses: taiki-e/install-action@efd8b64311f7a0a9b888ed13d0df78ec9184c163 # v2.62.11
|
uses: taiki-e/install-action@0e09747a63ae497bf945b3dcaf38fef0050d0109 # v2.62.0
|
||||||
with:
|
with:
|
||||||
tool: just,cargo-hack
|
tool: just,cargo-hack
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,12 +59,12 @@ jobs:
|
||||||
uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1
|
uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1
|
||||||
|
|
||||||
- name: Install Rust (${{ matrix.version.name }})
|
- name: Install Rust (${{ matrix.version.name }})
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@02be93da58aa71fb456aa9c43b301149248829d8 # v1.15.1
|
uses: actions-rust-lang/setup-rust-toolchain@2fcdc490d667999e01ddbbf0f2823181beef6b39 # v1.15.0
|
||||||
with:
|
with:
|
||||||
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@efd8b64311f7a0a9b888ed13d0df78ec9184c163 # v2.62.11
|
uses: taiki-e/install-action@0e09747a63ae497bf945b3dcaf38fef0050d0109 # v2.62.0
|
||||||
with:
|
with:
|
||||||
tool: just,cargo-hack,cargo-nextest,cargo-ci-cache-clean
|
tool: just,cargo-hack,cargo-nextest,cargo-ci-cache-clean
|
||||||
|
|
||||||
|
|
@ -92,7 +92,7 @@ jobs:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
|
||||||
- name: Install Rust
|
- name: Install Rust
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@02be93da58aa71fb456aa9c43b301149248829d8 # v1.15.1
|
uses: actions-rust-lang/setup-rust-toolchain@2fcdc490d667999e01ddbbf0f2823181beef6b39 # v1.15.0
|
||||||
with:
|
with:
|
||||||
toolchain: nightly
|
toolchain: nightly
|
||||||
|
|
||||||
|
|
@ -108,12 +108,12 @@ jobs:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
|
||||||
- name: Install Rust (nightly)
|
- name: Install Rust (nightly)
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@02be93da58aa71fb456aa9c43b301149248829d8 # v1.15.1
|
uses: actions-rust-lang/setup-rust-toolchain@2fcdc490d667999e01ddbbf0f2823181beef6b39 # v1.15.0
|
||||||
with:
|
with:
|
||||||
toolchain: nightly
|
toolchain: nightly
|
||||||
|
|
||||||
- name: Install just
|
- name: Install just
|
||||||
uses: taiki-e/install-action@efd8b64311f7a0a9b888ed13d0df78ec9184c163 # v2.62.11
|
uses: taiki-e/install-action@0e09747a63ae497bf945b3dcaf38fef0050d0109 # v2.62.0
|
||||||
with:
|
with:
|
||||||
tool: just
|
tool: just
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,13 @@ jobs:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
|
||||||
- name: Install Rust (nightly)
|
- name: Install Rust (nightly)
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@02be93da58aa71fb456aa9c43b301149248829d8 # v1.15.1
|
uses: actions-rust-lang/setup-rust-toolchain@2fcdc490d667999e01ddbbf0f2823181beef6b39 # v1.15.0
|
||||||
with:
|
with:
|
||||||
toolchain: nightly
|
toolchain: nightly
|
||||||
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@efd8b64311f7a0a9b888ed13d0df78ec9184c163 # v2.62.11
|
uses: taiki-e/install-action@0e09747a63ae497bf945b3dcaf38fef0050d0109 # v2.62.0
|
||||||
with:
|
with:
|
||||||
tool: just,cargo-llvm-cov,cargo-nextest
|
tool: just,cargo-llvm-cov,cargo-nextest
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ jobs:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
|
||||||
- name: Install Rust (nightly)
|
- name: Install Rust (nightly)
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@02be93da58aa71fb456aa9c43b301149248829d8 # v1.15.1
|
uses: actions-rust-lang/setup-rust-toolchain@2fcdc490d667999e01ddbbf0f2823181beef6b39 # v1.15.0
|
||||||
with:
|
with:
|
||||||
toolchain: nightly
|
toolchain: nightly
|
||||||
components: rustfmt
|
components: rustfmt
|
||||||
|
|
@ -36,7 +36,7 @@ jobs:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
|
||||||
- name: Install Rust
|
- name: Install Rust
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@02be93da58aa71fb456aa9c43b301149248829d8 # v1.15.1
|
uses: actions-rust-lang/setup-rust-toolchain@2fcdc490d667999e01ddbbf0f2823181beef6b39 # v1.15.0
|
||||||
with:
|
with:
|
||||||
components: clippy
|
components: clippy
|
||||||
|
|
||||||
|
|
@ -55,7 +55,7 @@ jobs:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
|
||||||
- name: Install Rust (nightly)
|
- name: Install Rust (nightly)
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@02be93da58aa71fb456aa9c43b301149248829d8 # v1.15.1
|
uses: actions-rust-lang/setup-rust-toolchain@2fcdc490d667999e01ddbbf0f2823181beef6b39 # v1.15.0
|
||||||
with:
|
with:
|
||||||
toolchain: nightly
|
toolchain: nightly
|
||||||
components: rust-docs
|
components: rust-docs
|
||||||
|
|
@ -72,17 +72,17 @@ jobs:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
|
||||||
- name: Install Rust (${{ vars.RUST_VERSION_EXTERNAL_TYPES }})
|
- name: Install Rust (${{ vars.RUST_VERSION_EXTERNAL_TYPES }})
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@02be93da58aa71fb456aa9c43b301149248829d8 # v1.15.1
|
uses: actions-rust-lang/setup-rust-toolchain@2fcdc490d667999e01ddbbf0f2823181beef6b39 # v1.15.0
|
||||||
with:
|
with:
|
||||||
toolchain: ${{ vars.RUST_VERSION_EXTERNAL_TYPES }}
|
toolchain: ${{ vars.RUST_VERSION_EXTERNAL_TYPES }}
|
||||||
|
|
||||||
- name: Install just
|
- name: Install just
|
||||||
uses: taiki-e/install-action@efd8b64311f7a0a9b888ed13d0df78ec9184c163 # v2.62.11
|
uses: taiki-e/install-action@0e09747a63ae497bf945b3dcaf38fef0050d0109 # v2.62.0
|
||||||
with:
|
with:
|
||||||
tool: just
|
tool: just
|
||||||
|
|
||||||
- name: Install cargo-check-external-types
|
- name: Install cargo-check-external-types
|
||||||
uses: taiki-e/cache-cargo-install-action@7447f04c51f2ba27ca35e7f1e28fab848c5b3ba7 # v2.3.1
|
uses: taiki-e/cache-cargo-install-action@b33c63d3b3c85540f4eba8a4f71a5cc0ce030855 # v2.3.0
|
||||||
with:
|
with:
|
||||||
tool: cargo-check-external-types
|
tool: cargo-check-external-types
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2041,9 +2041,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.6"
|
version = "2.7.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mime"
|
name = "mime"
|
||||||
|
|
@ -2850,9 +2850,9 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.228"
|
version = "1.0.226"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_core",
|
"serde_core",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
|
|
@ -2860,18 +2860,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_core"
|
name = "serde_core"
|
||||||
version = "1.0.228"
|
version = "1.0.226"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.228"
|
version = "1.0.226"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -3081,9 +3081,9 @@ checksum = "1ac9aa371f599d22256307c24a9d748c041e548cbf599f35d890f9d365361790"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.23.0"
|
version = "3.22.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16"
|
checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"getrandom 0.3.3",
|
"getrandom 0.3.3",
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
#![warn(missing_docs, missing_debug_implementations)]
|
#![warn(missing_docs, missing_debug_implementations)]
|
||||||
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
||||||
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
||||||
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
|
||||||
#[cfg(feature = "openssl")]
|
#[cfg(feature = "openssl")]
|
||||||
extern crate tls_openssl as openssl;
|
extern crate tls_openssl as openssl;
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,8 @@
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
- Properly wake Payload receivers when feeding errors or EOF.
|
- Properly wake Payload receivers when feeding errors or EOF
|
||||||
- Add `ServiceConfigBuilder` type to facilitate future configuration extensions.
|
- Shutdown connections when HTTP Responses are written without reading full Requests
|
||||||
- Add a configuration option to allow/disallow half closed connections in HTTP/1. This defaults to allow, reverting the change made in 3.11.1.
|
|
||||||
- Shutdown connections when HTTP Responses are written without reading full Requests.
|
|
||||||
|
|
||||||
## 3.11.1
|
## 3.11.1
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
body::{BoxBody, MessageBody},
|
body::{BoxBody, MessageBody},
|
||||||
h1::{self, ExpectHandler, H1Service, UpgradeHandler},
|
h1::{self, ExpectHandler, H1Service, UpgradeHandler},
|
||||||
service::HttpService,
|
service::HttpService,
|
||||||
ConnectCallback, Extensions, KeepAlive, Request, Response, ServiceConfigBuilder,
|
ConnectCallback, Extensions, KeepAlive, Request, Response, ServiceConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An HTTP service builder.
|
/// An HTTP service builder.
|
||||||
|
|
@ -19,7 +19,6 @@ pub struct HttpServiceBuilder<T, S, X = ExpectHandler, U = UpgradeHandler> {
|
||||||
client_disconnect_timeout: Duration,
|
client_disconnect_timeout: Duration,
|
||||||
secure: bool,
|
secure: bool,
|
||||||
local_addr: Option<net::SocketAddr>,
|
local_addr: Option<net::SocketAddr>,
|
||||||
h1_allow_half_closed: bool,
|
|
||||||
expect: X,
|
expect: X,
|
||||||
upgrade: Option<U>,
|
upgrade: Option<U>,
|
||||||
on_connect_ext: Option<Rc<ConnectCallback<T>>>,
|
on_connect_ext: Option<Rc<ConnectCallback<T>>>,
|
||||||
|
|
@ -41,7 +40,6 @@ where
|
||||||
client_disconnect_timeout: Duration::ZERO,
|
client_disconnect_timeout: Duration::ZERO,
|
||||||
secure: false,
|
secure: false,
|
||||||
local_addr: None,
|
local_addr: None,
|
||||||
h1_allow_half_closed: true,
|
|
||||||
|
|
||||||
// dispatcher parts
|
// dispatcher parts
|
||||||
expect: ExpectHandler,
|
expect: ExpectHandler,
|
||||||
|
|
@ -126,18 +124,6 @@ where
|
||||||
self.client_disconnect_timeout(dur)
|
self.client_disconnect_timeout(dur)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets whether HTTP/1 connections should support half-closures.
|
|
||||||
///
|
|
||||||
/// Clients can choose to shutdown their writer-side of the connection after completing their
|
|
||||||
/// request and while waiting for the server response. Setting this to `false` will cause the
|
|
||||||
/// server to abort the connection handling as soon as it detects an EOF from the client.
|
|
||||||
///
|
|
||||||
/// The default behavior is to allow, i.e. `true`
|
|
||||||
pub fn h1_allow_half_closed(mut self, allow: bool) -> Self {
|
|
||||||
self.h1_allow_half_closed = allow;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Provide service for `EXPECT: 100-Continue` support.
|
/// Provide service for `EXPECT: 100-Continue` support.
|
||||||
///
|
///
|
||||||
/// Service get called with request that contains `EXPECT` header.
|
/// Service get called with request that contains `EXPECT` header.
|
||||||
|
|
@ -156,7 +142,6 @@ where
|
||||||
client_disconnect_timeout: self.client_disconnect_timeout,
|
client_disconnect_timeout: self.client_disconnect_timeout,
|
||||||
secure: self.secure,
|
secure: self.secure,
|
||||||
local_addr: self.local_addr,
|
local_addr: self.local_addr,
|
||||||
h1_allow_half_closed: self.h1_allow_half_closed,
|
|
||||||
expect: expect.into_factory(),
|
expect: expect.into_factory(),
|
||||||
upgrade: self.upgrade,
|
upgrade: self.upgrade,
|
||||||
on_connect_ext: self.on_connect_ext,
|
on_connect_ext: self.on_connect_ext,
|
||||||
|
|
@ -181,7 +166,6 @@ where
|
||||||
client_disconnect_timeout: self.client_disconnect_timeout,
|
client_disconnect_timeout: self.client_disconnect_timeout,
|
||||||
secure: self.secure,
|
secure: self.secure,
|
||||||
local_addr: self.local_addr,
|
local_addr: self.local_addr,
|
||||||
h1_allow_half_closed: self.h1_allow_half_closed,
|
|
||||||
expect: self.expect,
|
expect: self.expect,
|
||||||
upgrade: Some(upgrade.into_factory()),
|
upgrade: Some(upgrade.into_factory()),
|
||||||
on_connect_ext: self.on_connect_ext,
|
on_connect_ext: self.on_connect_ext,
|
||||||
|
|
@ -211,14 +195,13 @@ where
|
||||||
S::InitError: fmt::Debug,
|
S::InitError: fmt::Debug,
|
||||||
S::Response: Into<Response<B>>,
|
S::Response: Into<Response<B>>,
|
||||||
{
|
{
|
||||||
let cfg = ServiceConfigBuilder::new()
|
let cfg = ServiceConfig::new(
|
||||||
.keep_alive(self.keep_alive)
|
self.keep_alive,
|
||||||
.client_request_timeout(self.client_request_timeout)
|
self.client_request_timeout,
|
||||||
.client_disconnect_timeout(self.client_disconnect_timeout)
|
self.client_disconnect_timeout,
|
||||||
.secure(self.secure)
|
self.secure,
|
||||||
.local_addr(self.local_addr)
|
self.local_addr,
|
||||||
.h1_allow_half_closed(self.h1_allow_half_closed)
|
);
|
||||||
.build();
|
|
||||||
|
|
||||||
H1Service::with_config(cfg, service.into_factory())
|
H1Service::with_config(cfg, service.into_factory())
|
||||||
.expect(self.expect)
|
.expect(self.expect)
|
||||||
|
|
@ -237,14 +220,13 @@ where
|
||||||
|
|
||||||
B: MessageBody + 'static,
|
B: MessageBody + 'static,
|
||||||
{
|
{
|
||||||
let cfg = ServiceConfigBuilder::new()
|
let cfg = ServiceConfig::new(
|
||||||
.keep_alive(self.keep_alive)
|
self.keep_alive,
|
||||||
.client_request_timeout(self.client_request_timeout)
|
self.client_request_timeout,
|
||||||
.client_disconnect_timeout(self.client_disconnect_timeout)
|
self.client_disconnect_timeout,
|
||||||
.secure(self.secure)
|
self.secure,
|
||||||
.local_addr(self.local_addr)
|
self.local_addr,
|
||||||
.h1_allow_half_closed(self.h1_allow_half_closed)
|
);
|
||||||
.build();
|
|
||||||
|
|
||||||
crate::h2::H2Service::with_config(cfg, service.into_factory())
|
crate::h2::H2Service::with_config(cfg, service.into_factory())
|
||||||
.on_connect_ext(self.on_connect_ext)
|
.on_connect_ext(self.on_connect_ext)
|
||||||
|
|
@ -260,14 +242,13 @@ where
|
||||||
|
|
||||||
B: MessageBody + 'static,
|
B: MessageBody + 'static,
|
||||||
{
|
{
|
||||||
let cfg = ServiceConfigBuilder::new()
|
let cfg = ServiceConfig::new(
|
||||||
.keep_alive(self.keep_alive)
|
self.keep_alive,
|
||||||
.client_request_timeout(self.client_request_timeout)
|
self.client_request_timeout,
|
||||||
.client_disconnect_timeout(self.client_disconnect_timeout)
|
self.client_disconnect_timeout,
|
||||||
.secure(self.secure)
|
self.secure,
|
||||||
.local_addr(self.local_addr)
|
self.local_addr,
|
||||||
.h1_allow_half_closed(self.h1_allow_half_closed)
|
);
|
||||||
.build();
|
|
||||||
|
|
||||||
HttpService::with_config(cfg, service.into_factory())
|
HttpService::with_config(cfg, service.into_factory())
|
||||||
.expect(self.expect)
|
.expect(self.expect)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
net::SocketAddr,
|
net,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
@ -8,76 +8,8 @@ use bytes::BytesMut;
|
||||||
|
|
||||||
use crate::{date::DateService, KeepAlive};
|
use crate::{date::DateService, KeepAlive};
|
||||||
|
|
||||||
/// A builder for creating a [`ServiceConfig`]
|
|
||||||
#[derive(Default, Debug)]
|
|
||||||
pub struct ServiceConfigBuilder {
|
|
||||||
inner: Inner,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ServiceConfigBuilder {
|
|
||||||
/// Creates a new, default, [`ServiceConfigBuilder`]
|
|
||||||
///
|
|
||||||
/// It uses the following default values:
|
|
||||||
///
|
|
||||||
/// - [`KeepAlive::default`] for the connection keep-alive setting
|
|
||||||
/// - 5 seconds for the client request timeout
|
|
||||||
/// - 0 seconds for the client shutdown timeout
|
|
||||||
/// - secure value of `false`
|
|
||||||
/// - [`None`] for the local address setting
|
|
||||||
/// - Allow for half closed HTTP/1 connections
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the `secure` attribute for this configuration
|
|
||||||
pub fn secure(mut self, secure: bool) -> Self {
|
|
||||||
self.inner.secure = secure;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the local address for this configuration
|
|
||||||
pub fn local_addr(mut self, local_addr: Option<SocketAddr>) -> Self {
|
|
||||||
self.inner.local_addr = local_addr;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets connection keep-alive setting
|
|
||||||
pub fn keep_alive(mut self, keep_alive: KeepAlive) -> Self {
|
|
||||||
self.inner.keep_alive = keep_alive;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the timeout for the client to finish sending the head of its first request
|
|
||||||
pub fn client_request_timeout(mut self, timeout: Duration) -> Self {
|
|
||||||
self.inner.client_request_timeout = timeout;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the timeout for cleanly disconnecting from the client after connection shutdown has
|
|
||||||
/// started
|
|
||||||
pub fn client_disconnect_timeout(mut self, timeout: Duration) -> Self {
|
|
||||||
self.inner.client_disconnect_timeout = timeout;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets whether HTTP/1 connections should support half-closures.
|
|
||||||
///
|
|
||||||
/// Clients can choose to shutdown their writer-side of the connection after completing their
|
|
||||||
/// request and while waiting for the server response. Setting this to `false` will cause the
|
|
||||||
/// server to abort the connection handling as soon as it detects an EOF from the client
|
|
||||||
pub fn h1_allow_half_closed(mut self, allow: bool) -> Self {
|
|
||||||
self.inner.h1_allow_half_closed = allow;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Builds a [`ServiceConfig`] from this [`ServiceConfigBuilder`] instance
|
|
||||||
pub fn build(self) -> ServiceConfig {
|
|
||||||
ServiceConfig(Rc::new(self.inner))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// HTTP service configuration.
|
/// HTTP service configuration.
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ServiceConfig(Rc<Inner>);
|
pub struct ServiceConfig(Rc<Inner>);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -86,22 +18,19 @@ struct Inner {
|
||||||
client_request_timeout: Duration,
|
client_request_timeout: Duration,
|
||||||
client_disconnect_timeout: Duration,
|
client_disconnect_timeout: Duration,
|
||||||
secure: bool,
|
secure: bool,
|
||||||
local_addr: Option<SocketAddr>,
|
local_addr: Option<std::net::SocketAddr>,
|
||||||
date_service: DateService,
|
date_service: DateService,
|
||||||
h1_allow_half_closed: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Inner {
|
impl Default for ServiceConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self::new(
|
||||||
keep_alive: KeepAlive::default(),
|
KeepAlive::default(),
|
||||||
client_request_timeout: Duration::from_secs(5),
|
Duration::from_secs(5),
|
||||||
client_disconnect_timeout: Duration::ZERO,
|
Duration::ZERO,
|
||||||
secure: false,
|
false,
|
||||||
local_addr: None,
|
None,
|
||||||
date_service: DateService::new(),
|
)
|
||||||
h1_allow_half_closed: true,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -112,7 +41,7 @@ impl ServiceConfig {
|
||||||
client_request_timeout: Duration,
|
client_request_timeout: Duration,
|
||||||
client_disconnect_timeout: Duration,
|
client_disconnect_timeout: Duration,
|
||||||
secure: bool,
|
secure: bool,
|
||||||
local_addr: Option<SocketAddr>,
|
local_addr: Option<net::SocketAddr>,
|
||||||
) -> ServiceConfig {
|
) -> ServiceConfig {
|
||||||
ServiceConfig(Rc::new(Inner {
|
ServiceConfig(Rc::new(Inner {
|
||||||
keep_alive: keep_alive.normalize(),
|
keep_alive: keep_alive.normalize(),
|
||||||
|
|
@ -121,7 +50,6 @@ impl ServiceConfig {
|
||||||
secure,
|
secure,
|
||||||
local_addr,
|
local_addr,
|
||||||
date_service: DateService::new(),
|
date_service: DateService::new(),
|
||||||
h1_allow_half_closed: true,
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -135,7 +63,7 @@ impl ServiceConfig {
|
||||||
///
|
///
|
||||||
/// Returns `None` for connections via UDS (Unix Domain Socket).
|
/// Returns `None` for connections via UDS (Unix Domain Socket).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn local_addr(&self) -> Option<SocketAddr> {
|
pub fn local_addr(&self) -> Option<net::SocketAddr> {
|
||||||
self.0.local_addr
|
self.0.local_addr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -172,15 +100,6 @@ impl ServiceConfig {
|
||||||
(timeout != Duration::ZERO).then(|| self.now() + timeout)
|
(timeout != Duration::ZERO).then(|| self.now() + timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether HTTP/1 connections should support half-closures.
|
|
||||||
///
|
|
||||||
/// Clients can choose to shutdown their writer-side of the connection after completing their
|
|
||||||
/// request and while waiting for the server response. If this configuration is `false`, the
|
|
||||||
/// server will abort the connection handling as soon as it detects an EOF from the client
|
|
||||||
pub fn h1_allow_half_closed(&self) -> bool {
|
|
||||||
self.0.h1_allow_half_closed
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn now(&self) -> Instant {
|
pub(crate) fn now(&self) -> Instant {
|
||||||
self.0.date_service.now()
|
self.0.date_service.now()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1219,16 +1219,8 @@ where
|
||||||
let inner_p = inner.as_mut().project();
|
let inner_p = inner.as_mut().project();
|
||||||
let state_is_none = inner_p.state.is_none();
|
let state_is_none = inner_p.state.is_none();
|
||||||
|
|
||||||
// If the read-half is closed, we start the shutdown procedure if either is
|
// read half is closed; we do not process any responses
|
||||||
// true:
|
if inner_p.flags.contains(Flags::READ_DISCONNECT) {
|
||||||
//
|
|
||||||
// - state is [`State::None`], which means that we're done with request
|
|
||||||
// processing, so if the client closed its writer-side it means that it won't
|
|
||||||
// send more requests.
|
|
||||||
// - The user requested to not allow half-closures
|
|
||||||
if inner_p.flags.contains(Flags::READ_DISCONNECT)
|
|
||||||
&& (!inner_p.config.h1_allow_half_closed() || state_is_none)
|
|
||||||
{
|
|
||||||
trace!("read half closed; start shutdown");
|
trace!("read half closed; start shutdown");
|
||||||
inner_p.flags.insert(Flags::SHUTDOWN);
|
inner_p.flags.insert(Flags::SHUTDOWN);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,4 @@
|
||||||
use std::{
|
use std::{future::Future, str, task::Poll, time::Duration};
|
||||||
future::Future,
|
|
||||||
pin::Pin,
|
|
||||||
str,
|
|
||||||
task::{Context, Poll},
|
|
||||||
time::Duration,
|
|
||||||
};
|
|
||||||
|
|
||||||
use actix_codec::Framed;
|
use actix_codec::Framed;
|
||||||
use actix_rt::{pin, time::sleep};
|
use actix_rt::{pin, time::sleep};
|
||||||
|
|
@ -15,7 +9,7 @@ use futures_util::future::lazy;
|
||||||
|
|
||||||
use super::dispatcher::{Dispatcher, DispatcherState, DispatcherStateProj, Flags};
|
use super::dispatcher::{Dispatcher, DispatcherState, DispatcherStateProj, Flags};
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{BoxBody, MessageBody},
|
body::MessageBody,
|
||||||
config::ServiceConfig,
|
config::ServiceConfig,
|
||||||
h1::{Codec, ExpectHandler, UpgradeHandler},
|
h1::{Codec, ExpectHandler, UpgradeHandler},
|
||||||
service::HttpFlow,
|
service::HttpFlow,
|
||||||
|
|
@ -23,26 +17,6 @@ use crate::{
|
||||||
Error, HttpMessage, KeepAlive, Method, OnConnectData, Request, Response, StatusCode,
|
Error, HttpMessage, KeepAlive, Method, OnConnectData, Request, Response, StatusCode,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct YieldService;
|
|
||||||
|
|
||||||
impl Service<Request> for YieldService {
|
|
||||||
type Response = Response<BoxBody>;
|
|
||||||
type Error = Response<BoxBody>;
|
|
||||||
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
|
|
||||||
|
|
||||||
actix_service::always_ready!();
|
|
||||||
|
|
||||||
fn call(&self, _: Request) -> Self::Future {
|
|
||||||
Box::pin(async {
|
|
||||||
// Yield twice because the dispatcher can poll the service twice per dispatcher's poll:
|
|
||||||
// once in `handle_request` and another in `poll_response`
|
|
||||||
actix_rt::task::yield_now().await;
|
|
||||||
actix_rt::task::yield_now().await;
|
|
||||||
Ok(Response::ok())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_slice(haystack: &[u8], needle: &[u8], from: usize) -> Option<usize> {
|
fn find_slice(haystack: &[u8], needle: &[u8], from: usize) -> Option<usize> {
|
||||||
memchr::memmem::find(&haystack[from..], needle)
|
memchr::memmem::find(&haystack[from..], needle)
|
||||||
}
|
}
|
||||||
|
|
@ -1017,91 +991,6 @@ async fn handler_drop_payload() {
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_rt::test]
|
|
||||||
async fn allow_half_closed() {
|
|
||||||
let buf = TestSeqBuffer::new(http_msg("GET / HTTP/1.1"));
|
|
||||||
buf.close_read();
|
|
||||||
let services = HttpFlow::new(YieldService, ExpectHandler, None::<UpgradeHandler>);
|
|
||||||
|
|
||||||
let mut cx = Context::from_waker(futures_util::task::noop_waker_ref());
|
|
||||||
let disptacher = Dispatcher::new(
|
|
||||||
buf.clone(),
|
|
||||||
services,
|
|
||||||
ServiceConfig::default(),
|
|
||||||
None,
|
|
||||||
OnConnectData::default(),
|
|
||||||
);
|
|
||||||
pin!(disptacher);
|
|
||||||
|
|
||||||
assert!(disptacher.as_mut().poll(&mut cx).is_pending());
|
|
||||||
assert_eq!(disptacher.poll_count, 1);
|
|
||||||
|
|
||||||
assert!(disptacher.as_mut().poll(&mut cx).is_ready());
|
|
||||||
assert_eq!(disptacher.poll_count, 3);
|
|
||||||
|
|
||||||
let mut res = BytesMut::from(buf.take_write_buf().as_ref());
|
|
||||||
stabilize_date_header(&mut res);
|
|
||||||
let exp = http_msg(
|
|
||||||
r"
|
|
||||||
HTTP/1.1 200 OK
|
|
||||||
content-length: 0
|
|
||||||
date: Thu, 01 Jan 1970 12:34:56 UTC
|
|
||||||
",
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
res,
|
|
||||||
exp,
|
|
||||||
"\nexpected response not in write buffer:\n\
|
|
||||||
response: {:?}\n\
|
|
||||||
expected: {:?}",
|
|
||||||
String::from_utf8_lossy(&res),
|
|
||||||
String::from_utf8_lossy(&exp)
|
|
||||||
);
|
|
||||||
|
|
||||||
let DispatcherStateProj::Normal { inner } = disptacher.as_mut().project().inner.project()
|
|
||||||
else {
|
|
||||||
panic!("End dispatcher state should be Normal");
|
|
||||||
};
|
|
||||||
assert!(inner.state.is_none());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[actix_rt::test]
|
|
||||||
async fn disallow_half_closed() {
|
|
||||||
use crate::{config::ServiceConfigBuilder, h1::dispatcher::State};
|
|
||||||
|
|
||||||
let buf = TestSeqBuffer::new(http_msg("GET / HTTP/1.1"));
|
|
||||||
buf.close_read();
|
|
||||||
let services = HttpFlow::new(YieldService, ExpectHandler, None::<UpgradeHandler>);
|
|
||||||
let config = ServiceConfigBuilder::new()
|
|
||||||
.h1_allow_half_closed(false)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let mut cx = Context::from_waker(futures_util::task::noop_waker_ref());
|
|
||||||
let disptacher = Dispatcher::new(
|
|
||||||
buf.clone(),
|
|
||||||
services,
|
|
||||||
config,
|
|
||||||
None,
|
|
||||||
OnConnectData::default(),
|
|
||||||
);
|
|
||||||
pin!(disptacher);
|
|
||||||
|
|
||||||
assert!(disptacher.as_mut().poll(&mut cx).is_pending());
|
|
||||||
assert_eq!(disptacher.poll_count, 1);
|
|
||||||
|
|
||||||
assert!(disptacher.as_mut().poll(&mut cx).is_ready());
|
|
||||||
assert_eq!(disptacher.poll_count, 2);
|
|
||||||
|
|
||||||
let res = BytesMut::from(buf.take_write_buf().as_ref());
|
|
||||||
assert!(res.is_empty());
|
|
||||||
|
|
||||||
let DispatcherStateProj::Normal { inner } = disptacher.as_mut().project().inner.project()
|
|
||||||
else {
|
|
||||||
panic!("End dispatcher state should be Normal");
|
|
||||||
};
|
|
||||||
assert!(matches!(inner.state, State::ServiceCall { .. }))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn http_msg(msg: impl AsRef<str>) -> BytesMut {
|
fn http_msg(msg: impl AsRef<str>) -> BytesMut {
|
||||||
let mut msg = msg
|
let mut msg = msg
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
)]
|
)]
|
||||||
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
||||||
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
|
||||||
pub use http::{uri, uri::Uri, Method, StatusCode, Version};
|
pub use http::{uri, uri::Uri, Method, StatusCode, Version};
|
||||||
|
|
||||||
|
|
@ -63,7 +63,7 @@ pub use self::payload::PayloadStream;
|
||||||
pub use self::service::TlsAcceptorConfig;
|
pub use self::service::TlsAcceptorConfig;
|
||||||
pub use self::{
|
pub use self::{
|
||||||
builder::HttpServiceBuilder,
|
builder::HttpServiceBuilder,
|
||||||
config::{ServiceConfig, ServiceConfigBuilder},
|
config::ServiceConfig,
|
||||||
error::Error,
|
error::Error,
|
||||||
extensions::Extensions,
|
extensions::Extensions,
|
||||||
header::ContentEncoding,
|
header::ContentEncoding,
|
||||||
|
|
|
||||||
|
|
@ -275,7 +275,6 @@ impl TestSeqBuffer {
|
||||||
{
|
{
|
||||||
Self(Rc::new(RefCell::new(TestSeqInner {
|
Self(Rc::new(RefCell::new(TestSeqInner {
|
||||||
read_buf: data.into(),
|
read_buf: data.into(),
|
||||||
read_closed: false,
|
|
||||||
write_buf: BytesMut::new(),
|
write_buf: BytesMut::new(),
|
||||||
err: None,
|
err: None,
|
||||||
})))
|
})))
|
||||||
|
|
@ -294,59 +293,36 @@ impl TestSeqBuffer {
|
||||||
Ref::map(self.0.borrow(), |inner| &inner.write_buf)
|
Ref::map(self.0.borrow(), |inner| &inner.write_buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_write_buf(&self) -> Bytes {
|
|
||||||
self.0.borrow_mut().write_buf.split().freeze()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn err(&self) -> Ref<'_, Option<io::Error>> {
|
pub fn err(&self) -> Ref<'_, Option<io::Error>> {
|
||||||
Ref::map(self.0.borrow(), |inner| &inner.err)
|
Ref::map(self.0.borrow(), |inner| &inner.err)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add data to read buffer.
|
/// Add data to read buffer.
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if called after [`TestSeqBuffer::close_read`] has been called
|
|
||||||
pub fn extend_read_buf<T: AsRef<[u8]>>(&mut self, data: T) {
|
pub fn extend_read_buf<T: AsRef<[u8]>>(&mut self, data: T) {
|
||||||
let mut inner = self.0.borrow_mut();
|
self.0
|
||||||
if inner.read_closed {
|
.borrow_mut()
|
||||||
panic!("Tried to extend the read buffer after calling close_read");
|
.read_buf
|
||||||
}
|
.extend_from_slice(data.as_ref())
|
||||||
|
|
||||||
inner.read_buf.extend_from_slice(data.as_ref())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Closes the [`AsyncRead`]/[`Read`] part of this test buffer.
|
|
||||||
///
|
|
||||||
/// The current data in the buffer will still be returned by a call to read/poll_read, however,
|
|
||||||
/// after the buffer is empty, it will return `Ok(0)` to signify the EOF condition
|
|
||||||
pub fn close_read(&self) {
|
|
||||||
self.0.borrow_mut().read_closed = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TestSeqInner {
|
pub struct TestSeqInner {
|
||||||
read_buf: BytesMut,
|
read_buf: BytesMut,
|
||||||
read_closed: bool,
|
|
||||||
write_buf: BytesMut,
|
write_buf: BytesMut,
|
||||||
err: Option<io::Error>,
|
err: Option<io::Error>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl io::Read for TestSeqBuffer {
|
impl io::Read for TestSeqBuffer {
|
||||||
fn read(&mut self, dst: &mut [u8]) -> Result<usize, io::Error> {
|
fn read(&mut self, dst: &mut [u8]) -> Result<usize, io::Error> {
|
||||||
let mut inner = self.0.borrow_mut();
|
if self.0.borrow().read_buf.is_empty() {
|
||||||
|
if self.0.borrow().err.is_some() {
|
||||||
if inner.read_buf.is_empty() {
|
Err(self.0.borrow_mut().err.take().unwrap())
|
||||||
if let Some(err) = inner.err.take() {
|
|
||||||
Err(err)
|
|
||||||
} else if inner.read_closed {
|
|
||||||
Ok(0)
|
|
||||||
} else {
|
} else {
|
||||||
Err(io::Error::new(io::ErrorKind::WouldBlock, ""))
|
Err(io::Error::new(io::ErrorKind::WouldBlock, ""))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let size = std::cmp::min(inner.read_buf.len(), dst.len());
|
let size = std::cmp::min(self.0.borrow().read_buf.len(), dst.len());
|
||||||
let b = inner.read_buf.split_to(size);
|
let b = self.0.borrow_mut().read_buf.split_to(size);
|
||||||
dst[..size].copy_from_slice(&b);
|
dst[..size].copy_from_slice(&b);
|
||||||
Ok(size)
|
Ok(size)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
||||||
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
#![allow(clippy::disallowed_names)] // false positives in some macro expansions
|
#![allow(clippy::disallowed_names)] // false positives in some macro expansions
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@
|
||||||
|
|
||||||
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
||||||
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
|
||||||
// This allows us to use the actix_multipart_derive within this crate's tests
|
// This allows us to use the actix_multipart_derive within this crate's tests
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
||||||
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
|
||||||
mod de;
|
mod de;
|
||||||
mod path;
|
mod path;
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
||||||
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
|
||||||
#[cfg(feature = "openssl")]
|
#[cfg(feature = "openssl")]
|
||||||
extern crate tls_openssl as openssl;
|
extern crate tls_openssl as openssl;
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@
|
||||||
|
|
||||||
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
||||||
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
|
||||||
mod context;
|
mod context;
|
||||||
pub mod ws;
|
pub mod ws;
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@
|
||||||
#![recursion_limit = "512"]
|
#![recursion_limit = "512"]
|
||||||
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
||||||
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@
|
||||||
|
|
||||||
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
||||||
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
|
||||||
pub use actix_http::{body, HttpMessage};
|
pub use actix_http::{body, HttpMessage};
|
||||||
#[cfg(feature = "cookies")]
|
#[cfg(feature = "cookies")]
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ struct Config {
|
||||||
keep_alive: KeepAlive,
|
keep_alive: KeepAlive,
|
||||||
client_request_timeout: Duration,
|
client_request_timeout: Duration,
|
||||||
client_disconnect_timeout: Duration,
|
client_disconnect_timeout: Duration,
|
||||||
h1_allow_half_closed: bool,
|
|
||||||
#[allow(dead_code)] // only dead when no TLS features are enabled
|
#[allow(dead_code)] // only dead when no TLS features are enabled
|
||||||
tls_handshake_timeout: Option<Duration>,
|
tls_handshake_timeout: Option<Duration>,
|
||||||
}
|
}
|
||||||
|
|
@ -117,7 +116,6 @@ where
|
||||||
keep_alive: KeepAlive::default(),
|
keep_alive: KeepAlive::default(),
|
||||||
client_request_timeout: Duration::from_secs(5),
|
client_request_timeout: Duration::from_secs(5),
|
||||||
client_disconnect_timeout: Duration::from_secs(1),
|
client_disconnect_timeout: Duration::from_secs(1),
|
||||||
h1_allow_half_closed: true,
|
|
||||||
tls_handshake_timeout: None,
|
tls_handshake_timeout: None,
|
||||||
})),
|
})),
|
||||||
backlog: 1024,
|
backlog: 1024,
|
||||||
|
|
@ -259,18 +257,6 @@ where
|
||||||
self.client_disconnect_timeout(Duration::from_millis(dur))
|
self.client_disconnect_timeout(Duration::from_millis(dur))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets whether HTTP/1 connections should support half-closures.
|
|
||||||
///
|
|
||||||
/// Clients can choose to shutdown their writer-side of the connection after completing their
|
|
||||||
/// request and while waiting for the server response. Setting this to `false` will cause the
|
|
||||||
/// server to abort the connection handling as soon as it detects an EOF from the client.
|
|
||||||
///
|
|
||||||
/// The default behavior is to allow, i.e. `true`
|
|
||||||
pub fn h1_allow_half_closed(self, allow: bool) -> Self {
|
|
||||||
self.config.lock().unwrap().h1_allow_half_closed = allow;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets function that will be called once before each connection is handled.
|
/// Sets function that will be called once before each connection is handled.
|
||||||
///
|
///
|
||||||
/// It will receive a `&std::any::Any`, which contains underlying connection type and an
|
/// It will receive a `&std::any::Any`, which contains underlying connection type and an
|
||||||
|
|
@ -572,7 +558,6 @@ where
|
||||||
.keep_alive(cfg.keep_alive)
|
.keep_alive(cfg.keep_alive)
|
||||||
.client_request_timeout(cfg.client_request_timeout)
|
.client_request_timeout(cfg.client_request_timeout)
|
||||||
.client_disconnect_timeout(cfg.client_disconnect_timeout)
|
.client_disconnect_timeout(cfg.client_disconnect_timeout)
|
||||||
.h1_allow_half_closed(cfg.h1_allow_half_closed)
|
|
||||||
.local_addr(addr);
|
.local_addr(addr);
|
||||||
|
|
||||||
if let Some(handler) = on_connect_fn.clone() {
|
if let Some(handler) = on_connect_fn.clone() {
|
||||||
|
|
@ -617,7 +602,6 @@ where
|
||||||
.keep_alive(cfg.keep_alive)
|
.keep_alive(cfg.keep_alive)
|
||||||
.client_request_timeout(cfg.client_request_timeout)
|
.client_request_timeout(cfg.client_request_timeout)
|
||||||
.client_disconnect_timeout(cfg.client_disconnect_timeout)
|
.client_disconnect_timeout(cfg.client_disconnect_timeout)
|
||||||
.h1_allow_half_closed(cfg.h1_allow_half_closed)
|
|
||||||
.local_addr(addr);
|
.local_addr(addr);
|
||||||
|
|
||||||
if let Some(handler) = on_connect_fn.clone() {
|
if let Some(handler) = on_connect_fn.clone() {
|
||||||
|
|
@ -693,7 +677,6 @@ where
|
||||||
let svc = HttpService::build()
|
let svc = HttpService::build()
|
||||||
.keep_alive(c.keep_alive)
|
.keep_alive(c.keep_alive)
|
||||||
.client_request_timeout(c.client_request_timeout)
|
.client_request_timeout(c.client_request_timeout)
|
||||||
.h1_allow_half_closed(c.h1_allow_half_closed)
|
|
||||||
.client_disconnect_timeout(c.client_disconnect_timeout);
|
.client_disconnect_timeout(c.client_disconnect_timeout);
|
||||||
|
|
||||||
let svc = if let Some(handler) = on_connect_fn.clone() {
|
let svc = if let Some(handler) = on_connect_fn.clone() {
|
||||||
|
|
@ -745,7 +728,6 @@ where
|
||||||
let svc = HttpService::build()
|
let svc = HttpService::build()
|
||||||
.keep_alive(c.keep_alive)
|
.keep_alive(c.keep_alive)
|
||||||
.client_request_timeout(c.client_request_timeout)
|
.client_request_timeout(c.client_request_timeout)
|
||||||
.h1_allow_half_closed(c.h1_allow_half_closed)
|
|
||||||
.client_disconnect_timeout(c.client_disconnect_timeout);
|
.client_disconnect_timeout(c.client_disconnect_timeout);
|
||||||
|
|
||||||
let svc = if let Some(handler) = on_connect_fn.clone() {
|
let svc = if let Some(handler) = on_connect_fn.clone() {
|
||||||
|
|
@ -812,7 +794,6 @@ where
|
||||||
let svc = HttpService::build()
|
let svc = HttpService::build()
|
||||||
.keep_alive(c.keep_alive)
|
.keep_alive(c.keep_alive)
|
||||||
.client_request_timeout(c.client_request_timeout)
|
.client_request_timeout(c.client_request_timeout)
|
||||||
.h1_allow_half_closed(c.h1_allow_half_closed)
|
|
||||||
.client_disconnect_timeout(c.client_disconnect_timeout);
|
.client_disconnect_timeout(c.client_disconnect_timeout);
|
||||||
|
|
||||||
let svc = if let Some(handler) = on_connect_fn.clone() {
|
let svc = if let Some(handler) = on_connect_fn.clone() {
|
||||||
|
|
@ -879,7 +860,6 @@ where
|
||||||
let svc = HttpService::build()
|
let svc = HttpService::build()
|
||||||
.keep_alive(c.keep_alive)
|
.keep_alive(c.keep_alive)
|
||||||
.client_request_timeout(c.client_request_timeout)
|
.client_request_timeout(c.client_request_timeout)
|
||||||
.h1_allow_half_closed(c.h1_allow_half_closed)
|
|
||||||
.client_disconnect_timeout(c.client_disconnect_timeout);
|
.client_disconnect_timeout(c.client_disconnect_timeout);
|
||||||
|
|
||||||
let svc = if let Some(handler) = on_connect_fn.clone() {
|
let svc = if let Some(handler) = on_connect_fn.clone() {
|
||||||
|
|
@ -947,7 +927,6 @@ where
|
||||||
.keep_alive(c.keep_alive)
|
.keep_alive(c.keep_alive)
|
||||||
.client_request_timeout(c.client_request_timeout)
|
.client_request_timeout(c.client_request_timeout)
|
||||||
.client_disconnect_timeout(c.client_disconnect_timeout)
|
.client_disconnect_timeout(c.client_disconnect_timeout)
|
||||||
.h1_allow_half_closed(c.h1_allow_half_closed)
|
|
||||||
.local_addr(addr);
|
.local_addr(addr);
|
||||||
|
|
||||||
let svc = if let Some(handler) = on_connect_fn.clone() {
|
let svc = if let Some(handler) = on_connect_fn.clone() {
|
||||||
|
|
@ -1016,7 +995,6 @@ where
|
||||||
.keep_alive(c.keep_alive)
|
.keep_alive(c.keep_alive)
|
||||||
.client_request_timeout(c.client_request_timeout)
|
.client_request_timeout(c.client_request_timeout)
|
||||||
.client_disconnect_timeout(c.client_disconnect_timeout)
|
.client_disconnect_timeout(c.client_disconnect_timeout)
|
||||||
.h1_allow_half_closed(c.h1_allow_half_closed)
|
|
||||||
.finish(map_config(fac, move |_| config.clone())),
|
.finish(map_config(fac, move |_| config.clone())),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
@ -1058,7 +1036,6 @@ where
|
||||||
let mut svc = HttpService::build()
|
let mut svc = HttpService::build()
|
||||||
.keep_alive(c.keep_alive)
|
.keep_alive(c.keep_alive)
|
||||||
.client_request_timeout(c.client_request_timeout)
|
.client_request_timeout(c.client_request_timeout)
|
||||||
.h1_allow_half_closed(c.h1_allow_half_closed)
|
|
||||||
.client_disconnect_timeout(c.client_disconnect_timeout);
|
.client_disconnect_timeout(c.client_disconnect_timeout);
|
||||||
|
|
||||||
if let Some(handler) = on_connect_fn.clone() {
|
if let Some(handler) = on_connect_fn.clone() {
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@
|
||||||
)]
|
)]
|
||||||
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
||||||
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
|
||||||
pub use actix_http::body;
|
pub use actix_http::body;
|
||||||
#[cfg(feature = "cookies")]
|
#[cfg(feature = "cookies")]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue