mirror of
https://github.com/fafhrd91/actix-web
synced 2025-08-07 15:32:57 +02:00
Compare commits
12 Commits
web-v4.7.0
...
error-resp
Author | SHA1 | Date | |
---|---|---|---|
|
eb10b74751 | ||
|
a2b9823d9d | ||
|
da56de4556 | ||
|
758ae1dac1 | ||
|
37577dcb89 | ||
|
8b8eb4eae1 | ||
|
22593a1532 | ||
|
f7646bcc48 | ||
|
8018983a68 | ||
|
266834cf7c | ||
|
40e1034566 | ||
|
98c99f3bc2 |
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
## 0.6.6
|
||||||
|
|
||||||
|
- Update `tokio-uring` dependency to `0.4`.
|
||||||
- Minimum supported Rust version (MSRV) is now 1.72.
|
- Minimum supported Rust version (MSRV) is now 1.72.
|
||||||
|
|
||||||
## 0.6.5
|
## 0.6.5
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "actix-files"
|
name = "actix-files"
|
||||||
version = "0.6.5"
|
version = "0.6.6"
|
||||||
authors = [
|
authors = [
|
||||||
"Nikolay Kim <fafhrd91@gmail.com>",
|
"Nikolay Kim <fafhrd91@gmail.com>",
|
||||||
"Rob Ede <robjtede@icloud.com>",
|
"Rob Ede <robjtede@icloud.com>",
|
||||||
@@ -40,8 +40,8 @@ v_htmlescape = "0.15.5"
|
|||||||
|
|
||||||
# experimental-io-uring
|
# experimental-io-uring
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
tokio-uring = { version = "0.4", optional = true, features = ["bytes"] }
|
tokio-uring = { version = "0.5", optional = true, features = ["bytes"] }
|
||||||
actix-server = { version = "2.2", optional = true } # ensure matching tokio-uring versions
|
actix-server = { version = "2.4", optional = true } # ensure matching tokio-uring versions
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix-rt = "2.7"
|
actix-rt = "2.7"
|
||||||
|
@@ -3,11 +3,11 @@
|
|||||||
<!-- prettier-ignore-start -->
|
<!-- prettier-ignore-start -->
|
||||||
|
|
||||||
[](https://crates.io/crates/actix-files)
|
[](https://crates.io/crates/actix-files)
|
||||||
[](https://docs.rs/actix-files/0.6.5)
|
[](https://docs.rs/actix-files/0.6.6)
|
||||||

|

|
||||||

|

|
||||||
<br />
|
<br />
|
||||||
[](https://deps.rs/crate/actix-files/0.6.5)
|
[](https://deps.rs/crate/actix-files/0.6.6)
|
||||||
[](https://crates.io/crates/actix-files)
|
[](https://crates.io/crates/actix-files)
|
||||||
[](https://discord.gg/NWpN5mmg3x)
|
[](https://discord.gg/NWpN5mmg3x)
|
||||||
|
|
||||||
|
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Add `error::InvalidStatusCode` re-export.
|
||||||
|
|
||||||
## 3.7.0
|
## 3.7.0
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@@ -106,7 +106,7 @@ tokio-util = { version = "0.7", features = ["io", "codec"] }
|
|||||||
tracing = { version = "0.1.30", default-features = false, features = ["log"] }
|
tracing = { version = "0.1.30", default-features = false, features = ["log"] }
|
||||||
|
|
||||||
# http2
|
# http2
|
||||||
h2 = { version = "0.3.24", optional = true }
|
h2 = { version = "0.3.26", optional = true }
|
||||||
|
|
||||||
# websockets
|
# websockets
|
||||||
local-channel = { version = "0.1", optional = true }
|
local-channel = { version = "0.1", optional = true }
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
use std::{error::Error as StdError, fmt, io, str::Utf8Error, string::FromUtf8Error};
|
use std::{error::Error as StdError, fmt, io, str::Utf8Error, string::FromUtf8Error};
|
||||||
|
|
||||||
use derive_more::{Display, Error, From};
|
use derive_more::{Display, Error, From};
|
||||||
pub use http::Error as HttpError;
|
pub use http::{status::InvalidStatusCode, Error as HttpError};
|
||||||
use http::{uri::InvalidUri, StatusCode};
|
use http::{uri::InvalidUri, StatusCode};
|
||||||
|
|
||||||
use crate::{body::BoxBody, Response};
|
use crate::{body::BoxBody, Response};
|
||||||
|
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
## 0.1.5
|
||||||
|
|
||||||
|
- Add `TestServerConfig::listen_address()` method.
|
||||||
|
|
||||||
## 0.1.4
|
## 0.1.4
|
||||||
|
|
||||||
- Add `TestServerConfig::rustls_0_23()` method for Rustls v0.23 support behind new `rustls-0_23` crate feature.
|
- Add `TestServerConfig::rustls_0_23()` method for Rustls v0.23 support behind new `rustls-0_23` crate feature.
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "actix-test"
|
name = "actix-test"
|
||||||
version = "0.1.4"
|
version = "0.1.5"
|
||||||
authors = [
|
authors = [
|
||||||
"Nikolay Kim <fafhrd91@gmail.com>",
|
"Nikolay Kim <fafhrd91@gmail.com>",
|
||||||
"Rob Ede <robjtede@icloud.com>",
|
"Rob Ede <robjtede@icloud.com>",
|
||||||
|
@@ -154,7 +154,7 @@ where
|
|||||||
// run server in separate orphaned thread
|
// run server in separate orphaned thread
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
rt::System::new().block_on(async move {
|
rt::System::new().block_on(async move {
|
||||||
let tcp = net::TcpListener::bind(("127.0.0.1", cfg.port)).unwrap();
|
let tcp = net::TcpListener::bind((cfg.listen_address.clone(), cfg.port)).unwrap();
|
||||||
let local_addr = tcp.local_addr().unwrap();
|
let local_addr = tcp.local_addr().unwrap();
|
||||||
let factory = factory.clone();
|
let factory = factory.clone();
|
||||||
let srv_cfg = cfg.clone();
|
let srv_cfg = cfg.clone();
|
||||||
@@ -514,6 +514,7 @@ pub struct TestServerConfig {
|
|||||||
tp: HttpVer,
|
tp: HttpVer,
|
||||||
stream: StreamType,
|
stream: StreamType,
|
||||||
client_request_timeout: Duration,
|
client_request_timeout: Duration,
|
||||||
|
listen_address: String,
|
||||||
port: u16,
|
port: u16,
|
||||||
workers: usize,
|
workers: usize,
|
||||||
disable_redirects: bool,
|
disable_redirects: bool,
|
||||||
@@ -532,6 +533,7 @@ impl TestServerConfig {
|
|||||||
tp: HttpVer::Both,
|
tp: HttpVer::Both,
|
||||||
stream: StreamType::Tcp,
|
stream: StreamType::Tcp,
|
||||||
client_request_timeout: Duration::from_secs(5),
|
client_request_timeout: Duration::from_secs(5),
|
||||||
|
listen_address: "127.0.0.1".to_string(),
|
||||||
port: 0,
|
port: 0,
|
||||||
workers: 1,
|
workers: 1,
|
||||||
disable_redirects: false,
|
disable_redirects: false,
|
||||||
@@ -607,6 +609,14 @@ impl TestServerConfig {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the address the server will listen on.
|
||||||
|
///
|
||||||
|
/// By default, only listens on `127.0.0.1`.
|
||||||
|
pub fn listen_address(mut self, addr: impl Into<String>) -> Self {
|
||||||
|
self.listen_address = addr.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets test server port.
|
/// Sets test server port.
|
||||||
///
|
///
|
||||||
/// By default, a random free port is determined by the OS.
|
/// By default, a random free port is determined by the OS.
|
||||||
@@ -657,9 +667,9 @@ impl TestServer {
|
|||||||
let scheme = if self.tls { "https" } else { "http" };
|
let scheme = if self.tls { "https" } else { "http" };
|
||||||
|
|
||||||
if uri.starts_with('/') {
|
if uri.starts_with('/') {
|
||||||
format!("{}://localhost:{}{}", scheme, self.addr.port(), uri)
|
format!("{}://{}{}", scheme, self.addr, uri)
|
||||||
} else {
|
} else {
|
||||||
format!("{}://localhost:{}/{}", scheme, self.addr.port(), uri)
|
format!("{}://{}/{}", scheme, self.addr, uri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
- Take the encoded buffer when yielding bytes in the response stream rather than splitting the buffer, reducing memory use
|
||||||
- Minimum supported Rust version (MSRV) is now 1.72.
|
- Minimum supported Rust version (MSRV) is now 1.72.
|
||||||
|
|
||||||
## 4.3.0
|
## 4.3.0
|
||||||
|
@@ -710,7 +710,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !this.buf.is_empty() {
|
if !this.buf.is_empty() {
|
||||||
Poll::Ready(Some(Ok(this.buf.split().freeze())))
|
Poll::Ready(Some(Ok(std::mem::take(&mut this.buf).freeze())))
|
||||||
} else if this.fut.alive() && !this.closed {
|
} else if this.fut.alive() && !this.closed {
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
} else {
|
} else {
|
||||||
|
@@ -2,10 +2,15 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- `ConnectionInfo::realip_remote_addr()` now handles IPv6 addresses from `Forwarded` header correctly. Previously, it sometimes returned the forwarded port as well.
|
||||||
|
|
||||||
## 4.7.0
|
## 4.7.0
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Add `#[scope]` macro.
|
||||||
- Add `middleware::Identity` type.
|
- Add `middleware::Identity` type.
|
||||||
- Add `CustomizeResponder::add_cookie()` method.
|
- Add `CustomizeResponder::add_cookie()` method.
|
||||||
- Add `guard::GuardContext::app_data()` method.
|
- Add `guard::GuardContext::app_data()` method.
|
||||||
|
@@ -6,7 +6,7 @@ use crate::{HttpResponse, ResponseError};
|
|||||||
|
|
||||||
/// General purpose Actix Web error.
|
/// 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()`.
|
/// 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
|
/// 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.
|
/// you can always get a `ResponseError` reference from it.
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
cause: Box<dyn ResponseError>,
|
cause: Box<dyn ResponseError>,
|
||||||
|
response_mappers: Vec<Box<dyn Fn(HttpResponse) -> HttpResponse>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
@@ -29,7 +30,20 @@ impl Error {
|
|||||||
|
|
||||||
/// Shortcut for creating an `HttpResponse`.
|
/// Shortcut for creating an `HttpResponse`.
|
||||||
pub fn error_response(&self) -> 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 {
|
fn from(err: T) -> Error {
|
||||||
Error {
|
Error {
|
||||||
cause: Box::new(err),
|
cause: Box::new(err),
|
||||||
|
response_mappers: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -21,6 +21,19 @@ fn unquote(val: &str) -> &str {
|
|||||||
val.trim().trim_start_matches('"').trim_end_matches('"')
|
val.trim().trim_start_matches('"').trim_end_matches('"')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove port and IPv6 square brackets from a peer specification.
|
||||||
|
fn bare_address(val: &str) -> &str {
|
||||||
|
if val.starts_with('[') {
|
||||||
|
val.split("]:")
|
||||||
|
.next()
|
||||||
|
.map(|s| s.trim_start_matches('[').trim_end_matches(']'))
|
||||||
|
// This shouldn't *actually* ever happen
|
||||||
|
.unwrap_or(val)
|
||||||
|
} else {
|
||||||
|
val.split(':').next().unwrap_or(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Extracts and trims first value for given header name.
|
/// Extracts and trims first value for given header name.
|
||||||
fn first_header_value<'a>(req: &'a RequestHead, name: &'_ HeaderName) -> Option<&'a str> {
|
fn first_header_value<'a>(req: &'a RequestHead, name: &'_ HeaderName) -> Option<&'a str> {
|
||||||
let hdr = req.headers.get(name)?.to_str().ok()?;
|
let hdr = req.headers.get(name)?.to_str().ok()?;
|
||||||
@@ -100,7 +113,7 @@ impl ConnectionInfo {
|
|||||||
// --- https://datatracker.ietf.org/doc/html/rfc7239#section-5.2
|
// --- https://datatracker.ietf.org/doc/html/rfc7239#section-5.2
|
||||||
|
|
||||||
match name.trim().to_lowercase().as_str() {
|
match name.trim().to_lowercase().as_str() {
|
||||||
"for" => realip_remote_addr.get_or_insert_with(|| unquote(val)),
|
"for" => realip_remote_addr.get_or_insert_with(|| bare_address(unquote(val))),
|
||||||
"proto" => scheme.get_or_insert_with(|| unquote(val)),
|
"proto" => scheme.get_or_insert_with(|| unquote(val)),
|
||||||
"host" => host.get_or_insert_with(|| unquote(val)),
|
"host" => host.get_or_insert_with(|| unquote(val)),
|
||||||
"by" => {
|
"by" => {
|
||||||
@@ -368,16 +381,25 @@ mod tests {
|
|||||||
.insert_header((header::FORWARDED, r#"for="192.0.2.60:8080""#))
|
.insert_header((header::FORWARDED, r#"for="192.0.2.60:8080""#))
|
||||||
.to_http_request();
|
.to_http_request();
|
||||||
let info = req.connection_info();
|
let info = req.connection_info();
|
||||||
assert_eq!(info.realip_remote_addr(), Some("192.0.2.60:8080"));
|
assert_eq!(info.realip_remote_addr(), Some("192.0.2.60"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn forwarded_for_ipv6() {
|
fn forwarded_for_ipv6() {
|
||||||
|
let req = TestRequest::default()
|
||||||
|
.insert_header((header::FORWARDED, r#"for="[2001:db8:cafe::17]""#))
|
||||||
|
.to_http_request();
|
||||||
|
let info = req.connection_info();
|
||||||
|
assert_eq!(info.realip_remote_addr(), Some("2001:db8:cafe::17"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn forwarded_for_ipv6_with_port() {
|
||||||
let req = TestRequest::default()
|
let req = TestRequest::default()
|
||||||
.insert_header((header::FORWARDED, r#"for="[2001:db8:cafe::17]:4711""#))
|
.insert_header((header::FORWARDED, r#"for="[2001:db8:cafe::17]:4711""#))
|
||||||
.to_http_request();
|
.to_http_request();
|
||||||
let info = req.connection_info();
|
let info = req.connection_info();
|
||||||
assert_eq!(info.realip_remote_addr(), Some("[2001:db8:cafe::17]:4711"));
|
assert_eq!(info.realip_remote_addr(), Some("2001:db8:cafe::17"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@@ -92,7 +92,7 @@ cfg-if = "1"
|
|||||||
derive_more = "0.99.5"
|
derive_more = "0.99.5"
|
||||||
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", "sink"] }
|
futures-util = { version = "0.3.17", default-features = false, features = ["alloc", "sink"] }
|
||||||
h2 = "0.3.24"
|
h2 = "0.3.26"
|
||||||
http = "0.2.7"
|
http = "0.2.7"
|
||||||
itoa = "1"
|
itoa = "1"
|
||||||
log =" 0.4"
|
log =" 0.4"
|
||||||
|
Reference in New Issue
Block a user