1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-09-02 17:46:38 +02:00

Compare commits

..

1 Commits

Author SHA1 Message Date
Rob Ede
d1f8cbc1a8 feat: PROXYv1 wrapper 2025-08-30 02:59:20 +01:00
11 changed files with 312 additions and 30 deletions

View File

@@ -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@ac90e63697ac2784f4ecfe2964e1a285c304003a # v1.14.1 uses: actions-rust-lang/setup-rust-toolchain@ab6845274e2ff01cd4462007e1a9d9df1ab49f42 # v1.14.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@14083e64ac8cf1f5e54356df00b9779b23e192a1 # v2.58.29 uses: taiki-e/install-action@f63c33fd96cc1e69a29bafd06541cf28588b43a4 # v2.58.21
with: with:
tool: just,cargo-hack,cargo-nextest,cargo-ci-cache-clean tool: just,cargo-hack,cargo-nextest,cargo-ci-cache-clean
@@ -77,13 +77,13 @@ jobs:
run: ./scripts/free-disk-space.sh run: ./scripts/free-disk-space.sh
- name: Setup mold linker - name: Setup mold linker
uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1 uses: rui314/setup-mold@7344740a9418dcdcb481c7df83d9fbd1d5072d7d # v1
- name: Install Rust - name: Install Rust
uses: actions-rust-lang/setup-rust-toolchain@ac90e63697ac2784f4ecfe2964e1a285c304003a # v1.14.1 uses: actions-rust-lang/setup-rust-toolchain@ab6845274e2ff01cd4462007e1a9d9df1ab49f42 # v1.14.0
- name: Install just, cargo-hack - name: Install just, cargo-hack
uses: taiki-e/install-action@14083e64ac8cf1f5e54356df00b9779b23e192a1 # v2.58.29 uses: taiki-e/install-action@f63c33fd96cc1e69a29bafd06541cf28588b43a4 # v2.58.21
with: with:
tool: just,cargo-hack tool: just,cargo-hack

View File

@@ -56,15 +56,15 @@ jobs:
- name: Setup mold linker - name: Setup mold linker
if: matrix.target.os == 'ubuntu-latest' if: matrix.target.os == 'ubuntu-latest'
uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1 uses: rui314/setup-mold@7344740a9418dcdcb481c7df83d9fbd1d5072d7d # v1
- name: Install Rust (${{ matrix.version.name }}) - name: Install Rust (${{ matrix.version.name }})
uses: actions-rust-lang/setup-rust-toolchain@ac90e63697ac2784f4ecfe2964e1a285c304003a # v1.14.1 uses: actions-rust-lang/setup-rust-toolchain@ab6845274e2ff01cd4462007e1a9d9df1ab49f42 # v1.14.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@14083e64ac8cf1f5e54356df00b9779b23e192a1 # v2.58.29 uses: taiki-e/install-action@f63c33fd96cc1e69a29bafd06541cf28588b43a4 # v2.58.21
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@ac90e63697ac2784f4ecfe2964e1a285c304003a # v1.14.1 uses: actions-rust-lang/setup-rust-toolchain@ab6845274e2ff01cd4462007e1a9d9df1ab49f42 # v1.14.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@ac90e63697ac2784f4ecfe2964e1a285c304003a # v1.14.1 uses: actions-rust-lang/setup-rust-toolchain@ab6845274e2ff01cd4462007e1a9d9df1ab49f42 # v1.14.0
with: with:
toolchain: nightly toolchain: nightly
- name: Install just - name: Install just
uses: taiki-e/install-action@14083e64ac8cf1f5e54356df00b9779b23e192a1 # v2.58.29 uses: taiki-e/install-action@f63c33fd96cc1e69a29bafd06541cf28588b43a4 # v2.58.21
with: with:
tool: just tool: just

View File

@@ -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@ac90e63697ac2784f4ecfe2964e1a285c304003a # v1.14.1 uses: actions-rust-lang/setup-rust-toolchain@ab6845274e2ff01cd4462007e1a9d9df1ab49f42 # v1.14.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@14083e64ac8cf1f5e54356df00b9779b23e192a1 # v2.58.29 uses: taiki-e/install-action@f63c33fd96cc1e69a29bafd06541cf28588b43a4 # v2.58.21
with: with:
tool: just,cargo-llvm-cov,cargo-nextest tool: just,cargo-llvm-cov,cargo-nextest

View File

@@ -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@ac90e63697ac2784f4ecfe2964e1a285c304003a # v1.14.1 uses: actions-rust-lang/setup-rust-toolchain@ab6845274e2ff01cd4462007e1a9d9df1ab49f42 # v1.14.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@ac90e63697ac2784f4ecfe2964e1a285c304003a # v1.14.1 uses: actions-rust-lang/setup-rust-toolchain@ab6845274e2ff01cd4462007e1a9d9df1ab49f42 # v1.14.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@ac90e63697ac2784f4ecfe2964e1a285c304003a # v1.14.1 uses: actions-rust-lang/setup-rust-toolchain@ab6845274e2ff01cd4462007e1a9d9df1ab49f42 # v1.14.0
with: with:
toolchain: nightly toolchain: nightly
components: rust-docs components: rust-docs
@@ -72,12 +72,12 @@ 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@ac90e63697ac2784f4ecfe2964e1a285c304003a # v1.14.1 uses: actions-rust-lang/setup-rust-toolchain@ab6845274e2ff01cd4462007e1a9d9df1ab49f42 # v1.14.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@14083e64ac8cf1f5e54356df00b9779b23e192a1 # v2.58.29 uses: taiki-e/install-action@f63c33fd96cc1e69a29bafd06541cf28588b43a4 # v2.58.21
with: with:
tool: just tool: just

67
Cargo.lock generated
View File

@@ -75,6 +75,7 @@ version = "3.11.1"
dependencies = [ dependencies = [
"actix-codec", "actix-codec",
"actix-http-test", "actix-http-test",
"actix-proxy-protocol",
"actix-rt", "actix-rt",
"actix-server", "actix-server",
"actix-service", "actix-service",
@@ -105,6 +106,7 @@ dependencies = [
"local-channel", "local-channel",
"memchr", "memchr",
"mime", "mime",
"nom 8.0.0",
"once_cell", "once_cell",
"openssl", "openssl",
"percent-encoding", "percent-encoding",
@@ -222,6 +224,27 @@ dependencies = [
"thiserror", "thiserror",
] ]
[[package]]
name = "actix-proxy-protocol"
version = "0.0.2"
dependencies = [
"actix-rt",
"actix-service",
"actix-utils",
"arrayvec",
"bitflags 2.9.3",
"crc32fast",
"futures-core",
"futures-util",
"impl-more 0.3.1",
"itoa",
"nom 8.0.0",
"pin-project-lite",
"smallvec",
"tokio",
"tracing",
]
[[package]] [[package]]
name = "actix-router" name = "actix-router"
version = "0.5.3" version = "0.5.3"
@@ -315,7 +338,7 @@ dependencies = [
"futures-core", "futures-core",
"http 0.2.12", "http 0.2.12",
"http 1.3.1", "http 1.3.1",
"impl-more", "impl-more 0.1.9",
"openssl", "openssl",
"pin-project-lite", "pin-project-lite",
"rustls-native-certs", "rustls-native-certs",
@@ -375,7 +398,7 @@ dependencies = [
"foldhash", "foldhash",
"futures-core", "futures-core",
"futures-util", "futures-util",
"impl-more", "impl-more 0.1.9",
"itoa", "itoa",
"language-tags", "language-tags",
"log", "log",
@@ -573,6 +596,12 @@ dependencies = [
"windows-sys 0.60.2", "windows-sys 0.60.2",
] ]
[[package]]
name = "arrayvec"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]] [[package]]
name = "assert_matches" name = "assert_matches"
version = "1.5.0" version = "1.5.0"
@@ -832,7 +861,7 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [ dependencies = [
"nom", "nom 7.1.3",
] ]
[[package]] [[package]]
@@ -1160,9 +1189,9 @@ checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476"
[[package]] [[package]]
name = "deranged" name = "deranged"
version = "0.5.3" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
dependencies = [ dependencies = [
"powerfmt", "powerfmt",
] ]
@@ -1750,6 +1779,12 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2"
[[package]]
name = "impl-more"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35a84fd5aa25fae5c0f4a33d9cac2ca017fc622cbd089be2229993514990f870"
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.11.0" version = "2.11.0"
@@ -2069,6 +2104,15 @@ dependencies = [
"minimal-lexical", "minimal-lexical",
] ]
[[package]]
name = "nom"
version = "8.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "num-conv" name = "num-conv"
version = "0.1.0" version = "0.1.0"
@@ -3021,11 +3065,12 @@ dependencies = [
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.42" version = "0.3.41"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ca967379f9d8eb8058d86ed467d81d03e81acd45757e4ca341c24affbe8e8e3" checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
dependencies = [ dependencies = [
"deranged", "deranged",
"itoa",
"num-conv", "num-conv",
"powerfmt", "powerfmt",
"serde", "serde",
@@ -3035,15 +3080,15 @@ dependencies = [
[[package]] [[package]]
name = "time-core" name = "time-core"
version = "0.1.5" version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9108bb380861b07264b950ded55a44a14a4adc68b9f5efd85aafc3aa4d40a68" checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
[[package]] [[package]]
name = "time-macros" name = "time-macros"
version = "0.2.23" version = "0.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7182799245a7264ce590b349d90338f1c1affad93d2639aed5f8f69c090b334c" checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
dependencies = [ dependencies = [
"num-conv", "num-conv",
"time-core", "time-core",

View File

@@ -60,6 +60,9 @@ http2 = ["dep:h2"]
# WebSocket protocol implementation # WebSocket protocol implementation
ws = ["dep:local-channel", "dep:base64", "dep:rand", "dep:sha1"] ws = ["dep:local-channel", "dep:base64", "dep:rand", "dep:sha1"]
# HAProxy PROXY protocol support
haproxy = ["dep:nom"]
# TLS via OpenSSL # TLS via OpenSSL
openssl = ["__tls", "actix-tls/accept", "actix-tls/openssl"] openssl = ["__tls", "actix-tls/accept", "actix-tls/openssl"]
@@ -93,6 +96,8 @@ __tls = []
[dependencies] [dependencies]
actix-codec = "0.5" actix-codec = "0.5"
# actix-proxy-protocol = "0.0.2"
actix-proxy-protocol = { path = "../../actix-web-lab/actix-proxy-protocol" }
actix-rt = { version = "2.2", default-features = false } actix-rt = { version = "2.2", default-features = false }
actix-service = "2" actix-service = "2"
actix-utils = "3" actix-utils = "3"
@@ -104,6 +109,7 @@ derive_more = { version = "2", features = ["as_ref", "deref", "deref_mut", "disp
encoding_rs = "0.8" encoding_rs = "0.8"
foldhash = "0.1" foldhash = "0.1"
futures-core = { version = "0.3.17", default-features = false, features = ["alloc"] } futures-core = { version = "0.3.17", default-features = false, features = ["alloc"] }
futures-util = { version = "0.3.17", default-features = false, features = ["alloc"] }
http = "0.2.7" http = "0.2.7"
httparse = "1.5.1" httparse = "1.5.1"
httpdate = "1.0.1" httpdate = "1.0.1"
@@ -126,6 +132,9 @@ local-channel = { version = "0.1", optional = true }
rand = { version = "0.9", optional = true } rand = { version = "0.9", optional = true }
sha1 = { version = "0.10", optional = true } sha1 = { version = "0.10", optional = true }
# proxy
nom = { version = "8", optional = true }
# openssl/rustls # openssl/rustls
actix-tls = { version = "3.4", default-features = false, optional = true } actix-tls = { version = "3.4", default-features = false, optional = true }
@@ -165,6 +174,10 @@ workspace = true
name = "ws" name = "ws"
required-features = ["ws", "rustls-0_23"] required-features = ["ws", "rustls-0_23"]
[[example]]
name = "haproxy"
required-features = ["http2", "haproxy"]
[[example]] [[example]]
name = "tls_rustls" name = "tls_rustls"
required-features = ["http2", "rustls-0_23"] required-features = ["http2", "rustls-0_23"]

View File

@@ -0,0 +1,45 @@
use std::{io, time::Duration};
use actix_http::{Error, HttpService, Request, Response, StatusCode};
use actix_server::Server;
use bytes::BytesMut;
use futures_util::StreamExt as _;
use http::header::HeaderValue;
use tracing::info;
#[actix_rt::main]
async fn main() -> io::Result<()> {
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
Server::build()
.bind("echo", ("127.0.0.1", 8080), || {
HttpService::build()
.client_request_timeout(Duration::from_secs(20))
.client_disconnect_timeout(Duration::from_secs(20))
.finish(|mut req: Request| async move {
let mut body = BytesMut::new();
while let Some(item) = req.payload().next().await {
body.extend_from_slice(&item?);
}
info!("request body: {body:?}");
let res = Response::build(StatusCode::OK)
.insert_header(("x-head", HeaderValue::from_static("dummy value!")))
.body(body);
Ok::<_, Error>(res)
})
.tcp_auto_h2c_proxy_protocol_v1()
})?
.workers(2)
.run()
.await
}
static_assertions::assert_impl_all!(
tokio::io::BufReader<tokio::net::TcpStream>:
tokio::io::AsyncRead,
tokio::io::AsyncWrite,
Unpin,
);

View File

@@ -993,6 +993,8 @@ where
Poll::Ready(Ok(n)) => { Poll::Ready(Ok(n)) => {
this.flags.remove(Flags::FINISHED); this.flags.remove(Flags::FINISHED);
eprintln!("readbuf contents: {:?}", this.read_buf);
if n == 0 { if n == 0 {
return Ok(true); return Ok(true);
} }

View File

@@ -91,6 +91,59 @@ where
} }
} }
#[cfg(feature = "haproxy")]
impl<S, B, X, U> H1Service<actix_proxy_protocol::v1::TlsStream<TcpStream>, S, B, X, U>
where
S: ServiceFactory<Request, Config = ()>,
S::Future: 'static,
S::Error: Into<Response<BoxBody>>,
S::InitError: fmt::Debug,
S::Response: Into<Response<B>>,
B: MessageBody,
X: ServiceFactory<Request, Config = (), Response = Request>,
X::Future: 'static,
X::Error: Into<Response<BoxBody>>,
X::InitError: fmt::Debug,
U: ServiceFactory<
(
Request,
Framed<actix_proxy_protocol::v1::TlsStream<TcpStream>, Codec>,
),
Config = (),
Response = (),
>,
U::Future: 'static,
U::Error: fmt::Display + Into<Response<BoxBody>>,
U::InitError: fmt::Debug,
{
/// Creates TCP stream service from HTTP service that consumes PROXY protocol v1 headers first.
///
/// The connection info obtained from the PROXY header.
pub fn tcp_proxy_protocol_v1(
self,
) -> impl ServiceFactory<
TcpStream,
Config = (),
Response = (),
Error = actix_proxy_protocol::v1::TlsError<std::io::Error, DispatchError>,
InitError = (),
> {
use actix_proxy_protocol::v1::{TlsError, TlsStream};
actix_proxy_protocol::v1::Acceptor::new()
.map_init_err(|_| unreachable!("TLS acceptor service factory does not error on init"))
.map_err(TlsError::into_service_error)
.map(|io: TlsStream<TcpStream>| {
let peer_addr = io.0.get_ref().peer_addr().ok();
(io, peer_addr)
})
.and_then(self.map_err(TlsError::Service))
}
}
#[cfg(feature = "openssl")] #[cfg(feature = "openssl")]
mod openssl { mod openssl {
use actix_tls::accept::{ use actix_tls::accept::{

View File

@@ -240,6 +240,131 @@ where
} }
} }
#[cfg(feature = "haproxy")]
impl<S, B, X, U> HttpService<actix_proxy_protocol::v1::TlsStream<TcpStream>, S, B, X, U>
where
S: ServiceFactory<Request, Config = ()>,
S::Future: 'static,
S::Error: Into<Response<BoxBody>> + 'static,
S::InitError: fmt::Debug,
S::Response: Into<Response<B>> + 'static,
<S::Service as Service<Request>>::Future: 'static,
B: MessageBody + 'static,
X: ServiceFactory<Request, Config = (), Response = Request>,
X::Future: 'static,
X::Error: Into<Response<BoxBody>>,
X::InitError: fmt::Debug,
U: ServiceFactory<
(
Request,
Framed<actix_proxy_protocol::v1::TlsStream<TcpStream>, h1::Codec>,
),
Config = (),
Response = (),
>,
U::Future: 'static,
U::Error: fmt::Display + Into<Response<BoxBody>>,
U::InitError: fmt::Debug,
{
/// Creates TCP stream service from HTTP service that consumes PROXY protocol v1 headers first.
///
/// The connection info obtained from the PROXY header.
pub fn tcp_proxy_protocol_v1(
self,
) -> impl ServiceFactory<
TcpStream,
Config = (),
Response = (),
Error = actix_proxy_protocol::v1::TlsError<std::io::Error, DispatchError>,
InitError = (),
> {
use actix_proxy_protocol::v1::{TlsError, TlsStream};
actix_proxy_protocol::v1::Acceptor::new()
.map_init_err(|_| unreachable!("TLS acceptor service factory does not error on init"))
.map_err(TlsError::into_service_error)
.map(|io: TlsStream<TcpStream>| {
let peer_addr = io.0.get_ref().peer_addr().ok();
(io, Protocol::Http1, peer_addr)
})
.and_then(self.map_err(TlsError::Service))
}
}
#[cfg(feature = "haproxy")]
impl<S, B, X, U> HttpService<actix_proxy_protocol::v1::TlsStream<TcpStream>, S, B, X, U>
where
S: ServiceFactory<Request, Config = ()>,
S::Future: 'static,
S::Error: Into<Response<BoxBody>> + 'static,
S::InitError: fmt::Debug,
S::Response: Into<Response<B>> + 'static,
<S::Service as Service<Request>>::Future: 'static,
B: MessageBody + 'static,
X: ServiceFactory<Request, Config = (), Response = Request>,
X::Future: 'static,
X::Error: Into<Response<BoxBody>>,
X::InitError: fmt::Debug,
U: ServiceFactory<
(
Request,
Framed<actix_proxy_protocol::v1::TlsStream<TcpStream>, h1::Codec>,
),
Config = (),
Response = (),
>,
U::Future: 'static,
U::Error: fmt::Display + Into<Response<BoxBody>>,
U::InitError: fmt::Debug,
{
/// Creates TCP stream service from HTTP service that consumes PROXY protocol v1 headers first.
///
/// The connection info obtained from the PROXY header.
pub fn tcp_auto_h2c_proxy_protocol_v1(
self,
) -> impl ServiceFactory<
TcpStream,
Config = (),
Response = (),
Error = actix_proxy_protocol::v1::TlsError<std::io::Error, DispatchError>,
InitError = (),
> {
use actix_proxy_protocol::v1::{TlsError, TlsStream};
actix_proxy_protocol::v1::Acceptor::new()
.map_init_err(|_| unreachable!("TLS acceptor service factory does not error on init"))
.map_err(TlsError::into_service_error)
.and_then(fn_service(move |io: TlsStream<TcpStream>| async move {
// subset of HTTP/2 preface defined by RFC 9113 §3.4
// this subset was chosen to maximize likelihood that peeking only once will allow us to
// reliably determine version or else it should fallback to h1 and fail quickly if data
// on the wire is junk
const H2_PREFACE: &[u8] = b"PRI * HTTP/2";
let mut buf = [0; 12];
// TODO: cannot peak into a bufreader
io.0.get_ref().peek(&mut buf).await.map_err(TlsError::Tls)?;
let proto = if buf == H2_PREFACE {
Protocol::Http2
} else {
Protocol::Http1
};
let peer_addr = io.0.get_ref().peer_addr().ok();
Ok((io, proto, peer_addr))
}))
.and_then(self.map_err(TlsError::Service))
}
}
/// Configuration options used when accepting TLS connection. /// Configuration options used when accepting TLS connection.
#[cfg(feature = "__tls")] #[cfg(feature = "__tls")]
#[derive(Debug, Default)] #[derive(Debug, Default)]

View File

@@ -16,7 +16,6 @@ Middleware is registered for each App, Scope, or Resource and executed in the re
Actix Web's middleware system is built on two main traits: Actix Web's middleware system is built on two main traits:
1. `Transform<S, Req>`: The builder trait that creates the actual Service. It's responsible for: 1. `Transform<S, Req>`: The builder trait that creates the actual Service. It's responsible for:
- Creating new middleware instances - Creating new middleware instances
- Assembling the middleware chain - Assembling the middleware chain
- Handling initialization errors - Handling initialization errors