Merge branch 'master' into feature/log-source-ip

This commit is contained in:
pando85 2020-05-09 06:18:39 +00:00 committed by GitHub
commit 489f91cb1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 167 additions and 147 deletions

View File

@ -4,15 +4,26 @@
### Changed ### Changed
* `{Resource,Scope}::default_service(f)` handlers now support app data extraction. [#1452] * Resources and Scopes can now access non-overridden data types set on App (or containing scopes) when setting their own data. [#1486]
* Implement `std::error::Error` for our custom errors [#1422]
* NormalizePath middleware now appends trailing / so that routes of form /example/ respond to /example requests.
* Fix audit issue logging by default peer address [#1485] * Fix audit issue logging by default peer address [#1485]
[#1422]: https://github.com/actix/actix-web/pull/1422
[#1452]: https://github.com/actix/actix-web/pull/1452
[#1485]: https://github.com/actix/actix-web/pull/1485 [#1485]: https://github.com/actix/actix-web/pull/1485
## [3.0.0-alpha.2] - 2020-05-08
### Changed
* `{Resource,Scope}::default_service(f)` handlers now support app data extraction. [#1452]
* Implement `std::error::Error` for our custom errors [#1422]
* NormalizePath middleware now appends trailing / so that routes of form /example/ respond to /example requests. [#1433]
* Remove the `failure` feature and support.
[#1422]: https://github.com/actix/actix-web/pull/1422
[#1433]: https://github.com/actix/actix-web/pull/1433
[#1452]: https://github.com/actix/actix-web/pull/1452
[#1486]: https://github.com/actix/actix-web/pull/1486
## [3.0.0-alpha.1] - 2020-03-11 ## [3.0.0-alpha.1] - 2020-03-11
### Added ### Added

View File

@ -1,6 +1,6 @@
[package] [package]
name = "actix-web" name = "actix-web"
version = "3.0.0-alpha.1" version = "3.0.0-alpha.2"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"] authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix web is a simple, pragmatic and extremely fast web framework for Rust." description = "Actix web is a simple, pragmatic and extremely fast web framework for Rust."
readme = "README.md" readme = "README.md"
@ -81,7 +81,7 @@ actix-threadpool = "0.3.1"
actix-tls = "2.0.0-alpha.1" actix-tls = "2.0.0-alpha.1"
actix-web-codegen = "0.2.0" actix-web-codegen = "0.2.0"
actix-http = "2.0.0-alpha.2" actix-http = "2.0.0-alpha.3"
awc = { version = "2.0.0-alpha.1", default-features = false } awc = { version = "2.0.0-alpha.1", default-features = false }
bytes = "0.5.3" bytes = "0.5.3"
@ -101,6 +101,7 @@ time = { version = "0.2.7", default-features = false, features = ["std"] }
url = "2.1" url = "2.1"
open-ssl = { version="0.10", package = "openssl", optional = true } open-ssl = { version="0.10", package = "openssl", optional = true }
rust-tls = { version = "0.17.0", package = "rustls", optional = true } rust-tls = { version = "0.17.0", package = "rustls", optional = true }
tinyvec = { version = "0.3", features = ["alloc"] }
[dev-dependencies] [dev-dependencies]
actix = "0.10.0-alpha.1" actix = "0.10.0-alpha.1"

View File

@ -18,8 +18,8 @@ name = "actix_files"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
actix-web = { version = "3.0.0-alpha.1", default-features = false } actix-web = { version = "3.0.0-alpha.2", default-features = false }
actix-http = "2.0.0-alpha.2" actix-http = "2.0.0-alpha.3"
actix-service = "1.0.1" actix-service = "1.0.1"
bitflags = "1" bitflags = "1"
bytes = "0.5.3" bytes = "0.5.3"
@ -33,4 +33,4 @@ v_htmlescape = "0.4"
[dev-dependencies] [dev-dependencies]
actix-rt = "1.0.0" actix-rt = "1.0.0"
actix-web = { version = "3.0.0-alpha.1", features=["openssl"] } actix-web = { version = "3.0.0-alpha.2", features = ["openssl"] }

View File

@ -23,7 +23,7 @@ actix-codec = "0.2.0"
actix-service = "1.0.1" actix-service = "1.0.1"
actix-router = "0.2.1" actix-router = "0.2.1"
actix-rt = "1.0.0" actix-rt = "1.0.0"
actix-http = "2.0.0-alpha.2" actix-http = "2.0.0-alpha.3"
bytes = "0.5.3" bytes = "0.5.3"
futures = "0.3.1" futures = "0.3.1"

View File

@ -1,16 +1,21 @@
# Changes # Changes
## [Unreleased] ## [2.0.0-alpha.3] - 2020-05-08
### Fixed
* Correct spelling of ConnectError::Unresolved [#1487]
* Fix a mistake in the encoding of websocket continuation messages wherein
Item::FirstText and Item::FirstBinary are each encoded as the other.
### Changed ### Changed
* Implement `std::error::Error` for our custom errors [#1422] * Implement `std::error::Error` for our custom errors [#1422]
* Remove `failure` support for `ResponseError` since that crate * Remove `failure` support for `ResponseError` since that crate
will be deprecated in the near future. will be deprecated in the near future.
* Fix a mistake in the encoding of websocket continuation messages wherein
Item::FirstText and Item::FirstBinary are each encoded as the other.
[#1422]: https://github.com/actix/actix-web/pull/1422 [#1422]: https://github.com/actix/actix-web/pull/1422
[#1487]: https://github.com/actix/actix-web/pull/1487
## [2.0.0-alpha.2] - 2020-03-07 ## [2.0.0-alpha.2] - 2020-03-07

View File

@ -1,6 +1,6 @@
[package] [package]
name = "actix-http" name = "actix-http"
version = "2.0.0-alpha.2" version = "2.0.0-alpha.3"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"] authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix http primitives" description = "Actix http primitives"
readme = "README.md" readme = "README.md"
@ -42,7 +42,7 @@ actors = ["actix"]
[dependencies] [dependencies]
actix-service = "1.0.5" actix-service = "1.0.5"
actix-codec = "0.2.0" actix-codec = "0.2.0"
actix-connect = "2.0.0-alpha.2" actix-connect = "2.0.0-alpha.3"
actix-utils = "1.0.6" actix-utils = "1.0.6"
actix-rt = "1.0.0" actix-rt = "1.0.0"
actix-threadpool = "0.3.1" actix-threadpool = "0.3.1"

View File

@ -48,7 +48,7 @@ pub enum ConnectError {
/// Unresolved host name /// Unresolved host name
#[display(fmt = "Connector received `Connect` method with unresolved host")] #[display(fmt = "Connector received `Connect` method with unresolved host")]
Unresolverd, Unresolved,
/// Connection io error /// Connection io error
#[display(fmt = "{}", _0)] #[display(fmt = "{}", _0)]
@ -63,7 +63,7 @@ impl From<actix_connect::ConnectError> for ConnectError {
actix_connect::ConnectError::Resolver(e) => ConnectError::Resolver(e), actix_connect::ConnectError::Resolver(e) => ConnectError::Resolver(e),
actix_connect::ConnectError::NoRecords => ConnectError::NoRecords, actix_connect::ConnectError::NoRecords => ConnectError::NoRecords,
actix_connect::ConnectError::InvalidInput => panic!(), actix_connect::ConnectError::InvalidInput => panic!(),
actix_connect::ConnectError::Unresolverd => ConnectError::Unresolverd, actix_connect::ConnectError::Unresolved => ConnectError::Unresolved,
actix_connect::ConnectError::Io(e) => ConnectError::Io(e), actix_connect::ConnectError::Io(e) => ConnectError::Io(e),
} }
} }

View File

@ -105,7 +105,7 @@ where
let key = if let Some(authority) = req.uri.authority() { let key = if let Some(authority) = req.uri.authority() {
authority.clone().into() authority.clone().into()
} else { } else {
return Err(ConnectError::Unresolverd); return Err(ConnectError::Unresolved);
}; };
// acquire connection // acquire connection
@ -195,7 +195,7 @@ where
if let Some(i) = self.inner.take() { if let Some(i) = self.inner.take() {
let mut inner = i.as_ref().borrow_mut(); let mut inner = i.as_ref().borrow_mut();
inner.release_waiter(&self.key, self.token); inner.release_waiter(&self.key, self.token);
inner.check_availibility(); inner.check_availability();
} }
} }
} }
@ -232,7 +232,7 @@ where
if let Some(i) = self.inner.take() { if let Some(i) = self.inner.take() {
let mut inner = i.as_ref().borrow_mut(); let mut inner = i.as_ref().borrow_mut();
inner.release(); inner.release();
inner.check_availibility(); inner.check_availability();
} }
} }
} }
@ -359,7 +359,7 @@ where
created, created,
used: Instant::now(), used: Instant::now(),
}); });
self.check_availibility(); self.check_availability();
} }
fn release_close(&mut self, io: ConnectionType<Io>) { fn release_close(&mut self, io: ConnectionType<Io>) {
@ -369,10 +369,10 @@ where
actix_rt::spawn(CloseConnection::new(io, timeout)) actix_rt::spawn(CloseConnection::new(io, timeout))
} }
} }
self.check_availibility(); self.check_availability();
} }
fn check_availibility(&self) { fn check_availability(&self) {
if !self.waiters_queue.is_empty() && self.acquired < self.config.limit { if !self.waiters_queue.is_empty() && self.acquired < self.config.limit {
self.waker.wake(); self.waker.wake();
} }
@ -534,7 +534,7 @@ where
if let Some(inner) = self.project().inner.take() { if let Some(inner) = self.project().inner.take() {
let mut inner = inner.as_ref().borrow_mut(); let mut inner = inner.as_ref().borrow_mut();
inner.release(); inner.release();
inner.check_availibility(); inner.check_availability();
} }
} }
} }

View File

@ -16,7 +16,7 @@ name = "actix_multipart"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
actix-web = { version = "3.0.0-alpha.1", default-features = false } actix-web = { version = "3.0.0-alpha.2", default-features = false }
actix-service = "1.0.1" actix-service = "1.0.1"
actix-utils = "1.0.3" actix-utils = "1.0.3"
bytes = "0.5.3" bytes = "0.5.3"
@ -29,4 +29,4 @@ twoway = "0.2"
[dev-dependencies] [dev-dependencies]
actix-rt = "1.0.0" actix-rt = "1.0.0"
actix-http = "2.0.0-alpha.2" actix-http = "2.0.0-alpha.3"

View File

@ -1,5 +1,11 @@
# Changes # Changes
# [3.0.0-alpha.1] - 2020-05-08
* Update the actix-web dependency to 3.0.0-alpha.1
* Update the actix dependency to 0.10.0-alpha.2
* Update the actix-http dependency to 2.0.0-alpha.3
## [2.0.0] - 2019-12-20 ## [2.0.0] - 2019-12-20
* Release * Release

View File

@ -1,6 +1,6 @@
[package] [package]
name = "actix-web-actors" name = "actix-web-actors"
version = "2.0.0" version = "3.0.0-alpha.1"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"] authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix actors support for actix web framework." description = "Actix actors support for actix web framework."
readme = "README.md" readme = "README.md"
@ -16,9 +16,9 @@ name = "actix_web_actors"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
actix = "0.10.0-alpha.1" actix = "0.10.0-alpha.2"
actix-web = "3.0.0-alpha.1" actix-web = "3.0.0-alpha.2"
actix-http = "2.0.0-alpha.2" actix-http = "2.0.0-alpha.3"
actix-codec = "0.2.0" actix-codec = "0.2.0"
bytes = "0.5.2" bytes = "0.5.2"
futures = "0.3.1" futures = "0.3.1"
@ -26,4 +26,4 @@ pin-project = "0.4.6"
[dev-dependencies] [dev-dependencies]
actix-rt = "1.0.0" actix-rt = "1.0.0"
env_logger = "0.6" env_logger = "0.7"

View File

@ -174,7 +174,7 @@ where
// frames // frames
if let Some(data) = self.fut.ctx().stream.pop_front() { if let Some(data) = self.fut.ctx().stream.pop_front() {
Poll::Ready(data.map(|b| Ok(b))) Poll::Ready(data.map(Ok))
} else if self.fut.alive() { } else if self.fut.alive() {
Poll::Pending Poll::Pending
} else { } else {

View File

@ -18,5 +18,5 @@ proc-macro2 = "^1"
[dev-dependencies] [dev-dependencies]
actix-rt = "1.0.0" actix-rt = "1.0.0"
actix-web = "3.0.0-alpha.1" actix-web = "3.0.0-alpha.2"
futures = "0.3.1" futures = "0.3.1"

View File

@ -36,7 +36,7 @@ compress = ["actix-http/compress"]
[dependencies] [dependencies]
actix-codec = "0.2.0" actix-codec = "0.2.0"
actix-service = "1.0.1" actix-service = "1.0.1"
actix-http = "2.0.0-alpha.2" actix-http = "2.0.0-alpha.3"
actix-rt = "1.0.0" actix-rt = "1.0.0"
base64 = "0.11" base64 = "0.11"
@ -50,17 +50,17 @@ rand = "0.7"
serde = "1.0" serde = "1.0"
serde_json = "1.0" serde_json = "1.0"
serde_urlencoded = "0.6.1" serde_urlencoded = "0.6.1"
open-ssl = { version="0.10", package="openssl", optional = true } open-ssl = { version = "0.10", package = "openssl", optional = true }
rust-tls = { version = "0.17.0", package="rustls", optional = true, features = ["dangerous_configuration"] } rust-tls = { version = "0.17.0", package = "rustls", optional = true, features = ["dangerous_configuration"] }
[dev-dependencies] [dev-dependencies]
actix-connect = { version = "2.0.0-alpha.2", features=["openssl"] } actix-connect = { version = "2.0.0-alpha.2", features = ["openssl"] }
actix-web = { version = "3.0.0-alpha.1", features=["openssl"] } actix-web = { version = "3.0.0-alpha.2", features = ["openssl"] }
actix-http = { version = "2.0.0-alpha.2", features=["openssl"] } actix-http = { version = "2.0.0-alpha.3", features = ["openssl"] }
actix-http-test = { version = "1.0.0", features=["openssl"] } actix-http-test = { version = "1.0.0", features = ["openssl"] }
actix-utils = "1.0.3" actix-utils = "1.0.3"
actix-server = "1.0.0" actix-server = "1.0.0"
actix-tls = { version = "2.0.0-alpha.1", features=["openssl", "rustls"] } actix-tls = { version = "2.0.0-alpha.1", features = ["openssl", "rustls"] }
brotli2 = "0.3.2" brotli2 = "0.3.2"
flate2 = "1.0.13" flate2 = "1.0.13"
futures = "0.3.1" futures = "0.3.1"

View File

@ -245,7 +245,7 @@ where
inner.path.reset(); inner.path.reset();
inner.head = head; inner.head = head;
inner.payload = payload; inner.payload = payload;
inner.app_data = self.data.clone(); inner.app_data.push(self.data.clone());
req req
} else { } else {
HttpRequest::new( HttpRequest::new(

View File

@ -6,6 +6,7 @@ use actix_http::http::{HeaderMap, Method, Uri, Version};
use actix_http::{Error, Extensions, HttpMessage, Message, Payload, RequestHead}; use actix_http::{Error, Extensions, HttpMessage, Message, Payload, RequestHead};
use actix_router::{Path, Url}; use actix_router::{Path, Url};
use futures::future::{ok, Ready}; use futures::future::{ok, Ready};
use tinyvec::TinyVec;
use crate::config::AppConfig; use crate::config::AppConfig;
use crate::error::UrlGenerationError; use crate::error::UrlGenerationError;
@ -21,7 +22,7 @@ pub(crate) struct HttpRequestInner {
pub(crate) head: Message<RequestHead>, pub(crate) head: Message<RequestHead>,
pub(crate) path: Path<Url>, pub(crate) path: Path<Url>,
pub(crate) payload: Payload, pub(crate) payload: Payload,
pub(crate) app_data: Rc<Extensions>, pub(crate) app_data: TinyVec<[Rc<Extensions>; 4]>,
rmap: Rc<ResourceMap>, rmap: Rc<ResourceMap>,
config: AppConfig, config: AppConfig,
pool: &'static HttpRequestPool, pool: &'static HttpRequestPool,
@ -38,13 +39,16 @@ impl HttpRequest {
app_data: Rc<Extensions>, app_data: Rc<Extensions>,
pool: &'static HttpRequestPool, pool: &'static HttpRequestPool,
) -> HttpRequest { ) -> HttpRequest {
let mut data = TinyVec::<[Rc<Extensions>; 4]>::new();
data.push(app_data);
HttpRequest(Rc::new(HttpRequestInner { HttpRequest(Rc::new(HttpRequestInner {
head, head,
path, path,
payload, payload,
rmap, rmap,
config, config,
app_data, app_data: data,
pool, pool,
})) }))
} }
@ -215,11 +219,13 @@ impl HttpRequest {
/// let opt_t = req.app_data::<Data<T>>(); /// let opt_t = req.app_data::<Data<T>>();
/// ``` /// ```
pub fn app_data<T: 'static>(&self) -> Option<&T> { pub fn app_data<T: 'static>(&self) -> Option<&T> {
if let Some(st) = self.0.app_data.get::<T>() { for container in self.0.app_data.iter().rev() {
Some(&st) if let Some(data) = container.get::<T>() {
} else { return Some(data);
None }
} }
None
} }
} }
@ -342,10 +348,13 @@ impl HttpRequestPool {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use actix_service::Service;
use bytes::Bytes;
use super::*; use super::*;
use crate::dev::{ResourceDef, ResourceMap}; use crate::dev::{ResourceDef, ResourceMap};
use crate::http::{header, StatusCode}; use crate::http::{header, StatusCode};
use crate::test::{call_service, init_service, TestRequest}; use crate::test::{call_service, init_service, read_body, TestRequest};
use crate::{web, App, HttpResponse}; use crate::{web, App, HttpResponse};
#[test] #[test]
@ -494,6 +503,68 @@ mod tests {
assert_eq!(resp.status(), StatusCode::BAD_REQUEST); assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
} }
#[actix_rt::test]
async fn test_cascading_data() {
#[allow(dead_code)]
fn echo_usize(req: HttpRequest) -> HttpResponse {
let num = req.app_data::<usize>().unwrap();
HttpResponse::Ok().body(num.to_string())
}
let mut srv = init_service(
App::new()
.app_data(88usize)
.service(web::resource("/").route(web::get().to(echo_usize)))
.service(
web::resource("/one")
.app_data(1u32)
.route(web::get().to(echo_usize)),
),
)
.await;
let req = TestRequest::get().uri("/").to_request();
let resp = srv.call(req).await.unwrap();
let body = read_body(resp).await;
assert_eq!(body, Bytes::from_static(b"88"));
let req = TestRequest::get().uri("/one").to_request();
let resp = srv.call(req).await.unwrap();
let body = read_body(resp).await;
assert_eq!(body, Bytes::from_static(b"88"));
}
#[actix_rt::test]
async fn test_overwrite_data() {
#[allow(dead_code)]
fn echo_usize(req: HttpRequest) -> HttpResponse {
let num = req.app_data::<usize>().unwrap();
HttpResponse::Ok().body(num.to_string())
}
let mut srv = init_service(
App::new()
.app_data(88usize)
.service(web::resource("/").route(web::get().to(echo_usize)))
.service(
web::resource("/one")
.app_data(1usize)
.route(web::get().to(echo_usize)),
),
)
.await;
let req = TestRequest::get().uri("/").to_request();
let resp = srv.call(req).await.unwrap();
let body = read_body(resp).await;
assert_eq!(body, Bytes::from_static(b"88"));
let req = TestRequest::get().uri("/one").to_request();
let resp = srv.call(req).await.unwrap();
let body = read_body(resp).await;
assert_eq!(body, Bytes::from_static(b"1"));
}
#[actix_rt::test] #[actix_rt::test]
async fn test_extensions_dropped() { async fn test_extensions_dropped() {
struct Tracker { struct Tracker {

View File

@ -198,9 +198,7 @@ where
/// Add resource data. /// Add resource data.
/// ///
/// If used, this method will create a new data context used for extracting /// Data of different types from parent contexts will still be accessible.
/// from requests. Data added here is *not* merged with data added on App
/// or containing scopes.
pub fn app_data<U: 'static>(mut self, data: U) -> Self { pub fn app_data<U: 'static>(mut self, data: U) -> Self {
if self.data.is_none() { if self.data.is_none() {
self.data = Some(Extensions::new()); self.data = Some(Extensions::new());
@ -539,14 +537,14 @@ impl Service for ResourceService {
for route in self.routes.iter_mut() { for route in self.routes.iter_mut() {
if route.check(&mut req) { if route.check(&mut req) {
if let Some(ref data) = self.data { if let Some(ref data) = self.data {
req.set_data_container(data.clone()); req.add_data_container(data.clone());
} }
return Either::Right(route.call(req)); return Either::Right(route.call(req));
} }
} }
if let Some(ref mut default) = self.default { if let Some(ref mut default) = self.default {
if let Some(ref data) = self.data { if let Some(ref data) = self.data {
req.set_data_container(data.clone()); req.add_data_container(data.clone());
} }
Either::Right(default.call(req)) Either::Right(default.call(req))
} else { } else {
@ -590,14 +588,13 @@ mod tests {
use actix_rt::time::delay_for; use actix_rt::time::delay_for;
use actix_service::Service; use actix_service::Service;
use bytes::Bytes;
use futures::future::ok; use futures::future::ok;
use crate::http::{header, HeaderValue, Method, StatusCode}; use crate::http::{header, HeaderValue, Method, StatusCode};
use crate::middleware::DefaultHeaders; use crate::middleware::DefaultHeaders;
use crate::service::ServiceRequest; use crate::service::ServiceRequest;
use crate::test::{call_service, init_service, read_body, TestRequest}; use crate::test::{call_service, init_service, TestRequest};
use crate::{guard, web, App, Error, HttpRequest, HttpResponse}; use crate::{guard, web, App, Error, HttpResponse};
#[actix_rt::test] #[actix_rt::test]
async fn test_middleware() { async fn test_middleware() {
@ -623,79 +620,6 @@ mod tests {
); );
} }
#[actix_rt::test]
async fn test_overwritten_data() {
#[allow(dead_code)]
fn echo_usize(req: HttpRequest) -> HttpResponse {
let num = req.app_data::<usize>().unwrap();
HttpResponse::Ok().body(format!("{}", num))
}
#[allow(dead_code)]
fn echo_u32(req: HttpRequest) -> HttpResponse {
let num = req.app_data::<u32>().unwrap();
HttpResponse::Ok().body(format!("{}", num))
}
#[allow(dead_code)]
fn echo_both(req: HttpRequest) -> HttpResponse {
let num = req.app_data::<usize>().unwrap();
let num2 = req.app_data::<u32>().unwrap();
HttpResponse::Ok().body(format!("{}-{}", num, num2))
}
let mut srv = init_service(
App::new()
.app_data(88usize)
.service(web::resource("/").route(web::get().to(echo_usize)))
.service(
web::resource("/one")
.app_data(1usize)
.route(web::get().to(echo_usize)),
)
.service(
web::resource("/two")
.app_data(2usize)
.route(web::get().to(echo_usize)),
)
.service(
web::resource("/three")
.app_data(3u32)
// this doesnt work because app_data "overrides" the
// entire data field potentially passed down
// .route(web::get().to(echo_both)),
.route(web::get().to(echo_u32)),
)
.service(web::resource("/eight").route(web::get().to(echo_usize))),
)
.await;
let req = TestRequest::get().uri("/").to_request();
let resp = srv.call(req).await.unwrap();
let body = read_body(resp).await;
assert_eq!(body, Bytes::from_static(b"88"));
let req = TestRequest::get().uri("/one").to_request();
let resp = srv.call(req).await.unwrap();
let body = read_body(resp).await;
assert_eq!(body, Bytes::from_static(b"1"));
let req = TestRequest::get().uri("/two").to_request();
let resp = srv.call(req).await.unwrap();
let body = read_body(resp).await;
assert_eq!(body, Bytes::from_static(b"2"));
// let req = TestRequest::get().uri("/three").to_request();
// let resp = srv.call(req).await.unwrap();
// let body = read_body(resp).await;
// assert_eq!(body, Bytes::from_static(b"88-3"));
let req = TestRequest::get().uri("/eight").to_request();
let resp = srv.call(req).await.unwrap();
let body = read_body(resp).await;
assert_eq!(body, Bytes::from_static(b"88"));
}
#[actix_rt::test] #[actix_rt::test]
async fn test_middleware_fn() { async fn test_middleware_fn() {
let mut srv = init_service( let mut srv = init_service(

View File

@ -153,9 +153,7 @@ where
/// Add scope data. /// Add scope data.
/// ///
/// If used, this method will create a new data context used for extracting /// Data of different types from parent contexts will still be accessible.
/// from requests. Data added here is *not* merged with data added on App
/// or containing scopes.
pub fn app_data<U: 'static>(mut self, data: U) -> Self { pub fn app_data<U: 'static>(mut self, data: U) -> Self {
if self.data.is_none() { if self.data.is_none() {
self.data = Some(Extensions::new()); self.data = Some(Extensions::new());
@ -624,12 +622,12 @@ impl Service for ScopeService {
if let Some((srv, _info)) = res { if let Some((srv, _info)) = res {
if let Some(ref data) = self.data { if let Some(ref data) = self.data {
req.set_data_container(data.clone()); req.add_data_container(data.clone());
} }
Either::Left(srv.call(req)) Either::Left(srv.call(req))
} else if let Some(ref mut default) = self.default { } else if let Some(ref mut default) = self.default {
if let Some(ref data) = self.data { if let Some(ref data) = self.data {
req.set_data_container(data.clone()); req.add_data_container(data.clone());
} }
Either::Left(default.call(req)) Either::Left(default.call(req))
} else { } else {

View File

@ -217,11 +217,13 @@ impl ServiceRequest {
/// Get an application data stored with `App::data()` method during /// Get an application data stored with `App::data()` method during
/// application configuration. /// application configuration.
pub fn app_data<T: 'static>(&self) -> Option<Data<T>> { pub fn app_data<T: 'static>(&self) -> Option<Data<T>> {
if let Some(st) = (self.0).0.app_data.get::<Data<T>>() { for container in (self.0).0.app_data.iter().rev() {
Some(st.clone()) if let Some(data) = container.get::<Data<T>>() {
} else { return Some(Data::clone(&data));
None }
} }
None
} }
/// Set request payload. /// Set request payload.
@ -230,9 +232,12 @@ impl ServiceRequest {
} }
#[doc(hidden)] #[doc(hidden)]
/// Set new app data container /// Add app data container to request's resolution set.
pub fn set_data_container(&mut self, extensions: Rc<Extensions>) { pub fn add_data_container(&mut self, extensions: Rc<Extensions>) {
Rc::get_mut(&mut (self.0).0).unwrap().app_data = extensions; Rc::get_mut(&mut (self.0).0)
.unwrap()
.app_data
.push(extensions);
} }
} }
@ -578,7 +583,6 @@ mod tests {
let resp = srv.call(req).await.unwrap(); let resp = srv.call(req).await.unwrap();
assert_eq!(resp.status(), http::StatusCode::NOT_FOUND); assert_eq!(resp.status(), http::StatusCode::NOT_FOUND);
} }
#[test] #[test]
fn test_fmt_debug() { fn test_fmt_debug() {
let req = TestRequest::get() let req = TestRequest::get()

View File

@ -52,8 +52,8 @@ sha1 = "0.6"
slab = "0.4" slab = "0.4"
serde_urlencoded = "0.6.1" serde_urlencoded = "0.6.1"
time = { version = "0.2.7", default-features = false, features = ["std"] } time = { version = "0.2.7", default-features = false, features = ["std"] }
open-ssl = { version="0.10", package = "openssl", optional = true } open-ssl = { version = "0.10", package = "openssl", optional = true }
[dev-dependencies] [dev-dependencies]
actix-web = "3.0.0-alpha.1" actix-web = "3.0.0-alpha.2"
actix-http = "2.0.0-alpha.2" actix-http = "2.0.0-alpha.3"