mirror of
https://github.com/fafhrd91/actix-web
synced 2025-08-20 12:45:41 +02:00
Compare commits
7 Commits
awc-v3.0.0
...
body-ergo-
Author | SHA1 | Date | |
---|---|---|---|
|
8d2abe4b35 | ||
|
f12f62ba73 | ||
|
fb5b4734a4 | ||
|
4d9dd30c72 | ||
|
d7a1b434cb | ||
|
d5ad250193 | ||
|
818c0f8cad |
@@ -1,9 +1,6 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
|
|
||||||
|
|
||||||
## 4.0.0-beta.14 - 2021-12-11
|
|
||||||
### Added
|
### Added
|
||||||
* Methods on `AcceptLanguage`: `ranked` and `preference`. [#2480]
|
* Methods on `AcceptLanguage`: `ranked` and `preference`. [#2480]
|
||||||
* `AcceptEncoding` typed header. [#2482]
|
* `AcceptEncoding` typed header. [#2482]
|
||||||
@@ -12,7 +9,6 @@
|
|||||||
* `ServiceResponse::map_into_{left,right}_body` and `HttpResponse::map_into_boxed_body`. [#2468]
|
* `ServiceResponse::map_into_{left,right}_body` and `HttpResponse::map_into_boxed_body`. [#2468]
|
||||||
* Connection data set through the `HttpServer::on_connect` callback is now accessible only from the new `HttpRequest::conn_data()` and `ServiceRequest::conn_data()` methods. [#2491]
|
* Connection data set through the `HttpServer::on_connect` callback is now accessible only from the new `HttpRequest::conn_data()` and `ServiceRequest::conn_data()` methods. [#2491]
|
||||||
* `HttpRequest::{req_data,req_data_mut}`. [#2487]
|
* `HttpRequest::{req_data,req_data_mut}`. [#2487]
|
||||||
* `ServiceResponse::into_parts`. [#2499]
|
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
* Rename `Accept::{mime_precedence => ranked}`. [#2480]
|
* Rename `Accept::{mime_precedence => ranked}`. [#2480]
|
||||||
@@ -41,7 +37,6 @@
|
|||||||
[#2491]: https://github.com/actix/actix-web/pull/2491
|
[#2491]: https://github.com/actix/actix-web/pull/2491
|
||||||
[#2492]: https://github.com/actix/actix-web/pull/2492
|
[#2492]: https://github.com/actix/actix-web/pull/2492
|
||||||
[#2493]: https://github.com/actix/actix-web/pull/2493
|
[#2493]: https://github.com/actix/actix-web/pull/2493
|
||||||
[#2499]: https://github.com/actix/actix-web/pull/2499
|
|
||||||
|
|
||||||
|
|
||||||
## 4.0.0-beta.13 - 2021-11-30
|
## 4.0.0-beta.13 - 2021-11-30
|
||||||
|
11
Cargo.toml
11
Cargo.toml
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "actix-web"
|
name = "actix-web"
|
||||||
version = "4.0.0-beta.14"
|
version = "4.0.0-beta.13"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||||
description = "Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust"
|
description = "Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust"
|
||||||
keywords = ["actix", "http", "web", "framework", "async"]
|
keywords = ["actix", "http", "web", "framework", "async"]
|
||||||
@@ -77,9 +77,9 @@ actix-service = "2.0.0"
|
|||||||
actix-utils = "3.0.0"
|
actix-utils = "3.0.0"
|
||||||
actix-tls = { version = "3.0.0-rc.1", default-features = false, optional = true }
|
actix-tls = { version = "3.0.0-rc.1", default-features = false, optional = true }
|
||||||
|
|
||||||
actix-http = "3.0.0-beta.15"
|
actix-http = "3.0.0-beta.14"
|
||||||
actix-router = "0.5.0-beta.2"
|
actix-router = "0.5.0-beta.2"
|
||||||
actix-web-codegen = "0.5.0-beta.6"
|
actix-web-codegen = "0.5.0-beta.5"
|
||||||
|
|
||||||
ahash = "0.7"
|
ahash = "0.7"
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
@@ -107,8 +107,8 @@ time = { version = "0.3", default-features = false, features = ["formatting"] }
|
|||||||
url = "2.1"
|
url = "2.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix-test = { version = "0.1.0-beta.8", features = ["openssl", "rustls"] }
|
actix-test = { version = "0.1.0-beta.7", features = ["openssl", "rustls"] }
|
||||||
awc = { version = "3.0.0-beta.13", features = ["openssl"] }
|
awc = { version = "3.0.0-beta.11", features = ["openssl"] }
|
||||||
|
|
||||||
brotli2 = "0.3.2"
|
brotli2 = "0.3.2"
|
||||||
criterion = { version = "0.3", features = ["html_reports"] }
|
criterion = { version = "0.3", features = ["html_reports"] }
|
||||||
@@ -118,6 +118,7 @@ futures-util = { version = "0.3.7", default-features = false, features = ["std"]
|
|||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
rcgen = "0.8"
|
rcgen = "0.8"
|
||||||
rustls-pemfile = "0.2"
|
rustls-pemfile = "0.2"
|
||||||
|
static_assertions = "1"
|
||||||
tls-openssl = { package = "openssl", version = "0.10.9" }
|
tls-openssl = { package = "openssl", version = "0.10.9" }
|
||||||
tls-rustls = { package = "rustls", version = "0.20.0" }
|
tls-rustls = { package = "rustls", version = "0.20.0" }
|
||||||
zstd = "0.9"
|
zstd = "0.9"
|
||||||
|
@@ -6,10 +6,10 @@
|
|||||||
<p>
|
<p>
|
||||||
|
|
||||||
[](https://crates.io/crates/actix-web)
|
[](https://crates.io/crates/actix-web)
|
||||||
[](https://docs.rs/actix-web/4.0.0-beta.14)
|
[](https://docs.rs/actix-web/4.0.0-beta.13)
|
||||||
[](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html)
|
[](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html)
|
||||||

|

|
||||||
[](https://deps.rs/crate/actix-web/4.0.0-beta.14)
|
[](https://deps.rs/crate/actix-web/4.0.0-beta.13)
|
||||||
<br />
|
<br />
|
||||||
[](https://github.com/actix/actix-web/actions)
|
[](https://github.com/actix/actix-web/actions)
|
||||||
[](https://codecov.io/gh/actix/actix-web)
|
[](https://codecov.io/gh/actix/actix-web)
|
||||||
|
@@ -3,10 +3,6 @@
|
|||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
|
|
||||||
|
|
||||||
## 0.6.0-beta.10 - 2021-12-11
|
|
||||||
* No significant changes since `0.6.0-beta.9`.
|
|
||||||
|
|
||||||
|
|
||||||
## 0.6.0-beta.9 - 2021-11-22
|
## 0.6.0-beta.9 - 2021-11-22
|
||||||
* Add crate feature `experimental-io-uring`, enabling async file I/O to be utilized. This feature is only available on Linux OSes with recent kernel versions. This feature is semver-exempt. [#2408]
|
* Add crate feature `experimental-io-uring`, enabling async file I/O to be utilized. This feature is only available on Linux OSes with recent kernel versions. This feature is semver-exempt. [#2408]
|
||||||
* Add `NamedFile::open_async`. [#2408]
|
* Add `NamedFile::open_async`. [#2408]
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "actix-files"
|
name = "actix-files"
|
||||||
version = "0.6.0-beta.10"
|
version = "0.6.0-beta.9"
|
||||||
authors = [
|
authors = [
|
||||||
"Nikolay Kim <fafhrd91@gmail.com>",
|
"Nikolay Kim <fafhrd91@gmail.com>",
|
||||||
"fakeshadow <24548779@qq.com>",
|
"fakeshadow <24548779@qq.com>",
|
||||||
@@ -22,17 +22,17 @@ path = "src/lib.rs"
|
|||||||
experimental-io-uring = ["actix-web/experimental-io-uring", "tokio-uring"]
|
experimental-io-uring = ["actix-web/experimental-io-uring", "tokio-uring"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-http = "3.0.0-beta.15"
|
actix-web = { version = "4.0.0-beta.11", default-features = false }
|
||||||
|
actix-http = "3.0.0-beta.14"
|
||||||
actix-service = "2"
|
actix-service = "2"
|
||||||
actix-utils = "3"
|
actix-utils = "3"
|
||||||
actix-web = { version = "4.0.0-beta.14", default-features = false }
|
|
||||||
|
|
||||||
askama_escape = "0.10"
|
askama_escape = "0.10"
|
||||||
bitflags = "1"
|
bitflags = "1"
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
derive_more = "0.99.5"
|
|
||||||
futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] }
|
futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] }
|
||||||
http-range = "0.1.4"
|
http-range = "0.1.4"
|
||||||
|
derive_more = "0.99.5"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
mime = "0.3"
|
mime = "0.3"
|
||||||
mime_guess = "2.0.1"
|
mime_guess = "2.0.1"
|
||||||
@@ -43,5 +43,5 @@ tokio-uring = { version = "0.1", optional = true }
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix-rt = "2.2"
|
actix-rt = "2.2"
|
||||||
actix-test = "0.1.0-beta.8"
|
actix-web = "4.0.0-beta.11"
|
||||||
actix-web = "4.0.0-beta.14"
|
actix-test = "0.1.0-beta.7"
|
||||||
|
@@ -3,11 +3,11 @@
|
|||||||
> Static file serving for Actix Web
|
> Static file serving for Actix Web
|
||||||
|
|
||||||
[](https://crates.io/crates/actix-files)
|
[](https://crates.io/crates/actix-files)
|
||||||
[](https://docs.rs/actix-files/0.6.0-beta.10)
|
[](https://docs.rs/actix-files/0.6.0-beta.9)
|
||||||
[](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html)
|
[](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html)
|
||||||

|

|
||||||
<br />
|
<br />
|
||||||
[](https://deps.rs/crate/actix-files/0.6.0-beta.10)
|
[](https://deps.rs/crate/actix-files/0.6.0-beta.9)
|
||||||
[](https://crates.io/crates/actix-files)
|
[](https://crates.io/crates/actix-files)
|
||||||
[](https://discord.gg/NWpN5mmg3x)
|
[](https://discord.gg/NWpN5mmg3x)
|
||||||
|
|
||||||
|
@@ -3,10 +3,6 @@
|
|||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
|
|
||||||
|
|
||||||
## 3.0.0-beta.9 - 2021-12-11
|
|
||||||
* No significant changes since `3.0.0-beta.8`.
|
|
||||||
|
|
||||||
|
|
||||||
## 3.0.0-beta.8 - 2021-11-30
|
## 3.0.0-beta.8 - 2021-11-30
|
||||||
* Update `actix-tls` to `3.0.0-rc.1`. [#2474]
|
* Update `actix-tls` to `3.0.0-rc.1`. [#2474]
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "actix-http-test"
|
name = "actix-http-test"
|
||||||
version = "3.0.0-beta.9"
|
version = "3.0.0-beta.8"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||||
description = "Various helpers for Actix applications to use during testing"
|
description = "Various helpers for Actix applications to use during testing"
|
||||||
keywords = ["http", "web", "framework", "async", "futures"]
|
keywords = ["http", "web", "framework", "async", "futures"]
|
||||||
@@ -35,7 +35,7 @@ actix-tls = "3.0.0-rc.1"
|
|||||||
actix-utils = "3.0.0"
|
actix-utils = "3.0.0"
|
||||||
actix-rt = "2.2"
|
actix-rt = "2.2"
|
||||||
actix-server = "2.0.0-rc.1"
|
actix-server = "2.0.0-rc.1"
|
||||||
awc = { version = "3.0.0-beta.13", default-features = false }
|
awc = { version = "3.0.0-beta.11", default-features = false }
|
||||||
|
|
||||||
base64 = "0.13"
|
base64 = "0.13"
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
@@ -51,5 +51,5 @@ tls-openssl = { version = "0.10.9", package = "openssl", optional = true }
|
|||||||
tokio = { version = "1.2", features = ["sync"] }
|
tokio = { version = "1.2", features = ["sync"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix-web = { version = "4.0.0-beta.14", default-features = false, features = ["cookies"] }
|
actix-web = { version = "4.0.0-beta.11", default-features = false, features = ["cookies"] }
|
||||||
actix-http = "3.0.0-beta.15"
|
actix-http = "3.0.0-beta.14"
|
||||||
|
@@ -3,11 +3,11 @@
|
|||||||
> Various helpers for Actix applications to use during testing.
|
> Various helpers for Actix applications to use during testing.
|
||||||
|
|
||||||
[](https://crates.io/crates/actix-http-test)
|
[](https://crates.io/crates/actix-http-test)
|
||||||
[](https://docs.rs/actix-http-test/3.0.0-beta.9)
|
[](https://docs.rs/actix-http-test/3.0.0-beta.8)
|
||||||
[](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html)
|
[](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html)
|
||||||

|

|
||||||
<br>
|
<br>
|
||||||
[](https://deps.rs/crate/actix-http-test/3.0.0-beta.9)
|
[](https://deps.rs/crate/actix-http-test/3.0.0-beta.8)
|
||||||
[](https://crates.io/crates/actix-http-test)
|
[](https://crates.io/crates/actix-http-test)
|
||||||
[](https://discord.gg/NWpN5mmg3x)
|
[](https://discord.gg/NWpN5mmg3x)
|
||||||
|
|
||||||
|
@@ -1,9 +1,6 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
|
|
||||||
|
|
||||||
## 3.0.0-beta.15 - 2021-12-11
|
|
||||||
### Added
|
### Added
|
||||||
* Add timeout for canceling HTTP/2 server side connection handshake. Default to 5 seconds. [#2483]
|
* Add timeout for canceling HTTP/2 server side connection handshake. Default to 5 seconds. [#2483]
|
||||||
* HTTP/2 handshake timeout can be configured with `ServiceConfig::client_timeout`. [#2483]
|
* HTTP/2 handshake timeout can be configured with `ServiceConfig::client_timeout`. [#2483]
|
||||||
@@ -21,7 +18,6 @@
|
|||||||
* `Request::take_conn_data()`. [#2491]
|
* `Request::take_conn_data()`. [#2491]
|
||||||
* `Request::take_req_data()`. [#2487]
|
* `Request::take_req_data()`. [#2487]
|
||||||
* `impl Clone` for `RequestHead`. [#2487]
|
* `impl Clone` for `RequestHead`. [#2487]
|
||||||
* New methods on `MessageBody` trait, `is_complete_body` and `take_complete_body`, both with default implementations, for optimisations on body types that are done in exactly one poll/chunk. [#2497]
|
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
* Rename `body::BoxBody::{from_body => new}`. [#2468]
|
* Rename `body::BoxBody::{from_body => new}`. [#2468]
|
||||||
@@ -49,7 +45,6 @@
|
|||||||
[#2487]: https://github.com/actix/actix-web/pull/2487
|
[#2487]: https://github.com/actix/actix-web/pull/2487
|
||||||
[#2488]: https://github.com/actix/actix-web/pull/2488
|
[#2488]: https://github.com/actix/actix-web/pull/2488
|
||||||
[#2491]: https://github.com/actix/actix-web/pull/2491
|
[#2491]: https://github.com/actix/actix-web/pull/2491
|
||||||
[#2497]: https://github.com/actix/actix-web/pull/2497
|
|
||||||
|
|
||||||
|
|
||||||
## 3.0.0-beta.14 - 2021-11-30
|
## 3.0.0-beta.14 - 2021-11-30
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "actix-http"
|
name = "actix-http"
|
||||||
version = "3.0.0-beta.15"
|
version = "3.0.0-beta.14"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||||
description = "HTTP primitives for the Actix ecosystem"
|
description = "HTTP primitives for the Actix ecosystem"
|
||||||
keywords = ["actix", "http", "framework", "async", "futures"]
|
keywords = ["actix", "http", "framework", "async", "futures"]
|
||||||
@@ -56,7 +56,7 @@ derive_more = "0.99.5"
|
|||||||
encoding_rs = "0.8"
|
encoding_rs = "0.8"
|
||||||
futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] }
|
futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] }
|
||||||
futures-util = { version = "0.3.7", default-features = false, features = ["alloc", "sink"] }
|
futures-util = { version = "0.3.7", default-features = false, features = ["alloc", "sink"] }
|
||||||
h2 = "0.3.9"
|
h2 = "0.3.1"
|
||||||
http = "0.2.5"
|
http = "0.2.5"
|
||||||
httparse = "1.5.1"
|
httparse = "1.5.1"
|
||||||
httpdate = "1.0.1"
|
httpdate = "1.0.1"
|
||||||
@@ -81,11 +81,10 @@ flate2 = { version = "1.0.13", optional = true }
|
|||||||
zstd = { version = "0.9", optional = true }
|
zstd = { version = "0.9", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix-http-test = { version = "3.0.0-beta.9", features = ["openssl"] }
|
|
||||||
actix-server = "2.0.0-rc.1"
|
actix-server = "2.0.0-rc.1"
|
||||||
|
actix-http-test = { version = "3.0.0-beta.7", features = ["openssl"] }
|
||||||
actix-tls = { version = "3.0.0-rc.1", features = ["openssl"] }
|
actix-tls = { version = "3.0.0-rc.1", features = ["openssl"] }
|
||||||
actix-web = "4.0.0-beta.14"
|
actix-web = "4.0.0-beta.13"
|
||||||
|
|
||||||
async-stream = "0.3"
|
async-stream = "0.3"
|
||||||
criterion = { version = "0.3", features = ["html_reports"] }
|
criterion = { version = "0.3", features = ["html_reports"] }
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
|
@@ -3,11 +3,11 @@
|
|||||||
> HTTP primitives for the Actix ecosystem.
|
> HTTP primitives for the Actix ecosystem.
|
||||||
|
|
||||||
[](https://crates.io/crates/actix-http)
|
[](https://crates.io/crates/actix-http)
|
||||||
[](https://docs.rs/actix-http/3.0.0-beta.15)
|
[](https://docs.rs/actix-http/3.0.0-beta.14)
|
||||||
[](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html)
|
[](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html)
|
||||||

|

|
||||||
<br />
|
<br />
|
||||||
[](https://deps.rs/crate/actix-http/3.0.0-beta.15)
|
[](https://deps.rs/crate/actix-http/3.0.0-beta.14)
|
||||||
[](https://crates.io/crates/actix-http)
|
[](https://crates.io/crates/actix-http)
|
||||||
[](https://discord.gg/NWpN5mmg3x)
|
[](https://discord.gg/NWpN5mmg3x)
|
||||||
|
|
||||||
|
@@ -51,34 +51,6 @@ impl MessageBody for BoxBody {
|
|||||||
.poll_next(cx)
|
.poll_next(cx)
|
||||||
.map_err(|err| Error::new_body().with_cause(err))
|
.map_err(|err| Error::new_body().with_cause(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_complete_body(&self) -> bool {
|
|
||||||
self.0.is_complete_body()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_complete_body(&mut self) -> Bytes {
|
|
||||||
debug_assert!(
|
|
||||||
self.is_complete_body(),
|
|
||||||
"boxed type does not allow taking complete body; caller should make sure to \
|
|
||||||
call `is_complete_body` first",
|
|
||||||
);
|
|
||||||
|
|
||||||
// we do not have DerefMut access to call take_complete_body directly but since
|
|
||||||
// is_complete_body is true we should expect the entire bytes chunk in one poll_next
|
|
||||||
|
|
||||||
let waker = futures_util::task::noop_waker();
|
|
||||||
let mut cx = Context::from_waker(&waker);
|
|
||||||
|
|
||||||
match self.as_pin_mut().poll_next(&mut cx) {
|
|
||||||
Poll::Ready(Some(Ok(data))) => data,
|
|
||||||
_ => {
|
|
||||||
panic!(
|
|
||||||
"boxed type indicated it allows taking complete body but failed to \
|
|
||||||
return Bytes when polled",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@@ -67,20 +67,6 @@ where
|
|||||||
.map_err(|err| Error::new_body().with_cause(err)),
|
.map_err(|err| Error::new_body().with_cause(err)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_complete_body(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
EitherBody::Left { body } => body.is_complete_body(),
|
|
||||||
EitherBody::Right { body } => body.is_complete_body(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_complete_body(&mut self) -> Bytes {
|
|
||||||
match self {
|
|
||||||
EitherBody::Left { body } => body.take_complete_body(),
|
|
||||||
EitherBody::Right { body } => body.take_complete_body(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@@ -19,64 +19,16 @@ use super::BodySize;
|
|||||||
pub trait MessageBody {
|
pub trait MessageBody {
|
||||||
// TODO: consider this bound to only fmt::Display since the error type is not really used
|
// TODO: consider this bound to only fmt::Display since the error type is not really used
|
||||||
// and there is an impl for Into<Box<StdError>> on String
|
// and there is an impl for Into<Box<StdError>> on String
|
||||||
type Error: Into<Box<dyn StdError>>;
|
type Error: Into<Box<dyn StdError>> + 'static;
|
||||||
|
|
||||||
/// Body size hint.
|
/// Body size hint.
|
||||||
fn size(&self) -> BodySize;
|
fn size(&self) -> BodySize;
|
||||||
|
|
||||||
/// Attempt to pull out the next chunk of body bytes.
|
/// Attempt to pull out the next chunk of body bytes.
|
||||||
// TODO: expand documentation
|
|
||||||
fn poll_next(
|
fn poll_next(
|
||||||
self: Pin<&mut Self>,
|
self: Pin<&mut Self>,
|
||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
) -> Poll<Option<Result<Bytes, Self::Error>>>;
|
) -> Poll<Option<Result<Bytes, Self::Error>>>;
|
||||||
|
|
||||||
/// Returns true if entire body bytes chunk is obtainable in one call to `poll_next`.
|
|
||||||
///
|
|
||||||
/// This method's implementation should agree with [`take_complete_body`] and should always be
|
|
||||||
/// checked before taking the body.
|
|
||||||
///
|
|
||||||
/// The default implementation returns `false.
|
|
||||||
///
|
|
||||||
/// [`take_complete_body`]: MessageBody::take_complete_body
|
|
||||||
fn is_complete_body(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the complete chunk of body bytes.
|
|
||||||
///
|
|
||||||
/// Implementors of this method should note the following:
|
|
||||||
/// - It is acceptable to skip the omit checks of [`is_complete_body`]. The responsibility of
|
|
||||||
/// performing this check is delegated to the caller.
|
|
||||||
/// - If the result of [`is_complete_body`] is conditional, that condition should be given
|
|
||||||
/// equivalent attention here.
|
|
||||||
/// - A second call call to [`take_complete_body`] should return an empty `Bytes` or panic.
|
|
||||||
/// - A call to [`poll_next`] after calling [`take_complete_body`] should return `None` unless
|
|
||||||
/// the chunk is guaranteed to be empty.
|
|
||||||
///
|
|
||||||
/// The default implementation panics unconditionally, indicating a control flow bug in the
|
|
||||||
/// calling code.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
/// With a correct implementation, panics if called without first checking [`is_complete_body`].
|
|
||||||
///
|
|
||||||
/// [`is_complete_body`]: MessageBody::is_complete_body
|
|
||||||
/// [`take_complete_body`]: MessageBody::take_complete_body
|
|
||||||
/// [`poll_next`]: MessageBody::poll_next
|
|
||||||
fn take_complete_body(&mut self) -> Bytes {
|
|
||||||
assert!(
|
|
||||||
self.is_complete_body(),
|
|
||||||
"type ({}) allows taking complete body but did not provide an implementation \
|
|
||||||
of `take_complete_body`",
|
|
||||||
std::any::type_name::<Self>()
|
|
||||||
);
|
|
||||||
|
|
||||||
unimplemented!(
|
|
||||||
"type ({}) does not allow taking complete body; caller should make sure to \
|
|
||||||
check `is_complete_body` first",
|
|
||||||
std::any::type_name::<Self>()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mod foreign_impls {
|
mod foreign_impls {
|
||||||
@@ -97,14 +49,6 @@ mod foreign_impls {
|
|||||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||||
match *self {}
|
match *self {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_complete_body(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_complete_body(&mut self) -> Bytes {
|
|
||||||
match *self {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageBody for () {
|
impl MessageBody for () {
|
||||||
@@ -122,16 +66,6 @@ mod foreign_impls {
|
|||||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||||
Poll::Ready(None)
|
Poll::Ready(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_complete_body(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn take_complete_body(&mut self) -> Bytes {
|
|
||||||
Bytes::new()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> MessageBody for Box<B>
|
impl<B> MessageBody for Box<B>
|
||||||
@@ -152,16 +86,6 @@ mod foreign_impls {
|
|||||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||||
Pin::new(self.get_mut().as_mut()).poll_next(cx)
|
Pin::new(self.get_mut().as_mut()).poll_next(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_complete_body(&self) -> bool {
|
|
||||||
self.as_ref().is_complete_body()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn take_complete_body(&mut self) -> Bytes {
|
|
||||||
self.as_mut().take_complete_body()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> MessageBody for Pin<Box<B>>
|
impl<B> MessageBody for Pin<Box<B>>
|
||||||
@@ -182,38 +106,6 @@ mod foreign_impls {
|
|||||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||||
self.as_mut().poll_next(cx)
|
self.as_mut().poll_next(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_complete_body(&self) -> bool {
|
|
||||||
self.as_ref().is_complete_body()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn take_complete_body(&mut self) -> Bytes {
|
|
||||||
debug_assert!(
|
|
||||||
self.is_complete_body(),
|
|
||||||
"inner type \"{}\" does not allow taking complete body; caller should make sure to \
|
|
||||||
call `is_complete_body` first",
|
|
||||||
std::any::type_name::<B>(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// we do not have DerefMut access to call take_complete_body directly but since
|
|
||||||
// is_complete_body is true we should expect the entire bytes chunk in one poll_next
|
|
||||||
|
|
||||||
let waker = futures_util::task::noop_waker();
|
|
||||||
let mut cx = Context::from_waker(&waker);
|
|
||||||
|
|
||||||
match self.as_mut().poll_next(&mut cx) {
|
|
||||||
Poll::Ready(Some(Ok(data))) => data,
|
|
||||||
_ => {
|
|
||||||
panic!(
|
|
||||||
"inner type \"{}\" indicated it allows taking complete body but failed to \
|
|
||||||
return Bytes when polled",
|
|
||||||
std::any::type_name::<B>()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageBody for &'static [u8] {
|
impl MessageBody for &'static [u8] {
|
||||||
@@ -224,23 +116,17 @@ mod foreign_impls {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(
|
||||||
mut self: Pin<&mut Self>,
|
self: Pin<&mut Self>,
|
||||||
_cx: &mut Context<'_>,
|
_cx: &mut Context<'_>,
|
||||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||||
if self.is_empty() {
|
if self.is_empty() {
|
||||||
Poll::Ready(None)
|
Poll::Ready(None)
|
||||||
} else {
|
} else {
|
||||||
Poll::Ready(Some(Ok(self.take_complete_body())))
|
let bytes = mem::take(self.get_mut());
|
||||||
|
let bytes = Bytes::from_static(bytes);
|
||||||
|
Poll::Ready(Some(Ok(bytes)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_complete_body(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_complete_body(&mut self) -> Bytes {
|
|
||||||
Bytes::from_static(mem::take(self))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageBody for Bytes {
|
impl MessageBody for Bytes {
|
||||||
@@ -251,23 +137,16 @@ mod foreign_impls {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(
|
||||||
mut self: Pin<&mut Self>,
|
self: Pin<&mut Self>,
|
||||||
_cx: &mut Context<'_>,
|
_cx: &mut Context<'_>,
|
||||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||||
if self.is_empty() {
|
if self.is_empty() {
|
||||||
Poll::Ready(None)
|
Poll::Ready(None)
|
||||||
} else {
|
} else {
|
||||||
Poll::Ready(Some(Ok(self.take_complete_body())))
|
let bytes = mem::take(self.get_mut());
|
||||||
|
Poll::Ready(Some(Ok(bytes)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_complete_body(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_complete_body(&mut self) -> Bytes {
|
|
||||||
mem::take(self)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageBody for BytesMut {
|
impl MessageBody for BytesMut {
|
||||||
@@ -278,23 +157,16 @@ mod foreign_impls {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(
|
||||||
mut self: Pin<&mut Self>,
|
self: Pin<&mut Self>,
|
||||||
_cx: &mut Context<'_>,
|
_cx: &mut Context<'_>,
|
||||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||||
if self.is_empty() {
|
if self.is_empty() {
|
||||||
Poll::Ready(None)
|
Poll::Ready(None)
|
||||||
} else {
|
} else {
|
||||||
Poll::Ready(Some(Ok(self.take_complete_body())))
|
let bytes = mem::take(self.get_mut()).freeze();
|
||||||
|
Poll::Ready(Some(Ok(bytes)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_complete_body(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_complete_body(&mut self) -> Bytes {
|
|
||||||
mem::take(self).freeze()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageBody for Vec<u8> {
|
impl MessageBody for Vec<u8> {
|
||||||
@@ -305,23 +177,16 @@ mod foreign_impls {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(
|
||||||
mut self: Pin<&mut Self>,
|
self: Pin<&mut Self>,
|
||||||
_cx: &mut Context<'_>,
|
_cx: &mut Context<'_>,
|
||||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||||
if self.is_empty() {
|
if self.is_empty() {
|
||||||
Poll::Ready(None)
|
Poll::Ready(None)
|
||||||
} else {
|
} else {
|
||||||
Poll::Ready(Some(Ok(self.take_complete_body())))
|
let bytes = mem::take(self.get_mut());
|
||||||
|
Poll::Ready(Some(Ok(Bytes::from(bytes))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_complete_body(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_complete_body(&mut self) -> Bytes {
|
|
||||||
Bytes::from(mem::take(self))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageBody for &'static str {
|
impl MessageBody for &'static str {
|
||||||
@@ -343,14 +208,6 @@ mod foreign_impls {
|
|||||||
Poll::Ready(Some(Ok(bytes)))
|
Poll::Ready(Some(Ok(bytes)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_complete_body(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_complete_body(&mut self) -> Bytes {
|
|
||||||
Bytes::from_static(mem::take(self).as_bytes())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageBody for String {
|
impl MessageBody for String {
|
||||||
@@ -371,14 +228,6 @@ mod foreign_impls {
|
|||||||
Poll::Ready(Some(Ok(Bytes::from(string))))
|
Poll::Ready(Some(Ok(Bytes::from(string))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_complete_body(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_complete_body(&mut self) -> Bytes {
|
|
||||||
Bytes::from(mem::take(self))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageBody for bytestring::ByteString {
|
impl MessageBody for bytestring::ByteString {
|
||||||
@@ -395,14 +244,6 @@ mod foreign_impls {
|
|||||||
let string = mem::take(self.get_mut());
|
let string = mem::take(self.get_mut());
|
||||||
Poll::Ready(Some(Ok(string.into_bytes())))
|
Poll::Ready(Some(Ok(string.into_bytes())))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_complete_body(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_complete_body(&mut self) -> Bytes {
|
|
||||||
mem::take(self).into_bytes()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,7 +272,7 @@ impl<B, F, E> MessageBody for MessageBodyMapErr<B, F>
|
|||||||
where
|
where
|
||||||
B: MessageBody,
|
B: MessageBody,
|
||||||
F: FnOnce(B::Error) -> E,
|
F: FnOnce(B::Error) -> E,
|
||||||
E: Into<Box<dyn StdError>>,
|
E: Into<Box<dyn StdError>> + 'static,
|
||||||
{
|
{
|
||||||
type Error = E;
|
type Error = E;
|
||||||
|
|
||||||
@@ -465,6 +306,8 @@ mod tests {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
// static_assertions::assert_obj_safe!(MessageBody<()>);
|
||||||
|
|
||||||
macro_rules! assert_poll_next {
|
macro_rules! assert_poll_next {
|
||||||
($pin:expr, $exp:expr) => {
|
($pin:expr, $exp:expr) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -565,51 +408,6 @@ mod tests {
|
|||||||
assert_poll_next!(pl, Bytes::from("test"));
|
assert_poll_next!(pl, Bytes::from("test"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn take_string() {
|
|
||||||
let mut data = "test".repeat(2);
|
|
||||||
let data_bytes = Bytes::from(data.clone());
|
|
||||||
assert!(data.is_complete_body());
|
|
||||||
assert_eq!(data.take_complete_body(), data_bytes);
|
|
||||||
|
|
||||||
let mut big_data = "test".repeat(64 * 1024);
|
|
||||||
let data_bytes = Bytes::from(big_data.clone());
|
|
||||||
assert!(big_data.is_complete_body());
|
|
||||||
assert_eq!(big_data.take_complete_body(), data_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn take_boxed_equivalence() {
|
|
||||||
let mut data = Bytes::from_static(b"test");
|
|
||||||
assert!(data.is_complete_body());
|
|
||||||
assert_eq!(data.take_complete_body(), b"test".as_ref());
|
|
||||||
|
|
||||||
let mut data = Box::new(Bytes::from_static(b"test"));
|
|
||||||
assert!(data.is_complete_body());
|
|
||||||
assert_eq!(data.take_complete_body(), b"test".as_ref());
|
|
||||||
|
|
||||||
let mut data = Box::pin(Bytes::from_static(b"test"));
|
|
||||||
assert!(data.is_complete_body());
|
|
||||||
assert_eq!(data.take_complete_body(), b"test".as_ref());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn take_policy() {
|
|
||||||
let mut data = Bytes::from_static(b"test");
|
|
||||||
// first call returns chunk
|
|
||||||
assert_eq!(data.take_complete_body(), b"test".as_ref());
|
|
||||||
// second call returns empty
|
|
||||||
assert_eq!(data.take_complete_body(), b"".as_ref());
|
|
||||||
|
|
||||||
let waker = futures_util::task::noop_waker();
|
|
||||||
let mut cx = Context::from_waker(&waker);
|
|
||||||
let mut data = Bytes::from_static(b"test");
|
|
||||||
// take returns whole chunk
|
|
||||||
assert_eq!(data.take_complete_body(), b"test".as_ref());
|
|
||||||
// subsequent poll_next returns None
|
|
||||||
assert_eq!(Pin::new(&mut data).poll_next(&mut cx), Poll::Ready(None));
|
|
||||||
}
|
|
||||||
|
|
||||||
// down-casting used to be done with a method on MessageBody trait
|
// down-casting used to be done with a method on MessageBody trait
|
||||||
// test is kept to demonstrate equivalence of Any trait
|
// test is kept to demonstrate equivalence of Any trait
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
//! Traits and structures to aid consuming and writing HTTP payloads.
|
//! Traits and structures to aid consuming and writing HTTP payloads.
|
||||||
|
|
||||||
|
// mod any;
|
||||||
mod body_stream;
|
mod body_stream;
|
||||||
mod boxed;
|
mod boxed;
|
||||||
mod either;
|
mod either;
|
||||||
@@ -9,6 +10,7 @@ mod size;
|
|||||||
mod sized_stream;
|
mod sized_stream;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
// pub use self::any::AnyBody;
|
||||||
pub use self::body_stream::BodyStream;
|
pub use self::body_stream::BodyStream;
|
||||||
pub use self::boxed::BoxBody;
|
pub use self::boxed::BoxBody;
|
||||||
pub use self::either::EitherBody;
|
pub use self::either::EitherBody;
|
||||||
|
@@ -40,14 +40,4 @@ impl MessageBody for None {
|
|||||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||||
Poll::Ready(Option::None)
|
Poll::Ready(Option::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_complete_body(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn take_complete_body(&mut self) -> Bytes {
|
|
||||||
Bytes::new()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
//! Stream encoders.
|
//! Stream encoders.
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
error::Error as StdError,
|
|
||||||
future::Future,
|
future::Future,
|
||||||
io::{self, Write as _},
|
io::{self, Write as _},
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
@@ -10,7 +9,6 @@ use std::{
|
|||||||
|
|
||||||
use actix_rt::task::{spawn_blocking, JoinHandle};
|
use actix_rt::task::{spawn_blocking, JoinHandle};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use derive_more::Display;
|
|
||||||
use futures_core::ready;
|
use futures_core::ready;
|
||||||
use pin_project_lite::pin_project;
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
@@ -23,7 +21,7 @@ use flate2::write::{GzEncoder, ZlibEncoder};
|
|||||||
#[cfg(feature = "compress-zstd")]
|
#[cfg(feature = "compress-zstd")]
|
||||||
use zstd::stream::write::Encoder as ZstdEncoder;
|
use zstd::stream::write::Encoder as ZstdEncoder;
|
||||||
|
|
||||||
use super::Writer;
|
use super::{EncoderError, Writer};
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{BodySize, MessageBody},
|
body::{BodySize, MessageBody},
|
||||||
error::BlockingError,
|
error::BlockingError,
|
||||||
@@ -53,32 +51,41 @@ impl<B: MessageBody> Encoder<B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn response(encoding: ContentEncoding, head: &mut ResponseHead, mut body: B) -> Self {
|
pub fn not_acceptable(body: Bytes) -> Self {
|
||||||
|
Encoder {
|
||||||
|
body: EncoderBody::Bytes { body },
|
||||||
|
encoder: None,
|
||||||
|
fut: None,
|
||||||
|
eof: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn response(encoding: ContentEncoding, head: &mut ResponseHead, body: B) -> Self {
|
||||||
let can_encode = !(head.headers().contains_key(&CONTENT_ENCODING)
|
let can_encode = !(head.headers().contains_key(&CONTENT_ENCODING)
|
||||||
|| head.status == StatusCode::SWITCHING_PROTOCOLS
|
|| head.status == StatusCode::SWITCHING_PROTOCOLS
|
||||||
|| head.status == StatusCode::NO_CONTENT
|
|| head.status == StatusCode::NO_CONTENT
|
||||||
|| encoding == ContentEncoding::Identity
|
|| encoding == ContentEncoding::Identity
|
||||||
|| encoding == ContentEncoding::Auto);
|
|| encoding == ContentEncoding::Auto);
|
||||||
|
|
||||||
// no need to compress an empty body
|
match body.size() {
|
||||||
if matches!(body.size(), BodySize::None) {
|
// no need to compress an empty body
|
||||||
return Self::none();
|
BodySize::None => return Self::none(),
|
||||||
|
|
||||||
|
// we cannot assume that Sized is not a stream
|
||||||
|
BodySize::Sized(_) | BodySize::Stream => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let body = if body.is_complete_body() {
|
// TODO potentially some optimisation for single-chunk responses here by trying to read the
|
||||||
let body = body.take_complete_body();
|
// payload eagerly, stopping after 2 polls if the first is a chunk and the second is None
|
||||||
EncoderBody::Full { body }
|
|
||||||
} else {
|
|
||||||
EncoderBody::Stream { body }
|
|
||||||
};
|
|
||||||
|
|
||||||
if can_encode {
|
if can_encode {
|
||||||
// Modify response body only if encoder is set
|
// Modify response body only if encoder is set
|
||||||
if let Some(enc) = ContentEncoder::encoder(encoding) {
|
if let Some(enc) = ContentEncoder::encoder(encoding) {
|
||||||
update_head(encoding, head);
|
update_head(encoding, head);
|
||||||
|
head.no_chunking(false);
|
||||||
|
|
||||||
return Encoder {
|
return Encoder {
|
||||||
body,
|
body: EncoderBody::Stream { body },
|
||||||
encoder: Some(enc),
|
encoder: Some(enc),
|
||||||
fut: None,
|
fut: None,
|
||||||
eof: false,
|
eof: false,
|
||||||
@@ -87,7 +94,7 @@ impl<B: MessageBody> Encoder<B> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Encoder {
|
Encoder {
|
||||||
body,
|
body: EncoderBody::Stream { body },
|
||||||
encoder: None,
|
encoder: None,
|
||||||
fut: None,
|
fut: None,
|
||||||
eof: false,
|
eof: false,
|
||||||
@@ -99,7 +106,7 @@ pin_project! {
|
|||||||
#[project = EncoderBodyProj]
|
#[project = EncoderBodyProj]
|
||||||
enum EncoderBody<B> {
|
enum EncoderBody<B> {
|
||||||
None,
|
None,
|
||||||
Full { body: Bytes },
|
Bytes { body: Bytes },
|
||||||
Stream { #[pin] body: B },
|
Stream { #[pin] body: B },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,7 +120,7 @@ where
|
|||||||
fn size(&self) -> BodySize {
|
fn size(&self) -> BodySize {
|
||||||
match self {
|
match self {
|
||||||
EncoderBody::None => BodySize::None,
|
EncoderBody::None => BodySize::None,
|
||||||
EncoderBody::Full { body } => body.size(),
|
EncoderBody::Bytes { body } => body.size(),
|
||||||
EncoderBody::Stream { body } => body.size(),
|
EncoderBody::Stream { body } => body.size(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,7 +131,7 @@ where
|
|||||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||||
match self.project() {
|
match self.project() {
|
||||||
EncoderBodyProj::None => Poll::Ready(None),
|
EncoderBodyProj::None => Poll::Ready(None),
|
||||||
EncoderBodyProj::Full { body } => {
|
EncoderBodyProj::Bytes { body } => {
|
||||||
Pin::new(body).poll_next(cx).map_err(|err| match err {})
|
Pin::new(body).poll_next(cx).map_err(|err| match err {})
|
||||||
}
|
}
|
||||||
EncoderBodyProj::Stream { body } => body
|
EncoderBodyProj::Stream { body } => body
|
||||||
@@ -132,24 +139,6 @@ where
|
|||||||
.map_err(|err| EncoderError::Body(err.into())),
|
.map_err(|err| EncoderError::Body(err.into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_complete_body(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
EncoderBody::None => true,
|
|
||||||
EncoderBody::Full { .. } => true,
|
|
||||||
EncoderBody::Stream { .. } => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_complete_body(&mut self) -> Bytes {
|
|
||||||
match self {
|
|
||||||
EncoderBody::None => Bytes::new(),
|
|
||||||
EncoderBody::Full { body } => body.take_complete_body(),
|
|
||||||
EncoderBody::Stream { .. } => {
|
|
||||||
panic!("EncoderBody::Stream variant cannot be taken")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> MessageBody for Encoder<B>
|
impl<B> MessageBody for Encoder<B>
|
||||||
@@ -159,10 +148,10 @@ where
|
|||||||
type Error = EncoderError;
|
type Error = EncoderError;
|
||||||
|
|
||||||
fn size(&self) -> BodySize {
|
fn size(&self) -> BodySize {
|
||||||
if self.encoder.is_some() {
|
if self.encoder.is_none() {
|
||||||
BodySize::Stream
|
|
||||||
} else {
|
|
||||||
self.body.size()
|
self.body.size()
|
||||||
|
} else {
|
||||||
|
BodySize::Stream
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,22 +222,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_complete_body(&self) -> bool {
|
|
||||||
if self.encoder.is_some() {
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
self.body.is_complete_body()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_complete_body(&mut self) -> Bytes {
|
|
||||||
if self.encoder.is_some() {
|
|
||||||
panic!("compressed body stream cannot be taken")
|
|
||||||
} else {
|
|
||||||
self.body.take_complete_body()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_head(encoding: ContentEncoding, head: &mut ResponseHead) {
|
fn update_head(encoding: ContentEncoding, head: &mut ResponseHead) {
|
||||||
@@ -256,8 +229,6 @@ fn update_head(encoding: ContentEncoding, head: &mut ResponseHead) {
|
|||||||
header::CONTENT_ENCODING,
|
header::CONTENT_ENCODING,
|
||||||
HeaderValue::from_static(encoding.as_str()),
|
HeaderValue::from_static(encoding.as_str()),
|
||||||
);
|
);
|
||||||
|
|
||||||
head.no_chunking(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ContentEncoder {
|
enum ContentEncoder {
|
||||||
@@ -391,32 +362,3 @@ impl ContentEncoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Display)]
|
|
||||||
#[non_exhaustive]
|
|
||||||
pub enum EncoderError {
|
|
||||||
#[display(fmt = "body")]
|
|
||||||
Body(Box<dyn StdError>),
|
|
||||||
|
|
||||||
#[display(fmt = "blocking")]
|
|
||||||
Blocking(BlockingError),
|
|
||||||
|
|
||||||
#[display(fmt = "io")]
|
|
||||||
Io(io::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StdError for EncoderError {
|
|
||||||
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
|
||||||
match self {
|
|
||||||
EncoderError::Body(err) => Some(&**err),
|
|
||||||
EncoderError::Blocking(err) => Some(err),
|
|
||||||
EncoderError::Io(err) => Some(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<EncoderError> for crate::Error {
|
|
||||||
fn from(err: EncoderError) -> Self {
|
|
||||||
crate::Error::new_encoder().with_cause(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,22 +1,60 @@
|
|||||||
//! Content-Encoding support.
|
//! Content-Encoding support.
|
||||||
|
|
||||||
use std::io;
|
use std::{error::Error as StdError, io};
|
||||||
|
|
||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
|
use derive_more::Display;
|
||||||
|
|
||||||
|
use crate::error::BlockingError;
|
||||||
|
|
||||||
|
#[cfg(feature = "__compress")]
|
||||||
mod decoder;
|
mod decoder;
|
||||||
|
#[cfg(feature = "__compress")]
|
||||||
mod encoder;
|
mod encoder;
|
||||||
|
|
||||||
|
#[cfg(feature = "__compress")]
|
||||||
pub use self::decoder::Decoder;
|
pub use self::decoder::Decoder;
|
||||||
|
#[cfg(feature = "__compress")]
|
||||||
pub use self::encoder::Encoder;
|
pub use self::encoder::Encoder;
|
||||||
|
|
||||||
|
#[derive(Debug, Display)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum EncoderError {
|
||||||
|
#[display(fmt = "body")]
|
||||||
|
Body(Box<dyn StdError>),
|
||||||
|
|
||||||
|
#[display(fmt = "blocking")]
|
||||||
|
Blocking(BlockingError),
|
||||||
|
|
||||||
|
#[display(fmt = "io")]
|
||||||
|
Io(io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StdError for EncoderError {
|
||||||
|
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
||||||
|
match self {
|
||||||
|
EncoderError::Body(err) => Some(&**err),
|
||||||
|
EncoderError::Blocking(err) => Some(err),
|
||||||
|
EncoderError::Io(err) => Some(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<EncoderError> for crate::Error {
|
||||||
|
fn from(err: EncoderError) -> Self {
|
||||||
|
crate::Error::new_encoder().with_cause(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Special-purpose writer for streaming (de-)compression.
|
/// Special-purpose writer for streaming (de-)compression.
|
||||||
///
|
///
|
||||||
/// Pre-allocates 8KiB of capacity.
|
/// Pre-allocates 8KiB of capacity.
|
||||||
|
#[cfg(feature = "__compress")]
|
||||||
pub(self) struct Writer {
|
pub(self) struct Writer {
|
||||||
buf: BytesMut,
|
buf: BytesMut,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "__compress")]
|
||||||
impl Writer {
|
impl Writer {
|
||||||
fn new() -> Writer {
|
fn new() -> Writer {
|
||||||
Writer {
|
Writer {
|
||||||
@@ -29,6 +67,7 @@ impl Writer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "__compress")]
|
||||||
impl io::Write for Writer {
|
impl io::Write for Writer {
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
self.buf.extend_from_slice(buf);
|
self.buf.extend_from_slice(buf);
|
||||||
|
@@ -9,6 +9,8 @@ use crate::{body::BoxBody, ws, Response};
|
|||||||
|
|
||||||
pub use http::Error as HttpError;
|
pub use http::Error as HttpError;
|
||||||
|
|
||||||
|
pub use crate::encoding::EncoderError;
|
||||||
|
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
inner: Box<ErrorInner>,
|
inner: Box<ErrorInner>,
|
||||||
}
|
}
|
||||||
|
@@ -19,13 +19,13 @@ use h2::{
|
|||||||
server::{Connection, SendResponse},
|
server::{Connection, SendResponse},
|
||||||
Ping, PingPong,
|
Ping, PingPong,
|
||||||
};
|
};
|
||||||
|
use http::header::{HeaderValue, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING};
|
||||||
use log::{error, trace};
|
use log::{error, trace};
|
||||||
use pin_project_lite::pin_project;
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{BodySize, BoxBody, MessageBody},
|
body::{BodySize, BoxBody, MessageBody},
|
||||||
config::ServiceConfig,
|
config::ServiceConfig,
|
||||||
header::{HeaderValue, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING},
|
|
||||||
service::HttpFlow,
|
service::HttpFlow,
|
||||||
Extensions, OnConnectData, Payload, Request, Response, ResponseHead,
|
Extensions, OnConnectData, Payload, Request, Response, ResponseHead,
|
||||||
};
|
};
|
||||||
@@ -217,28 +217,25 @@ where
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// poll response body and send chunks to client
|
// poll response body and send chunks to client.
|
||||||
actix_rt::pin!(body);
|
actix_rt::pin!(body);
|
||||||
|
|
||||||
while let Some(res) = poll_fn(|cx| body.as_mut().poll_next(cx)).await {
|
while let Some(res) = poll_fn(|cx| body.as_mut().poll_next(cx)).await {
|
||||||
let mut chunk = res.map_err(|err| DispatchError::ResponseBody(err.into()))?;
|
let mut chunk = res.map_err(|err| DispatchError::ResponseBody(err.into()))?;
|
||||||
|
|
||||||
'send: loop {
|
'send: loop {
|
||||||
let chunk_size = cmp::min(chunk.len(), CHUNK_SIZE);
|
|
||||||
|
|
||||||
// reserve enough space and wait for stream ready.
|
// reserve enough space and wait for stream ready.
|
||||||
stream.reserve_capacity(chunk_size);
|
stream.reserve_capacity(cmp::min(chunk.len(), CHUNK_SIZE));
|
||||||
|
|
||||||
match poll_fn(|cx| stream.poll_capacity(cx)).await {
|
match poll_fn(|cx| stream.poll_capacity(cx)).await {
|
||||||
// No capacity left. drop body and return.
|
// No capacity left. drop body and return.
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
|
Some(res) => {
|
||||||
|
// Split chuck to writeable size and send to client.
|
||||||
|
let cap = res.map_err(DispatchError::SendData)?;
|
||||||
|
|
||||||
Some(Err(err)) => return Err(DispatchError::SendData(err)),
|
|
||||||
|
|
||||||
Some(Ok(cap)) => {
|
|
||||||
// split chunk to writeable size and send to client
|
|
||||||
let len = chunk.len();
|
let len = chunk.len();
|
||||||
let bytes = chunk.split_to(cmp::min(len, cap));
|
let bytes = chunk.split_to(cmp::min(cap, len));
|
||||||
|
|
||||||
stream
|
stream
|
||||||
.send_data(bytes, false)
|
.send_data(bytes, false)
|
||||||
|
@@ -32,7 +32,6 @@ pub mod body;
|
|||||||
mod builder;
|
mod builder;
|
||||||
mod config;
|
mod config;
|
||||||
|
|
||||||
#[cfg(feature = "__compress")]
|
|
||||||
pub mod encoding;
|
pub mod encoding;
|
||||||
mod extensions;
|
mod extensions;
|
||||||
pub mod header;
|
pub mod header;
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
cell::{Ref, RefMut},
|
cell::{Ref, RefMut},
|
||||||
fmt, str,
|
fmt, mem, str,
|
||||||
};
|
};
|
||||||
|
|
||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
@@ -203,6 +203,12 @@ impl<B> Response<B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<B: Default> Response<B> {
|
||||||
|
pub fn take_body(&mut self) -> B {
|
||||||
|
mem::take(&mut self.body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<B> fmt::Debug for Response<B>
|
impl<B> fmt::Debug for Response<B>
|
||||||
where
|
where
|
||||||
B: MessageBody,
|
B: MessageBody,
|
||||||
|
@@ -101,7 +101,7 @@ async fn test_h2_1() -> io::Result<()> {
|
|||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_h2_body() -> io::Result<()> {
|
async fn test_h2_body() -> io::Result<()> {
|
||||||
let data = "HELLOWORLD".to_owned().repeat(64 * 1024); // 640 KiB
|
let data = "HELLOWORLD".to_owned().repeat(64 * 1024);
|
||||||
let mut srv = test_server(move || {
|
let mut srv = test_server(move || {
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.h2(|mut req: Request<_>| async move {
|
.h2(|mut req: Request<_>| async move {
|
||||||
|
@@ -3,10 +3,6 @@
|
|||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
|
|
||||||
|
|
||||||
## 0.4.0-beta.10 - 2021-12-11
|
|
||||||
* No significant changes since `0.4.0-beta.9`.
|
|
||||||
|
|
||||||
|
|
||||||
## 0.4.0-beta.9 - 2021-12-01
|
## 0.4.0-beta.9 - 2021-12-01
|
||||||
* Polling `Field` after dropping `Multipart` now fails immediately instead of hanging forever. [#2463]
|
* Polling `Field` after dropping `Multipart` now fails immediately instead of hanging forever. [#2463]
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "actix-multipart"
|
name = "actix-multipart"
|
||||||
version = "0.4.0-beta.10"
|
version = "0.4.0-beta.9"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||||
description = "Multipart form support for Actix Web"
|
description = "Multipart form support for Actix Web"
|
||||||
keywords = ["http", "web", "framework", "async", "futures"]
|
keywords = ["http", "web", "framework", "async", "futures"]
|
||||||
@@ -14,8 +14,8 @@ name = "actix_multipart"
|
|||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
actix-web = { version = "4.0.0-beta.11", default-features = false }
|
||||||
actix-utils = "3.0.0"
|
actix-utils = "3.0.0"
|
||||||
actix-web = { version = "4.0.0-beta.14", default-features = false }
|
|
||||||
|
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
derive_more = "0.99.5"
|
derive_more = "0.99.5"
|
||||||
@@ -28,7 +28,7 @@ twoway = "0.2"
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix-rt = "2.2"
|
actix-rt = "2.2"
|
||||||
actix-http = "3.0.0-beta.15"
|
actix-http = "3.0.0-beta.14"
|
||||||
futures-util = { version = "0.3.7", default-features = false, features = ["alloc"] }
|
futures-util = { version = "0.3.7", default-features = false, features = ["alloc"] }
|
||||||
tokio = { version = "1", features = ["sync"] }
|
tokio = { version = "1", features = ["sync"] }
|
||||||
tokio-stream = "0.1"
|
tokio-stream = "0.1"
|
||||||
|
@@ -3,11 +3,11 @@
|
|||||||
> Multipart form support for Actix Web.
|
> Multipart form support for Actix Web.
|
||||||
|
|
||||||
[](https://crates.io/crates/actix-multipart)
|
[](https://crates.io/crates/actix-multipart)
|
||||||
[](https://docs.rs/actix-multipart/0.4.0-beta.10)
|
[](https://docs.rs/actix-multipart/0.4.0-beta.9)
|
||||||
[](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html)
|
[](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html)
|
||||||

|

|
||||||
<br />
|
<br />
|
||||||
[](https://deps.rs/crate/actix-multipart/0.4.0-beta.10)
|
[](https://deps.rs/crate/actix-multipart/0.4.0-beta.9)
|
||||||
[](https://crates.io/crates/actix-multipart)
|
[](https://crates.io/crates/actix-multipart)
|
||||||
[](https://discord.gg/NWpN5mmg3x)
|
[](https://discord.gg/NWpN5mmg3x)
|
||||||
|
|
||||||
|
@@ -3,10 +3,6 @@
|
|||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
|
|
||||||
|
|
||||||
## 0.1.0-beta.8 - 2021-12-11
|
|
||||||
* No significant changes since `0.1.0-beta.7`.
|
|
||||||
|
|
||||||
|
|
||||||
## 0.1.0-beta.7 - 2021-11-22
|
## 0.1.0-beta.7 - 2021-11-22
|
||||||
* Fix compatibility with experimental `io-uring` feature of `actix-rt`. [#2408]
|
* Fix compatibility with experimental `io-uring` feature of `actix-rt`. [#2408]
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "actix-test"
|
name = "actix-test"
|
||||||
version = "0.1.0-beta.8"
|
version = "0.1.0-beta.7"
|
||||||
authors = [
|
authors = [
|
||||||
"Nikolay Kim <fafhrd91@gmail.com>",
|
"Nikolay Kim <fafhrd91@gmail.com>",
|
||||||
"Rob Ede <robjtede@icloud.com>",
|
"Rob Ede <robjtede@icloud.com>",
|
||||||
@@ -29,13 +29,13 @@ openssl = ["tls-openssl", "actix-http/openssl", "awc/openssl"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-codec = "0.4.1"
|
actix-codec = "0.4.1"
|
||||||
actix-http = "3.0.0-beta.15"
|
actix-http = "3.0.0-beta.14"
|
||||||
actix-http-test = "3.0.0-beta.9"
|
actix-http-test = "3.0.0-beta.7"
|
||||||
actix-rt = "2.1"
|
|
||||||
actix-service = "2.0.0"
|
actix-service = "2.0.0"
|
||||||
actix-utils = "3.0.0"
|
actix-utils = "3.0.0"
|
||||||
actix-web = { version = "4.0.0-beta.14", default-features = false, features = ["cookies"] }
|
actix-web = { version = "4.0.0-beta.11", default-features = false, features = ["cookies"] }
|
||||||
awc = { version = "3.0.0-beta.13", default-features = false, features = ["cookies"] }
|
actix-rt = "2.1"
|
||||||
|
awc = { version = "3.0.0-beta.11", default-features = false, features = ["cookies"] }
|
||||||
|
|
||||||
futures-core = { version = "0.3.7", default-features = false, features = ["std"] }
|
futures-core = { version = "0.3.7", default-features = false, features = ["std"] }
|
||||||
futures-util = { version = "0.3.7", default-features = false, features = [] }
|
futures-util = { version = "0.3.7", default-features = false, features = [] }
|
||||||
|
@@ -163,9 +163,11 @@ where
|
|||||||
local_addr,
|
local_addr,
|
||||||
);
|
);
|
||||||
|
|
||||||
let fac = factory()
|
let fac = factory().into_factory().map_err(|err| {
|
||||||
.into_factory()
|
let res: actix_http::Response<_> =
|
||||||
.map_err(|err| err.into().error_response());
|
err.into().error_response().into();
|
||||||
|
res.map_into_boxed_body()
|
||||||
|
});
|
||||||
|
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.client_timeout(timeout)
|
.client_timeout(timeout)
|
||||||
@@ -179,9 +181,11 @@ where
|
|||||||
local_addr,
|
local_addr,
|
||||||
);
|
);
|
||||||
|
|
||||||
let fac = factory()
|
let fac = factory().into_factory().map_err(|err| {
|
||||||
.into_factory()
|
let res: actix_http::Response<_> =
|
||||||
.map_err(|err| err.into().error_response());
|
err.into().error_response().into();
|
||||||
|
res.map_into_boxed_body()
|
||||||
|
});
|
||||||
|
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.client_timeout(timeout)
|
.client_timeout(timeout)
|
||||||
@@ -195,9 +199,11 @@ where
|
|||||||
local_addr,
|
local_addr,
|
||||||
);
|
);
|
||||||
|
|
||||||
let fac = factory()
|
let fac = factory().into_factory().map_err(|err| {
|
||||||
.into_factory()
|
let res: actix_http::Response<_> =
|
||||||
.map_err(|err| err.into().error_response());
|
err.into().error_response().into();
|
||||||
|
res.map_into_boxed_body()
|
||||||
|
});
|
||||||
|
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.client_timeout(timeout)
|
.client_timeout(timeout)
|
||||||
@@ -214,9 +220,11 @@ where
|
|||||||
local_addr,
|
local_addr,
|
||||||
);
|
);
|
||||||
|
|
||||||
let fac = factory()
|
let fac = factory().into_factory().map_err(|err| {
|
||||||
.into_factory()
|
let res: actix_http::Response<_> =
|
||||||
.map_err(|err| err.into().error_response());
|
err.into().error_response().into();
|
||||||
|
res.map_into_boxed_body()
|
||||||
|
});
|
||||||
|
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.client_timeout(timeout)
|
.client_timeout(timeout)
|
||||||
@@ -230,9 +238,11 @@ where
|
|||||||
local_addr,
|
local_addr,
|
||||||
);
|
);
|
||||||
|
|
||||||
let fac = factory()
|
let fac = factory().into_factory().map_err(|err| {
|
||||||
.into_factory()
|
let res: actix_http::Response<_> =
|
||||||
.map_err(|err| err.into().error_response());
|
err.into().error_response().into();
|
||||||
|
res.map_into_boxed_body()
|
||||||
|
});
|
||||||
|
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.client_timeout(timeout)
|
.client_timeout(timeout)
|
||||||
@@ -246,9 +256,11 @@ where
|
|||||||
local_addr,
|
local_addr,
|
||||||
);
|
);
|
||||||
|
|
||||||
let fac = factory()
|
let fac = factory().into_factory().map_err(|err| {
|
||||||
.into_factory()
|
let res: actix_http::Response<_> =
|
||||||
.map_err(|err| err.into().error_response());
|
err.into().error_response().into();
|
||||||
|
res.map_into_boxed_body()
|
||||||
|
});
|
||||||
|
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.client_timeout(timeout)
|
.client_timeout(timeout)
|
||||||
@@ -265,9 +277,11 @@ where
|
|||||||
local_addr,
|
local_addr,
|
||||||
);
|
);
|
||||||
|
|
||||||
let fac = factory()
|
let fac = factory().into_factory().map_err(|err| {
|
||||||
.into_factory()
|
let res: actix_http::Response<_> =
|
||||||
.map_err(|err| err.into().error_response());
|
err.into().error_response().into();
|
||||||
|
res.map_into_boxed_body()
|
||||||
|
});
|
||||||
|
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.client_timeout(timeout)
|
.client_timeout(timeout)
|
||||||
@@ -281,9 +295,11 @@ where
|
|||||||
local_addr,
|
local_addr,
|
||||||
);
|
);
|
||||||
|
|
||||||
let fac = factory()
|
let fac = factory().into_factory().map_err(|err| {
|
||||||
.into_factory()
|
let res: actix_http::Response<_> =
|
||||||
.map_err(|err| err.into().error_response());
|
err.into().error_response().into();
|
||||||
|
res.map_into_boxed_body()
|
||||||
|
});
|
||||||
|
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.client_timeout(timeout)
|
.client_timeout(timeout)
|
||||||
@@ -297,9 +313,11 @@ where
|
|||||||
local_addr,
|
local_addr,
|
||||||
);
|
);
|
||||||
|
|
||||||
let fac = factory()
|
let fac = factory().into_factory().map_err(|err| {
|
||||||
.into_factory()
|
let res: actix_http::Response<_> =
|
||||||
.map_err(|err| err.into().error_response());
|
err.into().error_response().into();
|
||||||
|
res.map_into_boxed_body()
|
||||||
|
});
|
||||||
|
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.client_timeout(timeout)
|
.client_timeout(timeout)
|
||||||
|
@@ -1,9 +1,6 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
|
|
||||||
|
|
||||||
## 4.0.0-beta.8 - 2021-12-11
|
|
||||||
* Add `ws:WsResponseBuilder` for building WebSocket session response. [#1920]
|
* Add `ws:WsResponseBuilder` for building WebSocket session response. [#1920]
|
||||||
* Deprecate `ws::{start_with_addr, start_with_protocols}`. [#1920]
|
* Deprecate `ws::{start_with_addr, start_with_protocols}`. [#1920]
|
||||||
* Minimum supported Rust version (MSRV) is now 1.52.
|
* Minimum supported Rust version (MSRV) is now 1.52.
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "actix-web-actors"
|
name = "actix-web-actors"
|
||||||
version = "4.0.0-beta.8"
|
version = "4.0.0-beta.7"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||||
description = "Actix actors support for Actix Web"
|
description = "Actix actors support for Actix Web"
|
||||||
keywords = ["actix", "http", "web", "framework", "async"]
|
keywords = ["actix", "http", "web", "framework", "async"]
|
||||||
@@ -16,8 +16,8 @@ path = "src/lib.rs"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
actix = { version = "0.12.0", default-features = false }
|
actix = { version = "0.12.0", default-features = false }
|
||||||
actix-codec = "0.4.1"
|
actix-codec = "0.4.1"
|
||||||
actix-http = "3.0.0-beta.15"
|
actix-http = "3.0.0-beta.14"
|
||||||
actix-web = { version = "4.0.0-beta.14", default-features = false }
|
actix-web = { version = "4.0.0-beta.11", default-features = false }
|
||||||
|
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
bytestring = "1"
|
bytestring = "1"
|
||||||
@@ -27,8 +27,8 @@ tokio = { version = "1", features = ["sync"] }
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix-rt = "2.2"
|
actix-rt = "2.2"
|
||||||
actix-test = "0.1.0-beta.8"
|
actix-test = "0.1.0-beta.7"
|
||||||
awc = { version = "3.0.0-beta.13", default-features = false }
|
|
||||||
|
|
||||||
|
awc = { version = "3.0.0-beta.11", default-features = false }
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
futures-util = { version = "0.3.7", default-features = false }
|
futures-util = { version = "0.3.7", default-features = false }
|
||||||
|
@@ -3,11 +3,11 @@
|
|||||||
> Actix actors support for Actix Web.
|
> Actix actors support for Actix Web.
|
||||||
|
|
||||||
[](https://crates.io/crates/actix-web-actors)
|
[](https://crates.io/crates/actix-web-actors)
|
||||||
[](https://docs.rs/actix-web-actors/4.0.0-beta.8)
|
[](https://docs.rs/actix-web-actors/4.0.0-beta.7)
|
||||||
[](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html)
|
[](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html)
|
||||||

|

|
||||||
<br />
|
<br />
|
||||||
[](https://deps.rs/crate/actix-web-actors/4.0.0-beta.8)
|
[](https://deps.rs/crate/actix-web-actors/4.0.0-beta.7)
|
||||||
[](https://crates.io/crates/actix-web-actors)
|
[](https://crates.io/crates/actix-web-actors)
|
||||||
[](https://discord.gg/NWpN5mmg3x)
|
[](https://discord.gg/NWpN5mmg3x)
|
||||||
|
|
||||||
|
@@ -3,10 +3,6 @@
|
|||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
|
|
||||||
|
|
||||||
## 0.5.0-beta.6 - 2021-12-11
|
|
||||||
* No significant changes since `0.5.0-beta.5`.
|
|
||||||
|
|
||||||
|
|
||||||
## 0.5.0-beta.5 - 2021-10-20
|
## 0.5.0-beta.5 - 2021-10-20
|
||||||
* Improve error recovery potential when macro input is invalid. [#2410]
|
* Improve error recovery potential when macro input is invalid. [#2410]
|
||||||
* Add `#[actix_web::test]` macro for setting up tests with a runtime. [#2409]
|
* Add `#[actix_web::test]` macro for setting up tests with a runtime. [#2409]
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "actix-web-codegen"
|
name = "actix-web-codegen"
|
||||||
version = "0.5.0-beta.6"
|
version = "0.5.0-beta.5"
|
||||||
description = "Routing and runtime macros for Actix Web"
|
description = "Routing and runtime macros for Actix Web"
|
||||||
homepage = "https://actix.rs"
|
homepage = "https://actix.rs"
|
||||||
repository = "https://github.com/actix/actix-web.git"
|
repository = "https://github.com/actix/actix-web.git"
|
||||||
@@ -21,11 +21,11 @@ proc-macro2 = "1"
|
|||||||
actix-router = "0.5.0-beta.2"
|
actix-router = "0.5.0-beta.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix-macros = "0.2.3"
|
|
||||||
actix-rt = "2.2"
|
actix-rt = "2.2"
|
||||||
actix-test = "0.1.0-beta.8"
|
actix-macros = "0.2.3"
|
||||||
|
actix-test = "0.1.0-beta.7"
|
||||||
actix-utils = "3.0.0"
|
actix-utils = "3.0.0"
|
||||||
actix-web = "4.0.0-beta.14"
|
actix-web = "4.0.0-beta.11"
|
||||||
|
|
||||||
futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] }
|
futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] }
|
||||||
trybuild = "1"
|
trybuild = "1"
|
||||||
|
@@ -3,11 +3,11 @@
|
|||||||
> Routing and runtime macros for Actix Web.
|
> Routing and runtime macros for Actix Web.
|
||||||
|
|
||||||
[](https://crates.io/crates/actix-web-codegen)
|
[](https://crates.io/crates/actix-web-codegen)
|
||||||
[](https://docs.rs/actix-web-codegen/0.5.0-beta.6)
|
[](https://docs.rs/actix-web-codegen/0.5.0-beta.5)
|
||||||
[](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html)
|
[](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html)
|
||||||

|

|
||||||
<br />
|
<br />
|
||||||
[](https://deps.rs/crate/actix-web-codegen/0.5.0-beta.6)
|
[](https://deps.rs/crate/actix-web-codegen/0.5.0-beta.5)
|
||||||
[](https://crates.io/crates/actix-web-codegen)
|
[](https://crates.io/crates/actix-web-codegen)
|
||||||
[](https://discord.gg/NWpN5mmg3x)
|
[](https://discord.gg/NWpN5mmg3x)
|
||||||
|
|
||||||
|
@@ -3,10 +3,6 @@
|
|||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
|
|
||||||
|
|
||||||
## 3.0.0-beta.13 - 2021-12-11
|
|
||||||
* No significant changes since `3.0.0-beta.12`.
|
|
||||||
|
|
||||||
|
|
||||||
## 3.0.0-beta.12 - 2021-11-30
|
## 3.0.0-beta.12 - 2021-11-30
|
||||||
* Update `actix-tls` to `3.0.0-rc.1`. [#2474]
|
* Update `actix-tls` to `3.0.0-rc.1`. [#2474]
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "awc"
|
name = "awc"
|
||||||
version = "3.0.0-beta.13"
|
version = "3.0.0-beta.12"
|
||||||
authors = [
|
authors = [
|
||||||
"Nikolay Kim <fafhrd91@gmail.com>",
|
"Nikolay Kim <fafhrd91@gmail.com>",
|
||||||
"fakeshadow <24548779@qq.com>",
|
"fakeshadow <24548779@qq.com>",
|
||||||
@@ -60,7 +60,7 @@ dangerous-h2c = []
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
actix-codec = "0.4.1"
|
actix-codec = "0.4.1"
|
||||||
actix-service = "2.0.0"
|
actix-service = "2.0.0"
|
||||||
actix-http = "3.0.0-beta.15"
|
actix-http = "3.0.0-beta.14"
|
||||||
actix-rt = { version = "2.1", default-features = false }
|
actix-rt = { version = "2.1", default-features = false }
|
||||||
actix-tls = { version = "3.0.0-rc.1", features = ["connect", "uri"] }
|
actix-tls = { version = "3.0.0-rc.1", features = ["connect", "uri"] }
|
||||||
actix-utils = "3.0.0"
|
actix-utils = "3.0.0"
|
||||||
@@ -72,7 +72,7 @@ cfg-if = "1"
|
|||||||
derive_more = "0.99.5"
|
derive_more = "0.99.5"
|
||||||
futures-core = { version = "0.3.7", default-features = false }
|
futures-core = { version = "0.3.7", default-features = false }
|
||||||
futures-util = { version = "0.3.7", default-features = false }
|
futures-util = { version = "0.3.7", default-features = false }
|
||||||
h2 = "0.3.9"
|
h2 = "0.3"
|
||||||
http = "0.2.5"
|
http = "0.2.5"
|
||||||
itoa = "0.4"
|
itoa = "0.4"
|
||||||
log =" 0.4"
|
log =" 0.4"
|
||||||
@@ -93,13 +93,13 @@ tls-rustls = { package = "rustls", version = "0.20.0", optional = true, features
|
|||||||
trust-dns-resolver = { version = "0.20.0", optional = true }
|
trust-dns-resolver = { version = "0.20.0", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix-http = { version = "3.0.0-beta.15", features = ["openssl"] }
|
actix-web = { version = "4.0.0-beta.11", features = ["openssl"] }
|
||||||
actix-http-test = { version = "3.0.0-beta.9", features = ["openssl"] }
|
actix-http = { version = "3.0.0-beta.14", features = ["openssl"] }
|
||||||
actix-server = "2.0.0-rc.1"
|
actix-http-test = { version = "3.0.0-beta.7", features = ["openssl"] }
|
||||||
actix-test = { version = "0.1.0-beta.8", features = ["openssl", "rustls"] }
|
|
||||||
actix-tls = { version = "3.0.0-rc.1", features = ["openssl", "rustls"] }
|
|
||||||
actix-utils = "3.0.0"
|
actix-utils = "3.0.0"
|
||||||
actix-web = { version = "4.0.0-beta.14", features = ["openssl"] }
|
actix-server = "2.0.0-rc.1"
|
||||||
|
actix-tls = { version = "3.0.0-rc.1", features = ["openssl", "rustls"] }
|
||||||
|
actix-test = { version = "0.1.0-beta.7", features = ["openssl", "rustls"] }
|
||||||
|
|
||||||
brotli2 = "0.3.2"
|
brotli2 = "0.3.2"
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
|
@@ -3,9 +3,9 @@
|
|||||||
> Async HTTP and WebSocket client library.
|
> Async HTTP and WebSocket client library.
|
||||||
|
|
||||||
[](https://crates.io/crates/awc)
|
[](https://crates.io/crates/awc)
|
||||||
[](https://docs.rs/awc/3.0.0-beta.13)
|
[](https://docs.rs/awc/3.0.0-beta.12)
|
||||||

|

|
||||||
[](https://deps.rs/crate/awc/3.0.0-beta.13)
|
[](https://deps.rs/crate/awc/3.0.0-beta.12)
|
||||||
[](https://discord.gg/NWpN5mmg3x)
|
[](https://discord.gg/NWpN5mmg3x)
|
||||||
|
|
||||||
## Documentation & Resources
|
## Documentation & Resources
|
||||||
|
31
scripts/bump
31
scripts/bump
@@ -41,8 +41,6 @@ cat "$CHANGELOG_FILE" |
|
|||||||
# if word count of changelog chunk is 0 then insert filler changelog chunk
|
# if word count of changelog chunk is 0 then insert filler changelog chunk
|
||||||
if [ "$(wc -w "$CHANGE_CHUNK_FILE" | awk '{ print $1 }')" = "0" ]; then
|
if [ "$(wc -w "$CHANGE_CHUNK_FILE" | awk '{ print $1 }')" = "0" ]; then
|
||||||
echo "* No significant changes since \`$CURRENT_VERSION\`." >"$CHANGE_CHUNK_FILE"
|
echo "* No significant changes since \`$CURRENT_VERSION\`." >"$CHANGE_CHUNK_FILE"
|
||||||
echo >>"$CHANGE_CHUNK_FILE"
|
|
||||||
echo >>"$CHANGE_CHUNK_FILE"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "${2-}" ]; then
|
if [ -n "${2-}" ]; then
|
||||||
@@ -84,33 +82,8 @@ rm -f $README_FILE.bak
|
|||||||
echo "manifest, changelog, and readme updated"
|
echo "manifest, changelog, and readme updated"
|
||||||
echo
|
echo
|
||||||
echo "check other references:"
|
echo "check other references:"
|
||||||
rg --glob='**/Cargo.toml' "\
|
rg "$PACKAGE_NAME =" || true
|
||||||
${PACKAGE_NAME} ?= ?\"[^\"]+\"\
|
rg "package = \"$PACKAGE_NAME\"" || true
|
||||||
|${PACKAGE_NAME} ?=.*version ?= ?\"([^\"]+)\"\
|
|
||||||
|package ?= ?\"${PACKAGE_NAME}\".*version ?= ?\"([^\"]+)\"\
|
|
||||||
|version ?= ?\"([^\"]+)\".*package ?= ?\"${PACKAGE_NAME}\"" || true
|
|
||||||
|
|
||||||
echo
|
|
||||||
read -p "Update all references: (y/N) " UPDATE_REFERENCES
|
|
||||||
UPDATE_REFERENCES="${UPDATE_REFERENCES:-n}"
|
|
||||||
|
|
||||||
if [ "$UPDATE_REFERENCES" = 'y' ] || [ "$UPDATE_REFERENCES" = 'Y' ]; then
|
|
||||||
|
|
||||||
for f in $(fd Cargo.toml); do
|
|
||||||
sed -i.bak -E \
|
|
||||||
"s/^(${PACKAGE_NAME} ?= ?\")[^\"]+(\")$/\1${NEW_VERSION}\2/g" $f
|
|
||||||
sed -i.bak -E \
|
|
||||||
"s/^(${PACKAGE_NAME} ?=.*version ?= ?\")[^\"]+(\".*)$/\1${NEW_VERSION}\2/g" $f
|
|
||||||
sed -i.bak -E \
|
|
||||||
"s/^(.*package ?= ?\"${PACKAGE_NAME}\".*version ?= ?\")[^\"]+(\".*)$/\1${NEW_VERSION}\2/g" $f
|
|
||||||
sed -i.bak -E \
|
|
||||||
"s/^(.*version ?= ?\")[^\"]+(\".*package ?= ?\"${PACKAGE_NAME}\".*)$/\1${NEW_VERSION}\2/g" $f
|
|
||||||
|
|
||||||
# remove backup file
|
|
||||||
rm -f $f.bak
|
|
||||||
done
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $MACOS ]; then
|
if [ $MACOS ]; then
|
||||||
printf "prepare $PACKAGE_NAME release $NEW_VERSION" | pbcopy
|
printf "prepare $PACKAGE_NAME release $NEW_VERSION" | pbcopy
|
||||||
|
146
src/any_body.rs
Normal file
146
src/any_body.rs
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
use std::{
|
||||||
|
error::Error as StdError,
|
||||||
|
mem,
|
||||||
|
pin::Pin,
|
||||||
|
task::{Context, Poll},
|
||||||
|
};
|
||||||
|
|
||||||
|
use actix_http::body::{BodySize, BoxBody, MessageBody};
|
||||||
|
use bytes::Bytes;
|
||||||
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
|
use crate::Error;
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[project = AnyBodyProj]
|
||||||
|
pub enum AnyBody<B = BoxBody> {
|
||||||
|
None,
|
||||||
|
Full { body: Bytes },
|
||||||
|
Stream { #[pin] body: B },
|
||||||
|
Boxed { body: BoxBody },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: MessageBody + 'static> AnyBody<B> {
|
||||||
|
pub fn into_body<B1>(self) -> AnyBody<B1> {
|
||||||
|
match self {
|
||||||
|
AnyBody::None => AnyBody::None,
|
||||||
|
AnyBody::Full { body } => AnyBody::Full { body },
|
||||||
|
AnyBody::Stream { body } => AnyBody::Boxed {
|
||||||
|
body: BoxBody::new(body),
|
||||||
|
},
|
||||||
|
AnyBody::Boxed { body } => AnyBody::Boxed { body },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B> Default for AnyBody<B> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Full { body: Bytes::new() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B> MessageBody for AnyBody<B>
|
||||||
|
where
|
||||||
|
B: MessageBody,
|
||||||
|
B::Error: 'static,
|
||||||
|
{
|
||||||
|
type Error = Box<dyn StdError>;
|
||||||
|
|
||||||
|
fn size(&self) -> BodySize {
|
||||||
|
match self {
|
||||||
|
Self::None => BodySize::None,
|
||||||
|
Self::Full { body } => body.size(),
|
||||||
|
Self::Stream { body } => body.size(),
|
||||||
|
Self::Boxed { body } => body.size(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_next(
|
||||||
|
self: Pin<&mut Self>,
|
||||||
|
cx: &mut Context<'_>,
|
||||||
|
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||||
|
match self.project() {
|
||||||
|
AnyBodyProj::None => Poll::Ready(None),
|
||||||
|
AnyBodyProj::Full { body } => {
|
||||||
|
let bytes = mem::take(body);
|
||||||
|
Poll::Ready(Some(Ok(bytes)))
|
||||||
|
}
|
||||||
|
AnyBodyProj::Stream { body } => body.poll_next(cx).map_err(|err| err.into()),
|
||||||
|
AnyBodyProj::Boxed { body } => body.as_pin_mut().poll_next(cx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pin_project! {
|
||||||
|
#[project = EitherAnyBodyProj]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum EitherAnyBody<L, R = BoxBody> {
|
||||||
|
/// A body of type `L`.
|
||||||
|
Left { #[pin] body: AnyBody<L> },
|
||||||
|
|
||||||
|
/// A body of type `R`.
|
||||||
|
Right { #[pin] body: AnyBody<R> },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl<L> EitherAnyBody<L, BoxBody> {
|
||||||
|
// /// Creates new `EitherBody` using left variant and boxed right variant.
|
||||||
|
// pub fn new(body: L) -> Self {
|
||||||
|
// Self::Left {
|
||||||
|
// body: AnyBody::Stream { body },
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl<L, R> EitherAnyBody<L, R> {
|
||||||
|
// /// Creates new `EitherBody` using left variant.
|
||||||
|
// pub fn left(body: L) -> Self {
|
||||||
|
// Self::Left {
|
||||||
|
// body: AnyBody::Stream { body },
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /// Creates new `EitherBody` using right variant.
|
||||||
|
// pub fn right(body: R) -> Self {
|
||||||
|
// Self::Right {
|
||||||
|
// body: AnyBody::Stream { body },
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
impl<L, R> MessageBody for EitherAnyBody<L, R>
|
||||||
|
where
|
||||||
|
L: MessageBody + 'static,
|
||||||
|
R: MessageBody + 'static,
|
||||||
|
{
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn size(&self) -> BodySize {
|
||||||
|
match self {
|
||||||
|
Self::Left { body } => body.size(),
|
||||||
|
Self::Right { body } => body.size(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_next(
|
||||||
|
self: Pin<&mut Self>,
|
||||||
|
cx: &mut Context<'_>,
|
||||||
|
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||||
|
match self.project() {
|
||||||
|
EitherAnyBodyProj::Left { body } => body.poll_next(cx).map_err(Error::from),
|
||||||
|
EitherAnyBodyProj::Right { body } => body.poll_next(cx).map_err(Error::from),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use static_assertions::assert_eq_size;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
assert_eq_size!(AnyBody<()>, [u8; 40]);
|
||||||
|
assert_eq_size!(AnyBody<u64>, [u8; 40]); // how is this the same size as ()
|
||||||
|
}
|
38
src/dev.rs
38
src/dev.rs
@@ -102,41 +102,3 @@ impl<B> BodyEncoding for crate::HttpResponse<B> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove this if it doesn't appear to be needed
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) enum AnyBody {
|
|
||||||
None,
|
|
||||||
Full { body: crate::web::Bytes },
|
|
||||||
Boxed { body: actix_http::body::BoxBody },
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::body::MessageBody for AnyBody {
|
|
||||||
type Error = crate::BoxError;
|
|
||||||
|
|
||||||
/// Body size hint.
|
|
||||||
fn size(&self) -> crate::body::BodySize {
|
|
||||||
match self {
|
|
||||||
AnyBody::None => crate::body::BodySize::None,
|
|
||||||
AnyBody::Full { body } => body.size(),
|
|
||||||
AnyBody::Boxed { body } => body.size(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Attempt to pull out the next chunk of body bytes.
|
|
||||||
fn poll_next(
|
|
||||||
self: std::pin::Pin<&mut Self>,
|
|
||||||
cx: &mut std::task::Context<'_>,
|
|
||||||
) -> std::task::Poll<Option<Result<crate::web::Bytes, Self::Error>>> {
|
|
||||||
match self.get_mut() {
|
|
||||||
AnyBody::None => std::task::Poll::Ready(None),
|
|
||||||
AnyBody::Full { body } => {
|
|
||||||
let bytes = std::mem::take(body);
|
|
||||||
std::task::Poll::Ready(Some(Ok(bytes)))
|
|
||||||
}
|
|
||||||
AnyBody::Boxed { body } => body.as_pin_mut().poll_next(cx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -2,7 +2,7 @@ use std::{error::Error as StdError, fmt};
|
|||||||
|
|
||||||
use actix_http::{body::BoxBody, Response};
|
use actix_http::{body::BoxBody, Response};
|
||||||
|
|
||||||
use crate::{HttpResponse, ResponseError};
|
use crate::{any_body::AnyBody, HttpResponse, ResponseError};
|
||||||
|
|
||||||
/// General purpose actix web error.
|
/// General purpose actix web error.
|
||||||
///
|
///
|
||||||
@@ -69,8 +69,15 @@ impl<T: ResponseError + 'static> From<T> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Error> for Response<BoxBody> {
|
impl From<Error> for Response<AnyBody<BoxBody>> {
|
||||||
fn from(err: Error) -> Response<BoxBody> {
|
fn from(err: Error) -> Self {
|
||||||
err.error_response().into()
|
err.error_response().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Error> for actix_http::Response<BoxBody> {
|
||||||
|
fn from(err: Error) -> Self {
|
||||||
|
let res: actix_http::Response<_> = err.error_response().into();
|
||||||
|
res.map_into_boxed_body()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -7,7 +7,7 @@ use actix_http::{
|
|||||||
};
|
};
|
||||||
use bytes::{BufMut as _, BytesMut};
|
use bytes::{BufMut as _, BytesMut};
|
||||||
|
|
||||||
use crate::{Error, HttpRequest, HttpResponse, Responder, ResponseError};
|
use crate::{any_body::AnyBody, Error, HttpRequest, HttpResponse, Responder, ResponseError};
|
||||||
|
|
||||||
/// Wraps errors to alter the generated response status code.
|
/// Wraps errors to alter the generated response status code.
|
||||||
///
|
///
|
||||||
@@ -91,7 +91,9 @@ where
|
|||||||
let mime = mime::TEXT_PLAIN_UTF_8.try_into_value().unwrap();
|
let mime = mime::TEXT_PLAIN_UTF_8.try_into_value().unwrap();
|
||||||
res.headers_mut().insert(header::CONTENT_TYPE, mime);
|
res.headers_mut().insert(header::CONTENT_TYPE, mime);
|
||||||
|
|
||||||
res.set_body(BoxBody::new(buf.into_inner()))
|
res.set_body(AnyBody::Full {
|
||||||
|
body: buf.into_inner().freeze(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalErrorType::Response(ref resp) => {
|
InternalErrorType::Response(ref resp) => {
|
||||||
|
@@ -14,6 +14,7 @@ use actix_http::{
|
|||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
any_body::AnyBody,
|
||||||
error::{downcast_dyn, downcast_get_type_id},
|
error::{downcast_dyn, downcast_get_type_id},
|
||||||
helpers, HttpResponse,
|
helpers, HttpResponse,
|
||||||
};
|
};
|
||||||
@@ -33,7 +34,7 @@ pub trait ResponseError: fmt::Debug + fmt::Display {
|
|||||||
///
|
///
|
||||||
/// By default, the generated response uses a 500 Internal Server Error status code, a
|
/// By default, the generated response uses a 500 Internal Server Error status code, a
|
||||||
/// `Content-Type` of `text/plain`, and the body is set to `Self`'s `Display` impl.
|
/// `Content-Type` of `text/plain`, and the body is set to `Self`'s `Display` impl.
|
||||||
fn error_response(&self) -> HttpResponse<BoxBody> {
|
fn error_response(&self) -> HttpResponse {
|
||||||
let mut res = HttpResponse::new(self.status_code());
|
let mut res = HttpResponse::new(self.status_code());
|
||||||
|
|
||||||
let mut buf = BytesMut::new();
|
let mut buf = BytesMut::new();
|
||||||
@@ -42,7 +43,7 @@ pub trait ResponseError: fmt::Debug + fmt::Display {
|
|||||||
let mime = mime::TEXT_PLAIN_UTF_8.try_into_value().unwrap();
|
let mime = mime::TEXT_PLAIN_UTF_8.try_into_value().unwrap();
|
||||||
res.headers_mut().insert(header::CONTENT_TYPE, mime);
|
res.headers_mut().insert(header::CONTENT_TYPE, mime);
|
||||||
|
|
||||||
res.set_body(BoxBody::new(buf))
|
res.set_body(AnyBody::Full { body: buf.freeze() })
|
||||||
}
|
}
|
||||||
|
|
||||||
downcast_get_type_id!();
|
downcast_get_type_id!();
|
||||||
@@ -50,7 +51,7 @@ pub trait ResponseError: fmt::Debug + fmt::Display {
|
|||||||
|
|
||||||
downcast_dyn!(ResponseError);
|
downcast_dyn!(ResponseError);
|
||||||
|
|
||||||
impl ResponseError for Box<dyn StdError + 'static> {}
|
impl ResponseError for Box<dyn StdError> {}
|
||||||
|
|
||||||
#[cfg(feature = "openssl")]
|
#[cfg(feature = "openssl")]
|
||||||
impl ResponseError for actix_tls::accept::openssl::reexports::Error {}
|
impl ResponseError for actix_tls::accept::openssl::reexports::Error {}
|
||||||
@@ -128,7 +129,15 @@ impl ResponseError for actix_http::error::ContentTypeError {
|
|||||||
|
|
||||||
impl ResponseError for actix_http::ws::HandshakeError {
|
impl ResponseError for actix_http::ws::HandshakeError {
|
||||||
fn error_response(&self) -> HttpResponse<BoxBody> {
|
fn error_response(&self) -> HttpResponse<BoxBody> {
|
||||||
Response::from(self).map_into_boxed_body().into()
|
Response::from(self)
|
||||||
|
.map_body(|_, body| AnyBody::Boxed { body })
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ResponseError for actix_http::error::EncoderError {
|
||||||
|
fn error_response(&self) -> HttpResponse {
|
||||||
|
todo!("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -70,6 +70,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")]
|
||||||
|
|
||||||
|
mod any_body;
|
||||||
mod app;
|
mod app;
|
||||||
mod app_service;
|
mod app_service;
|
||||||
mod config;
|
mod config;
|
||||||
|
@@ -10,7 +10,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body::{EitherBody, MessageBody},
|
body::MessageBody,
|
||||||
encoding::Encoder,
|
encoding::Encoder,
|
||||||
header::{ContentEncoding, ACCEPT_ENCODING},
|
header::{ContentEncoding, ACCEPT_ENCODING},
|
||||||
StatusCode,
|
StatusCode,
|
||||||
@@ -22,6 +22,7 @@ use once_cell::sync::Lazy;
|
|||||||
use pin_project_lite::pin_project;
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
any_body::AnyBody,
|
||||||
dev::BodyEncoding,
|
dev::BodyEncoding,
|
||||||
service::{ServiceRequest, ServiceResponse},
|
service::{ServiceRequest, ServiceResponse},
|
||||||
Error, HttpResponse,
|
Error, HttpResponse,
|
||||||
@@ -61,7 +62,7 @@ where
|
|||||||
B: MessageBody,
|
B: MessageBody,
|
||||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||||
{
|
{
|
||||||
type Response = ServiceResponse<EitherBody<Encoder<B>>>;
|
type Response = ServiceResponse<Encoder<AnyBody<B>>>;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Transform = CompressMiddleware<S>;
|
type Transform = CompressMiddleware<S>;
|
||||||
type InitError = ();
|
type InitError = ();
|
||||||
@@ -111,7 +112,7 @@ where
|
|||||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||||
B: MessageBody,
|
B: MessageBody,
|
||||||
{
|
{
|
||||||
type Response = ServiceResponse<EitherBody<Encoder<B>>>;
|
type Response = ServiceResponse<Encoder<AnyBody<B>>>;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Future = Either<CompressResponse<S, B>, Ready<Result<Self::Response, Self::Error>>>;
|
type Future = Either<CompressResponse<S, B>, Ready<Result<Self::Response, Self::Error>>>;
|
||||||
|
|
||||||
@@ -146,12 +147,15 @@ where
|
|||||||
let res = HttpResponse::with_body(
|
let res = HttpResponse::with_body(
|
||||||
StatusCode::NOT_ACCEPTABLE,
|
StatusCode::NOT_ACCEPTABLE,
|
||||||
SUPPORTED_ALGORITHM_NAMES.clone(),
|
SUPPORTED_ALGORITHM_NAMES.clone(),
|
||||||
);
|
)
|
||||||
|
.map_body(|_, body| match body {
|
||||||
|
AnyBody::Full { body } => AnyBody::Stream {
|
||||||
|
body: Encoder::not_acceptable(body),
|
||||||
|
},
|
||||||
|
_ => unreachable!("probably"),
|
||||||
|
});
|
||||||
|
|
||||||
Either::right(ok(req
|
Either::right(ok(req.into_response(res)))
|
||||||
.into_response(res)
|
|
||||||
.map_into_boxed_body()
|
|
||||||
.map_into_right_body()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,7 +178,7 @@ where
|
|||||||
B: MessageBody,
|
B: MessageBody,
|
||||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||||
{
|
{
|
||||||
type Output = Result<ServiceResponse<EitherBody<Encoder<B>>>, Error>;
|
type Output = Result<ServiceResponse<Encoder<AnyBody<B>>>, Error>;
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let this = self.project();
|
let this = self.project();
|
||||||
@@ -187,8 +191,8 @@ where
|
|||||||
*this.encoding
|
*this.encoding
|
||||||
};
|
};
|
||||||
|
|
||||||
Poll::Ready(Ok(resp.map_body(move |head, body| {
|
Poll::Ready(Ok(resp.map_body(move |head, body| AnyBody::Stream {
|
||||||
EitherBody::left(Encoder::response(enc, head, body))
|
body: Encoder::response(enc, head, body),
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -22,6 +22,7 @@ use regex::{Regex, RegexSet};
|
|||||||
use time::{format_description::well_known::Rfc3339, OffsetDateTime};
|
use time::{format_description::well_known::Rfc3339, OffsetDateTime};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
any_body::AnyBody,
|
||||||
body::{BodySize, MessageBody},
|
body::{BodySize, MessageBody},
|
||||||
http::header::HeaderName,
|
http::header::HeaderName,
|
||||||
service::{ServiceRequest, ServiceResponse},
|
service::{ServiceRequest, ServiceResponse},
|
||||||
@@ -175,7 +176,7 @@ impl Default for Logger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B> Transform<S, ServiceRequest> for Logger
|
impl<S, B: 'static> Transform<S, ServiceRequest> for Logger
|
||||||
where
|
where
|
||||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||||
B: MessageBody,
|
B: MessageBody,
|
||||||
@@ -210,7 +211,7 @@ pub struct LoggerMiddleware<S> {
|
|||||||
service: S,
|
service: S,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B> Service<ServiceRequest> for LoggerMiddleware<S>
|
impl<S, B: 'static> Service<ServiceRequest> for LoggerMiddleware<S>
|
||||||
where
|
where
|
||||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||||
B: MessageBody,
|
B: MessageBody,
|
||||||
@@ -262,7 +263,7 @@ pin_project! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B> Future for LoggerResponse<S, B>
|
impl<S, B: 'static> Future for LoggerResponse<S, B>
|
||||||
where
|
where
|
||||||
B: MessageBody,
|
B: MessageBody,
|
||||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||||
@@ -290,11 +291,13 @@ where
|
|||||||
let time = *this.time;
|
let time = *this.time;
|
||||||
let format = this.format.take();
|
let format = this.format.take();
|
||||||
|
|
||||||
Poll::Ready(Ok(res.map_body(move |_, body| StreamLog {
|
Poll::Ready(Ok(res.map_body(move |_, body| AnyBody::Stream {
|
||||||
body,
|
body: StreamLog {
|
||||||
time,
|
body: body.into_body(),
|
||||||
format,
|
time,
|
||||||
size: 0,
|
format,
|
||||||
|
size: 0,
|
||||||
|
},
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -302,7 +305,7 @@ where
|
|||||||
pin_project! {
|
pin_project! {
|
||||||
pub struct StreamLog<B> {
|
pub struct StreamLog<B> {
|
||||||
#[pin]
|
#[pin]
|
||||||
body: B,
|
body: AnyBody<B>,
|
||||||
format: Option<Format>,
|
format: Option<Format>,
|
||||||
size: usize,
|
size: usize,
|
||||||
time: OffsetDateTime,
|
time: OffsetDateTime,
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body::{BoxBody, EitherBody, MessageBody},
|
body::{BoxBody, MessageBody},
|
||||||
error::HttpError,
|
error::HttpError,
|
||||||
header::HeaderMap,
|
header::HeaderMap,
|
||||||
header::IntoHeaderPair,
|
header::IntoHeaderPair,
|
||||||
@@ -9,7 +9,9 @@ use actix_http::{
|
|||||||
};
|
};
|
||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
|
|
||||||
use crate::{BoxError, Error, HttpRequest, HttpResponse, HttpResponseBuilder};
|
use crate::{
|
||||||
|
any_body::AnyBody, BoxError, Error, HttpRequest, HttpResponse, HttpResponseBuilder,
|
||||||
|
};
|
||||||
|
|
||||||
/// Trait implemented by types that can be converted to an HTTP response.
|
/// Trait implemented by types that can be converted to an HTTP response.
|
||||||
///
|
///
|
||||||
@@ -72,7 +74,7 @@ impl Responder for HttpResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Responder for actix_http::Response<BoxBody> {
|
impl Responder for actix_http::Response<AnyBody<BoxBody>> {
|
||||||
type Body = BoxBody;
|
type Body = BoxBody;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -95,7 +97,10 @@ impl Responder for actix_http::ResponseBuilder {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn respond_to(mut self, req: &HttpRequest) -> HttpResponse<Self::Body> {
|
fn respond_to(mut self, req: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
self.finish().map_into_boxed_body().respond_to(req)
|
self.finish()
|
||||||
|
.map_into_boxed_body()
|
||||||
|
.map_body(|_, body| AnyBody::Boxed { body })
|
||||||
|
.respond_to(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,12 +109,12 @@ where
|
|||||||
T: Responder,
|
T: Responder,
|
||||||
<T::Body as MessageBody>::Error: Into<BoxError>,
|
<T::Body as MessageBody>::Error: Into<BoxError>,
|
||||||
{
|
{
|
||||||
type Body = EitherBody<T::Body>;
|
type Body = T::Body;
|
||||||
|
|
||||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
|
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
match self {
|
match self {
|
||||||
Some(val) => val.respond_to(req).map_into_left_body(),
|
Some(val) => val.respond_to(req),
|
||||||
None => HttpResponse::new(StatusCode::NOT_FOUND).map_into_right_body(),
|
None => HttpResponse::new(StatusCode::NOT_FOUND).map_into_body(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,12 +125,12 @@ where
|
|||||||
<T::Body as MessageBody>::Error: Into<BoxError>,
|
<T::Body as MessageBody>::Error: Into<BoxError>,
|
||||||
E: Into<Error>,
|
E: Into<Error>,
|
||||||
{
|
{
|
||||||
type Body = EitherBody<T::Body>;
|
type Body = T::Body;
|
||||||
|
|
||||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
|
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
match self {
|
match self {
|
||||||
Ok(val) => val.respond_to(req).map_into_left_body(),
|
Ok(val) => val.respond_to(req),
|
||||||
Err(err) => HttpResponse::from_error(err.into()).map_into_right_body(),
|
Err(err) => HttpResponse::from_error(err.into()).map_into_body(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,7 +151,12 @@ macro_rules! impl_responder_by_forward_into_base_response {
|
|||||||
type Body = $body;
|
type Body = $body;
|
||||||
|
|
||||||
fn respond_to(self, _: &HttpRequest) -> HttpResponse<Self::Body> {
|
fn respond_to(self, _: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
let res: actix_http::Response<_> = self.into();
|
let res = actix_http::Response::with_body(
|
||||||
|
StatusCode::default(),
|
||||||
|
AnyBody::Full {
|
||||||
|
body: Bytes::from(self),
|
||||||
|
},
|
||||||
|
);
|
||||||
res.into()
|
res.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,7 +181,12 @@ macro_rules! impl_into_string_responder {
|
|||||||
|
|
||||||
fn respond_to(self, _: &HttpRequest) -> HttpResponse<Self::Body> {
|
fn respond_to(self, _: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
let string: String = self.into();
|
let string: String = self.into();
|
||||||
let res: actix_http::Response<_> = string.into();
|
let res = actix_http::Response::with_body(
|
||||||
|
StatusCode::default(),
|
||||||
|
AnyBody::Full {
|
||||||
|
body: Bytes::from(string),
|
||||||
|
},
|
||||||
|
);
|
||||||
res.into()
|
res.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -250,12 +265,12 @@ where
|
|||||||
T: Responder,
|
T: Responder,
|
||||||
<T::Body as MessageBody>::Error: Into<BoxError>,
|
<T::Body as MessageBody>::Error: Into<BoxError>,
|
||||||
{
|
{
|
||||||
type Body = EitherBody<T::Body>;
|
type Body = T::Body;
|
||||||
|
|
||||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
|
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
let headers = match self.headers {
|
let headers = match self.headers {
|
||||||
Ok(headers) => headers,
|
Ok(headers) => headers,
|
||||||
Err(err) => return HttpResponse::from_error(err).map_into_right_body(),
|
Err(err) => return HttpResponse::from_error(err).map_into_body(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut res = self.responder.respond_to(req);
|
let mut res = self.responder.respond_to(req);
|
||||||
@@ -269,7 +284,7 @@ where
|
|||||||
res.headers_mut().insert(k, v);
|
res.headers_mut().insert(k, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
res.map_into_left_body()
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -22,6 +22,7 @@ use actix_http::header::HeaderValue;
|
|||||||
use cookie::{Cookie, CookieJar};
|
use cookie::{Cookie, CookieJar};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
any_body::AnyBody,
|
||||||
error::{Error, JsonPayloadError},
|
error::{Error, JsonPayloadError},
|
||||||
BoxError, HttpResponse,
|
BoxError, HttpResponse,
|
||||||
};
|
};
|
||||||
@@ -333,7 +334,7 @@ impl HttpResponseBuilder {
|
|||||||
.set_body(body);
|
.set_body(body);
|
||||||
|
|
||||||
#[allow(unused_mut)] // mut is only unused when cookies are disabled
|
#[allow(unused_mut)] // mut is only unused when cookies are disabled
|
||||||
let mut res = HttpResponse::from(res);
|
let mut res = HttpResponse::from(res.map_body(|_, body| AnyBody::Stream { body }));
|
||||||
|
|
||||||
#[cfg(feature = "cookies")]
|
#[cfg(feature = "cookies")]
|
||||||
if let Some(ref jar) = self.cookies {
|
if let Some(ref jar) = self.cookies {
|
||||||
@@ -416,7 +417,7 @@ impl From<HttpResponseBuilder> for HttpResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<HttpResponseBuilder> for Response<BoxBody> {
|
impl From<HttpResponseBuilder> for Response<AnyBody<BoxBody>> {
|
||||||
fn from(mut builder: HttpResponseBuilder) -> Self {
|
fn from(mut builder: HttpResponseBuilder) -> Self {
|
||||||
builder.finish().into()
|
builder.finish().into()
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body::{BoxBody, EitherBody, MessageBody},
|
body::{BoxBody, MessageBody, None as NoneBody},
|
||||||
header::HeaderMap,
|
header::HeaderMap,
|
||||||
Extensions, Response, ResponseHead, StatusCode,
|
Extensions, Response, ResponseHead, StatusCode,
|
||||||
};
|
};
|
||||||
@@ -22,11 +22,11 @@ use {
|
|||||||
cookie::Cookie,
|
cookie::Cookie,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{error::Error, HttpResponseBuilder};
|
use crate::{any_body::AnyBody, error::Error, HttpResponseBuilder};
|
||||||
|
|
||||||
/// An outgoing response.
|
/// An outgoing response.
|
||||||
pub struct HttpResponse<B = BoxBody> {
|
pub struct HttpResponse<B = BoxBody> {
|
||||||
res: Response<B>,
|
res: Response<AnyBody<B>>,
|
||||||
pub(crate) error: Option<Error>,
|
pub(crate) error: Option<Error>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ impl HttpResponse<BoxBody> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(status: StatusCode) -> Self {
|
pub fn new(status: StatusCode) -> Self {
|
||||||
Self {
|
Self {
|
||||||
res: Response::new(status),
|
res: Response::with_body(status, AnyBody::default()),
|
||||||
error: None,
|
error: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,6 +54,13 @@ impl HttpResponse<BoxBody> {
|
|||||||
response.error = Some(error);
|
response.error = Some(error);
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn map_into_body<B>(self) -> HttpResponse<B>
|
||||||
|
where
|
||||||
|
B: MessageBody + 'static,
|
||||||
|
{
|
||||||
|
self.map_body(|_, body| body.into_body())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> HttpResponse<B> {
|
impl<B> HttpResponse<B> {
|
||||||
@@ -61,7 +68,7 @@ impl<B> HttpResponse<B> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn with_body(status: StatusCode, body: B) -> Self {
|
pub fn with_body(status: StatusCode, body: B) -> Self {
|
||||||
Self {
|
Self {
|
||||||
res: Response::with_body(status, body),
|
res: Response::with_body(status, AnyBody::Stream { body }),
|
||||||
error: None,
|
error: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,12 +189,12 @@ impl<B> HttpResponse<B> {
|
|||||||
|
|
||||||
/// Get body of this response
|
/// Get body of this response
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn body(&self) -> &B {
|
pub fn body(&self) -> &AnyBody<B> {
|
||||||
self.res.body()
|
self.res.body()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a body
|
/// Set a body
|
||||||
pub fn set_body<B2>(self, body: B2) -> HttpResponse<B2> {
|
pub fn set_body<B2>(self, body: AnyBody<B2>) -> HttpResponse<B2> {
|
||||||
HttpResponse {
|
HttpResponse {
|
||||||
res: self.res.set_body(body),
|
res: self.res.set_body(body),
|
||||||
error: None,
|
error: None,
|
||||||
@@ -196,12 +203,12 @@ impl<B> HttpResponse<B> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Split response and body
|
/// Split response and body
|
||||||
pub fn into_parts(self) -> (HttpResponse<()>, B) {
|
pub fn into_parts(self) -> (HttpResponse<()>, AnyBody<B>) {
|
||||||
let (head, body) = self.res.into_parts();
|
let (head, body) = self.res.into_parts();
|
||||||
|
|
||||||
(
|
(
|
||||||
HttpResponse {
|
HttpResponse {
|
||||||
res: head,
|
res: head.map_body(|_, _b| AnyBody::default()),
|
||||||
error: None,
|
error: None,
|
||||||
},
|
},
|
||||||
body,
|
body,
|
||||||
@@ -211,7 +218,7 @@ impl<B> HttpResponse<B> {
|
|||||||
/// Drop request's body
|
/// Drop request's body
|
||||||
pub fn drop_body(self) -> HttpResponse<()> {
|
pub fn drop_body(self) -> HttpResponse<()> {
|
||||||
HttpResponse {
|
HttpResponse {
|
||||||
res: self.res.drop_body(),
|
res: self.res.drop_body().map_body(|_, _b| AnyBody::default()),
|
||||||
error: None,
|
error: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -219,7 +226,7 @@ impl<B> HttpResponse<B> {
|
|||||||
/// Set a body and return previous body value
|
/// Set a body and return previous body value
|
||||||
pub fn map_body<F, B2>(self, f: F) -> HttpResponse<B2>
|
pub fn map_body<F, B2>(self, f: F) -> HttpResponse<B2>
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut ResponseHead, B) -> B2,
|
F: FnOnce(&mut ResponseHead, AnyBody<B>) -> AnyBody<B2>,
|
||||||
{
|
{
|
||||||
HttpResponse {
|
HttpResponse {
|
||||||
res: self.res.map_body(f),
|
res: self.res.map_body(f),
|
||||||
@@ -229,27 +236,28 @@ impl<B> HttpResponse<B> {
|
|||||||
|
|
||||||
// TODO: docs for the body map methods below
|
// TODO: docs for the body map methods below
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn map_into_left_body<R>(self) -> HttpResponse<EitherBody<B, R>> {
|
|
||||||
self.map_body(|_, body| EitherBody::left(body))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn map_into_right_body<L>(self) -> HttpResponse<EitherBody<L, B>> {
|
|
||||||
self.map_body(|_, body| EitherBody::right(body))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn map_into_boxed_body(self) -> HttpResponse<BoxBody>
|
pub fn map_into_boxed_body(self) -> HttpResponse<BoxBody>
|
||||||
where
|
where
|
||||||
B: MessageBody + 'static,
|
B: MessageBody + 'static,
|
||||||
{
|
{
|
||||||
// TODO: avoid double boxing with down-casting, if it improves perf
|
self.map_body(|_, body| AnyBody::Boxed {
|
||||||
self.map_body(|_, body| BoxBody::new(body))
|
body: match body {
|
||||||
|
AnyBody::None => BoxBody::new(NoneBody::new()),
|
||||||
|
AnyBody::Full { body } => BoxBody::new(body),
|
||||||
|
AnyBody::Stream { body } => BoxBody::new(body),
|
||||||
|
AnyBody::Boxed { body } => body,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract response body
|
/// Extract response body
|
||||||
pub fn into_body(self) -> B {
|
pub fn take_body(&mut self) -> AnyBody<B> {
|
||||||
|
self.res.take_body()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extract response body
|
||||||
|
pub fn into_body(self) -> AnyBody<B> {
|
||||||
self.res.into_body()
|
self.res.into_body()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -266,8 +274,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> From<Response<B>> for HttpResponse<B> {
|
impl<B> From<Response<AnyBody<B>>> for HttpResponse<B> {
|
||||||
fn from(res: Response<B>) -> Self {
|
fn from(res: Response<AnyBody<B>>) -> Self {
|
||||||
HttpResponse { res, error: None }
|
HttpResponse { res, error: None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -278,7 +286,7 @@ impl From<Error> for HttpResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> From<HttpResponse<B>> for Response<B> {
|
impl<B> From<HttpResponse<B>> for Response<AnyBody<B>> {
|
||||||
fn from(res: HttpResponse<B>) -> Self {
|
fn from(res: HttpResponse<B>) -> Self {
|
||||||
// this impl will always be called as part of dispatcher
|
// this impl will always be called as part of dispatcher
|
||||||
|
|
||||||
@@ -291,14 +299,14 @@ impl<B> From<HttpResponse<B>> for Response<B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Future is only implemented for BoxBody payload type because it's the most useful for making
|
// Future is only implemented for default payload type because it's the most useful for making
|
||||||
// simple handlers without async blocks. Making it generic over all MessageBody types requires a
|
// simple handlers without async blocks. Making it generic over all MessageBody types requires a
|
||||||
// future impl on Response which would cause it's body field to be, undesirably, Option<B>.
|
// future impl on Response which would cause it's body field to be, undesirably, Option<B>.
|
||||||
//
|
//
|
||||||
// This impl is not particularly efficient due to the Response construction and should probably
|
// This impl is not particularly efficient due to the Response construction and should probably
|
||||||
// not be invoked if performance is important. Prefer an async fn/block in such cases.
|
// not be invoked if performance is important. Prefer an async fn/block in such cases.
|
||||||
impl Future for HttpResponse<BoxBody> {
|
impl Future for HttpResponse {
|
||||||
type Output = Result<Response<BoxBody>, Error>;
|
type Output = Result<Response<AnyBody>, Error>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
if let Some(err) = self.error.take() {
|
if let Some(err) = self.error.take() {
|
||||||
@@ -307,7 +315,7 @@ impl Future for HttpResponse<BoxBody> {
|
|||||||
|
|
||||||
Poll::Ready(Ok(mem::replace(
|
Poll::Ready(Ok(mem::replace(
|
||||||
&mut self.res,
|
&mut self.res,
|
||||||
Response::new(StatusCode::default()),
|
Response::with_body(StatusCode::default(), AnyBody::None),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,7 @@ use actix_tls::accept::openssl::reexports::{AlpnError, SslAcceptor, SslAcceptorB
|
|||||||
#[cfg(feature = "rustls")]
|
#[cfg(feature = "rustls")]
|
||||||
use actix_tls::accept::rustls::reexports::ServerConfig as RustlsServerConfig;
|
use actix_tls::accept::rustls::reexports::ServerConfig as RustlsServerConfig;
|
||||||
|
|
||||||
use crate::{config::AppConfig, Error};
|
use crate::{any_body::AnyBody, config::AppConfig, Error};
|
||||||
|
|
||||||
struct Socket {
|
struct Socket {
|
||||||
scheme: &'static str,
|
scheme: &'static str,
|
||||||
@@ -55,7 +55,7 @@ where
|
|||||||
S: ServiceFactory<Request, Config = AppConfig>,
|
S: ServiceFactory<Request, Config = AppConfig>,
|
||||||
S::Error: Into<Error>,
|
S::Error: Into<Error>,
|
||||||
S::InitError: fmt::Debug,
|
S::InitError: fmt::Debug,
|
||||||
S::Response: Into<Response<B>>,
|
S::Response: Into<Response<AnyBody<B>>>,
|
||||||
B: MessageBody,
|
B: MessageBody,
|
||||||
{
|
{
|
||||||
pub(super) factory: F,
|
pub(super) factory: F,
|
||||||
@@ -75,7 +75,7 @@ where
|
|||||||
S: ServiceFactory<Request, Config = AppConfig> + 'static,
|
S: ServiceFactory<Request, Config = AppConfig> + 'static,
|
||||||
S::Error: Into<Error> + 'static,
|
S::Error: Into<Error> + 'static,
|
||||||
S::InitError: fmt::Debug,
|
S::InitError: fmt::Debug,
|
||||||
S::Response: Into<Response<B>> + 'static,
|
S::Response: Into<Response<AnyBody<B>>> + 'static,
|
||||||
<S::Service as Service<Request>>::Future: 'static,
|
<S::Service as Service<Request>>::Future: 'static,
|
||||||
S::Service: 'static,
|
S::Service: 'static,
|
||||||
|
|
||||||
@@ -300,9 +300,10 @@ where
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let fac = factory()
|
let fac = factory().into_factory().map_err(|err| {
|
||||||
.into_factory()
|
let res: actix_http::Response<_> = err.into().error_response().into();
|
||||||
.map_err(|err| err.into().error_response());
|
res.map_into_boxed_body()
|
||||||
|
});
|
||||||
|
|
||||||
svc.finish(map_config(fac, move |_| {
|
svc.finish(map_config(fac, move |_| {
|
||||||
AppConfig::new(false, host.clone(), addr)
|
AppConfig::new(false, host.clone(), addr)
|
||||||
@@ -360,9 +361,10 @@ where
|
|||||||
svc
|
svc
|
||||||
};
|
};
|
||||||
|
|
||||||
let fac = factory()
|
let fac = factory().into_factory().map_err(|err| {
|
||||||
.into_factory()
|
let res: actix_http::Response<_> = err.into().error_response().into();
|
||||||
.map_err(|err| err.into().error_response());
|
res.map_into_boxed_body()
|
||||||
|
});
|
||||||
|
|
||||||
svc.finish(map_config(fac, move |_| {
|
svc.finish(map_config(fac, move |_| {
|
||||||
AppConfig::new(true, host.clone(), addr)
|
AppConfig::new(true, host.clone(), addr)
|
||||||
@@ -544,9 +546,10 @@ where
|
|||||||
.on_connect_ext(move |io: &_, ext: _| (&*handler)(io as &dyn Any, ext));
|
.on_connect_ext(move |io: &_, ext: _| (&*handler)(io as &dyn Any, ext));
|
||||||
}
|
}
|
||||||
|
|
||||||
let fac = factory()
|
let fac = factory().into_factory().map_err(|err| {
|
||||||
.into_factory()
|
let res: actix_http::Response<_> = err.into().error_response().into();
|
||||||
.map_err(|err| err.into().error_response());
|
res.map_into_boxed_body()
|
||||||
|
});
|
||||||
|
|
||||||
svc.finish(map_config(fac, move |_| config.clone()))
|
svc.finish(map_config(fac, move |_| config.clone()))
|
||||||
})
|
})
|
||||||
@@ -585,9 +588,10 @@ where
|
|||||||
socket_addr,
|
socket_addr,
|
||||||
);
|
);
|
||||||
|
|
||||||
let fac = factory()
|
let fac = factory().into_factory().map_err(|err| {
|
||||||
.into_factory()
|
let res: actix_http::Response<_> = err.into().error_response().into();
|
||||||
.map_err(|err| err.into().error_response());
|
res.map_into_boxed_body()
|
||||||
|
});
|
||||||
|
|
||||||
fn_service(|io: UnixStream| async { Ok((io, Protocol::Http1, None)) }).and_then(
|
fn_service(|io: UnixStream| async { Ok((io, Protocol::Http1, None)) }).and_then(
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
@@ -610,7 +614,7 @@ where
|
|||||||
S: ServiceFactory<Request, Config = AppConfig>,
|
S: ServiceFactory<Request, Config = AppConfig>,
|
||||||
S::Error: Into<Error>,
|
S::Error: Into<Error>,
|
||||||
S::InitError: fmt::Debug,
|
S::InitError: fmt::Debug,
|
||||||
S::Response: Into<Response<B>>,
|
S::Response: Into<Response<AnyBody<B>>>,
|
||||||
S::Service: 'static,
|
S::Service: 'static,
|
||||||
B: MessageBody,
|
B: MessageBody,
|
||||||
{
|
{
|
||||||
|
@@ -5,7 +5,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body::{BoxBody, EitherBody, MessageBody},
|
body::{self, BoxBody, MessageBody},
|
||||||
header::HeaderMap,
|
header::HeaderMap,
|
||||||
Extensions, HttpMessage, Method, Payload, PayloadStream, RequestHead, Response,
|
Extensions, HttpMessage, Method, Payload, PayloadStream, RequestHead, Response,
|
||||||
ResponseHead, StatusCode, Uri, Version,
|
ResponseHead, StatusCode, Uri, Version,
|
||||||
@@ -19,6 +19,7 @@ use actix_service::{
|
|||||||
use cookie::{Cookie, ParseError as CookieParseError};
|
use cookie::{Cookie, ParseError as CookieParseError};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
any_body::AnyBody,
|
||||||
config::{AppConfig, AppService},
|
config::{AppConfig, AppService},
|
||||||
dev::ensure_leading_slash,
|
dev::ensure_leading_slash,
|
||||||
guard::Guard,
|
guard::Guard,
|
||||||
@@ -112,7 +113,7 @@ impl ServiceRequest {
|
|||||||
|
|
||||||
/// Create service response
|
/// Create service response
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn into_response<B, R: Into<Response<B>>>(self, res: R) -> ServiceResponse<B> {
|
pub fn into_response<B, R: Into<Response<AnyBody<B>>>>(self, res: R) -> ServiceResponse<B> {
|
||||||
let res = HttpResponse::from(res.into());
|
let res = HttpResponse::from(res.into());
|
||||||
ServiceResponse::new(self.req, res)
|
ServiceResponse::new(self.req, res)
|
||||||
}
|
}
|
||||||
@@ -410,15 +411,14 @@ impl<B> ServiceResponse<B> {
|
|||||||
self.response.headers_mut()
|
self.response.headers_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Destructures `ServiceResponse` into request and response components.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn into_parts(self) -> (HttpRequest, HttpResponse<B>) {
|
pub fn take_body(&mut self) -> AnyBody<B> {
|
||||||
(self.request, self.response)
|
self.response.take_body()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract response body
|
/// Extract response body
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn into_body(self) -> B {
|
pub fn into_body(self) -> AnyBody<B> {
|
||||||
self.response.into_body()
|
self.response.into_body()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,7 +426,7 @@ impl<B> ServiceResponse<B> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn map_body<F, B2>(self, f: F) -> ServiceResponse<B2>
|
pub fn map_body<F, B2>(self, f: F) -> ServiceResponse<B2>
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut ResponseHead, B) -> B2,
|
F: FnOnce(&mut ResponseHead, AnyBody<B>) -> AnyBody<B2>,
|
||||||
{
|
{
|
||||||
let response = self.response.map_body(f);
|
let response = self.response.map_body(f);
|
||||||
|
|
||||||
@@ -436,22 +436,29 @@ impl<B> ServiceResponse<B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
// #[inline]
|
||||||
pub fn map_into_left_body<R>(self) -> ServiceResponse<EitherBody<B, R>> {
|
// pub fn map_into_left_body<R>(self) -> ServiceResponse<EitherBody<B, R>> {
|
||||||
self.map_body(|_, body| EitherBody::left(body))
|
// self.map_body(|_, body| EitherBody::left(body))
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[inline]
|
// #[inline]
|
||||||
pub fn map_into_right_body<L>(self) -> ServiceResponse<EitherBody<L, B>> {
|
// pub fn map_into_right_body<L>(self) -> ServiceResponse<EitherBody<L, B>> {
|
||||||
self.map_body(|_, body| EitherBody::right(body))
|
// self.map_body(|_, body| EitherBody::right(body))
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn map_into_boxed_body(self) -> ServiceResponse<BoxBody>
|
pub fn map_into_boxed_body(self) -> ServiceResponse<BoxBody>
|
||||||
where
|
where
|
||||||
B: MessageBody + 'static,
|
B: MessageBody + 'static,
|
||||||
{
|
{
|
||||||
self.map_body(|_, body| BoxBody::new(body))
|
self.map_body(|_, body| AnyBody::Stream {
|
||||||
|
body: match body {
|
||||||
|
AnyBody::None => BoxBody::new(body::None::new()),
|
||||||
|
AnyBody::Full { body } => BoxBody::new(body),
|
||||||
|
AnyBody::Stream { body } => BoxBody::new(body),
|
||||||
|
AnyBody::Boxed { body } => body,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,8 +468,8 @@ impl<B> From<ServiceResponse<B>> for HttpResponse<B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> From<ServiceResponse<B>> for Response<B> {
|
impl<B> From<ServiceResponse<B>> for Response<AnyBody<B>> {
|
||||||
fn from(res: ServiceResponse<B>) -> Response<B> {
|
fn from(res: ServiceResponse<B>) -> Response<AnyBody<B>> {
|
||||||
res.response.into()
|
res.response.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -163,7 +163,7 @@ where
|
|||||||
|
|
||||||
actix_rt::pin!(body);
|
actix_rt::pin!(body);
|
||||||
while let Some(item) = poll_fn(|cx| body.as_mut().poll_next(cx)).await {
|
while let Some(item) = poll_fn(|cx| body.as_mut().poll_next(cx)).await {
|
||||||
bytes.extend_from_slice(&item.map_err(Into::into).unwrap());
|
bytes.extend_from_slice(&item.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes.freeze()
|
bytes.freeze()
|
||||||
@@ -205,7 +205,7 @@ where
|
|||||||
|
|
||||||
actix_rt::pin!(body);
|
actix_rt::pin!(body);
|
||||||
while let Some(item) = poll_fn(|cx| body.as_mut().poll_next(cx)).await {
|
while let Some(item) = poll_fn(|cx| body.as_mut().poll_next(cx)).await {
|
||||||
bytes.extend_from_slice(&item.map_err(Into::into).unwrap());
|
bytes.extend_from_slice(&item.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes.freeze()
|
bytes.freeze()
|
||||||
|
@@ -12,9 +12,9 @@ use futures_core::ready;
|
|||||||
use pin_project_lite::pin_project;
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body, dev,
|
dev,
|
||||||
web::{Form, Json},
|
web::{Form, Json},
|
||||||
Error, FromRequest, HttpRequest, HttpResponse, Responder,
|
Error, FromRequest, HttpRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Combines two extractor or responder types into a single type.
|
/// Combines two extractor or responder types into a single type.
|
||||||
@@ -140,21 +140,23 @@ impl<L, R> Either<L, R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [here](#responder) for example of usage as a handler return type.
|
// /// See [here](#responder) for example of usage as a handler return type.
|
||||||
impl<L, R> Responder for Either<L, R>
|
// impl<L, R> Responder for Either<L, R>
|
||||||
where
|
// where
|
||||||
L: Responder,
|
// L: Responder,
|
||||||
R: Responder,
|
// R: Responder,
|
||||||
{
|
// {
|
||||||
type Body = body::EitherBody<L::Body, R::Body>;
|
// type Body = EitherAnyBody<L::Body, R::Body>;
|
||||||
|
|
||||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
|
// fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
match self {
|
// match self {
|
||||||
Either::Left(a) => a.respond_to(req).map_into_left_body(),
|
// Either::Left(a) => a.respond_to(req).map_body(|_, body| EitherAnyBodyProj::left(body)),
|
||||||
Either::Right(b) => b.respond_to(req).map_into_right_body(),
|
// Either::Right(b) => b
|
||||||
}
|
// .respond_to(req)
|
||||||
}
|
// .map_body(|_, body| EitherAnyBodyProj::right(body)),
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
/// A composite error resulting from failure to extract an `Either<L, R>`.
|
/// A composite error resulting from failure to extract an `Either<L, R>`.
|
||||||
///
|
///
|
||||||
|
@@ -20,9 +20,8 @@ use serde::{de::DeserializeOwned, Serialize};
|
|||||||
#[cfg(feature = "__compress")]
|
#[cfg(feature = "__compress")]
|
||||||
use crate::dev::Decompress;
|
use crate::dev::Decompress;
|
||||||
use crate::{
|
use crate::{
|
||||||
body::EitherBody, error::UrlencodedError, extract::FromRequest,
|
error::UrlencodedError, extract::FromRequest, http::header::CONTENT_LENGTH, web, Error,
|
||||||
http::header::CONTENT_LENGTH, web, Error, HttpMessage, HttpRequest, HttpResponse,
|
HttpMessage, HttpRequest, HttpResponse, Responder,
|
||||||
Responder,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// URL encoded payload extractor and responder.
|
/// URL encoded payload extractor and responder.
|
||||||
@@ -181,7 +180,7 @@ impl<T: fmt::Display> fmt::Display for Form<T> {
|
|||||||
|
|
||||||
/// See [here](#responder) for example of usage as a handler return type.
|
/// See [here](#responder) for example of usage as a handler return type.
|
||||||
impl<T: Serialize> Responder for Form<T> {
|
impl<T: Serialize> Responder for Form<T> {
|
||||||
type Body = EitherBody<String>;
|
type Body = String;
|
||||||
|
|
||||||
fn respond_to(self, _: &HttpRequest) -> HttpResponse<Self::Body> {
|
fn respond_to(self, _: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
match serde_urlencoded::to_string(&self.0) {
|
match serde_urlencoded::to_string(&self.0) {
|
||||||
@@ -189,12 +188,12 @@ impl<T: Serialize> Responder for Form<T> {
|
|||||||
.content_type(mime::APPLICATION_WWW_FORM_URLENCODED)
|
.content_type(mime::APPLICATION_WWW_FORM_URLENCODED)
|
||||||
.message_body(body)
|
.message_body(body)
|
||||||
{
|
{
|
||||||
Ok(res) => res.map_into_left_body(),
|
Ok(res) => res,
|
||||||
Err(err) => HttpResponse::from_error(err).map_into_right_body(),
|
Err(err) => HttpResponse::from_error(err).map_into_body(),
|
||||||
},
|
},
|
||||||
|
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
HttpResponse::from_error(UrlencodedError::Serialize(err)).map_into_right_body()
|
HttpResponse::from_error(UrlencodedError::Serialize(err)).map_into_body()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,7 +19,6 @@ use actix_http::Payload;
|
|||||||
#[cfg(feature = "__compress")]
|
#[cfg(feature = "__compress")]
|
||||||
use crate::dev::Decompress;
|
use crate::dev::Decompress;
|
||||||
use crate::{
|
use crate::{
|
||||||
body::EitherBody,
|
|
||||||
error::{Error, JsonPayloadError},
|
error::{Error, JsonPayloadError},
|
||||||
extract::FromRequest,
|
extract::FromRequest,
|
||||||
http::header::CONTENT_LENGTH,
|
http::header::CONTENT_LENGTH,
|
||||||
@@ -117,7 +116,7 @@ impl<T: Serialize> Serialize for Json<T> {
|
|||||||
///
|
///
|
||||||
/// If serialization failed
|
/// If serialization failed
|
||||||
impl<T: Serialize> Responder for Json<T> {
|
impl<T: Serialize> Responder for Json<T> {
|
||||||
type Body = EitherBody<String>;
|
type Body = String;
|
||||||
|
|
||||||
fn respond_to(self, _: &HttpRequest) -> HttpResponse<Self::Body> {
|
fn respond_to(self, _: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
match serde_json::to_string(&self.0) {
|
match serde_json::to_string(&self.0) {
|
||||||
@@ -125,12 +124,12 @@ impl<T: Serialize> Responder for Json<T> {
|
|||||||
.content_type(mime::APPLICATION_JSON)
|
.content_type(mime::APPLICATION_JSON)
|
||||||
.message_body(body)
|
.message_body(body)
|
||||||
{
|
{
|
||||||
Ok(res) => res.map_into_left_body(),
|
Ok(res) => res,
|
||||||
Err(err) => HttpResponse::from_error(err).map_into_right_body(),
|
Err(err) => HttpResponse::from_error(err).map_into_body(),
|
||||||
},
|
},
|
||||||
|
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
HttpResponse::from_error(JsonPayloadError::Serialize(err)).map_into_right_body()
|
HttpResponse::from_error(JsonPayloadError::Serialize(err)).map_into_body()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user