Merge pull request #101 from actix/master

actix#1740 actix#1723 actix#1741 actix#1744 actix#1743
This commit is contained in:
云上于天 2020-10-21 21:23:42 +08:00 committed by GitHub
commit 6bff019aa7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 79 additions and 17 deletions

View File

@ -1,7 +1,11 @@
# Changes # Changes
## Unreleased - 2020-xx-xx ## Unreleased - 2020-xx-xx
* Implement Logger middleware regex exclude pattern [#1723]
* Print unconfigured `Data<T>` type when attempting extraction. [#1743]
[#1723]: https://github.com/actix/actix-web/pull/1723
[#1743]: https://github.com/actix/actix-web/pull/1743
## 3.1.0 - 2020-09-29 ## 3.1.0 - 2020-09-29
### Changed ### Changed

View File

@ -91,7 +91,7 @@ log = "0.4"
mime = "0.3" mime = "0.3"
socket2 = "0.3" socket2 = "0.3"
pin-project = "0.4.17" pin-project = "0.4.17"
regex = "1.3" regex = "1.4"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
serde_urlencoded = "0.6.1" serde_urlencoded = "0.6.1"

View File

@ -1,7 +1,7 @@
# Changes # Changes
## Unreleased - 2020-xx-xx ## Unreleased - 2020-xx-xx
* Upgrade `base64` to `0.13`.
## 2.0.0 - 2020-09-11 ## 2.0.0 - 2020-09-11
* No significant changes from `2.0.0-beta.4`. * No significant changes from `2.0.0-beta.4`.

View File

@ -49,7 +49,7 @@ actix-threadpool = "0.3.1"
actix-tls = { version = "2.0.0", optional = true } actix-tls = { version = "2.0.0", optional = true }
actix = { version = "0.10.0", optional = true } actix = { version = "0.10.0", optional = true }
base64 = "0.12" base64 = "0.13"
bitflags = "1.2" bitflags = "1.2"
bytes = "0.5.3" bytes = "0.5.3"
cookie = { version = "0.14.1", features = ["percent-encode"] } cookie = { version = "0.14.1", features = ["percent-encode"] }

View File

@ -4,7 +4,9 @@ use std::ptr::copy_nonoverlapping;
use std::slice; use std::slice;
// Holds a slice guaranteed to be shorter than 8 bytes // Holds a slice guaranteed to be shorter than 8 bytes
struct ShortSlice<'a>(&'a mut [u8]); struct ShortSlice<'a> {
inner: &'a mut [u8],
}
impl<'a> ShortSlice<'a> { impl<'a> ShortSlice<'a> {
/// # Safety /// # Safety
@ -12,10 +14,11 @@ impl<'a> ShortSlice<'a> {
unsafe fn new(slice: &'a mut [u8]) -> Self { unsafe fn new(slice: &'a mut [u8]) -> Self {
// Sanity check for debug builds // Sanity check for debug builds
debug_assert!(slice.len() < 8); debug_assert!(slice.len() < 8);
ShortSlice(slice) ShortSlice { inner: slice }
} }
fn len(&self) -> usize { fn len(&self) -> usize {
self.0.len() self.inner.len()
} }
} }
@ -56,7 +59,7 @@ pub(crate) fn apply_mask(buf: &mut [u8], mask_u32: u32) {
fn xor_short(buf: ShortSlice<'_>, mask: u64) { fn xor_short(buf: ShortSlice<'_>, mask: u64) {
// SAFETY: we know that a `ShortSlice` fits in a u64 // SAFETY: we know that a `ShortSlice` fits in a u64
unsafe { unsafe {
let (ptr, len) = (buf.0.as_mut_ptr(), buf.0.len()); let (ptr, len) = (buf.inner.as_mut_ptr(), buf.len());
let mut b: u64 = 0; let mut b: u64 = 0;
#[allow(trivial_casts)] #[allow(trivial_casts)]
copy_nonoverlapping(ptr, &mut b as *mut _ as *mut u8, len); copy_nonoverlapping(ptr, &mut b as *mut _ as *mut u8, len);
@ -96,7 +99,13 @@ fn align_buf(buf: &mut [u8]) -> (ShortSlice<'_>, &mut [u64], ShortSlice<'_>) {
// SAFETY: we know the middle section is correctly aligned, and the outer // SAFETY: we know the middle section is correctly aligned, and the outer
// sections are smaller than 8 bytes // sections are smaller than 8 bytes
unsafe { (ShortSlice::new(head), cast_slice(mid), ShortSlice(tail)) } unsafe {
(
ShortSlice::new(head),
cast_slice(mid),
ShortSlice::new(tail),
)
}
} else { } else {
// We didn't cross even one aligned boundary! // We didn't cross even one aligned boundary!

View File

@ -6,9 +6,8 @@ fn compile_macros() {
t.compile_fail("tests/trybuild/simple-fail.rs"); t.compile_fail("tests/trybuild/simple-fail.rs");
t.pass("tests/trybuild/route-ok.rs"); t.pass("tests/trybuild/route-ok.rs");
t.compile_fail("tests/trybuild/route-duplicate-method-fail.rs");
t.compile_fail("tests/trybuild/route-unexpected-method-fail.rs");
test_route_duplicate_unexpected_method(&t);
test_route_missing_method(&t) test_route_missing_method(&t)
} }
@ -25,3 +24,13 @@ fn test_route_missing_method(t: &trybuild::TestCases) {
#[rustversion::nightly] #[rustversion::nightly]
fn test_route_missing_method(_t: &trybuild::TestCases) {} fn test_route_missing_method(_t: &trybuild::TestCases) {}
// FIXME: Re-test them on nightly once rust-lang/rust#77993 is fixed.
#[rustversion::not(nightly)]
fn test_route_duplicate_unexpected_method(t: &trybuild::TestCases) {
t.compile_fail("tests/trybuild/route-duplicate-method-fail.rs");
t.compile_fail("tests/trybuild/route-unexpected-method-fail.rs");
}
#[rustversion::nightly]
fn test_route_duplicate_unexpected_method(_t: &trybuild::TestCases) {}

View File

@ -1,7 +1,7 @@
# Changes # Changes
## Unreleased - 2020-xx-xx ## Unreleased - 2020-xx-xx
* Upgrade `base64` to `0.13`.
## 2.0.0 - 2020-09-11 ## 2.0.0 - 2020-09-11
### Changed ### Changed

View File

@ -42,7 +42,7 @@ actix-service = "1.0.6"
actix-http = "2.0.0" actix-http = "2.0.0"
actix-rt = "1.0.0" actix-rt = "1.0.0"
base64 = "0.12" base64 = "0.13"
bytes = "0.5.3" bytes = "0.5.3"
derive_more = "0.99.2" derive_more = "0.99.2"
futures-core = { version = "0.3.5", default-features = false } futures-core = { version = "0.3.5", default-features = false }

View File

@ -1,3 +1,4 @@
use std::any::type_name;
use std::ops::Deref; use std::ops::Deref;
use std::sync::Arc; use std::sync::Arc;
@ -121,8 +122,9 @@ impl<T: ?Sized + 'static> FromRequest for Data<T> {
} else { } else {
log::debug!( log::debug!(
"Failed to construct App-level Data extractor. \ "Failed to construct App-level Data extractor. \
Request path: {:?}", Request path: {:?} (type: {})",
req.path() req.path(),
type_name::<T>(),
); );
err(ErrorInternalServerError( err(ErrorInternalServerError(
"App data is not configured, to configure use App::data()", "App data is not configured, to configure use App::data()",

View File

@ -13,7 +13,7 @@ use actix_service::{Service, Transform};
use bytes::Bytes; use bytes::Bytes;
use futures_util::future::{ok, Ready}; use futures_util::future::{ok, Ready};
use log::debug; use log::debug;
use regex::Regex; use regex::{Regex, RegexSet};
use time::OffsetDateTime; use time::OffsetDateTime;
use crate::dev::{BodySize, MessageBody, ResponseBody}; use crate::dev::{BodySize, MessageBody, ResponseBody};
@ -92,6 +92,7 @@ pub struct Logger(Rc<Inner>);
struct Inner { struct Inner {
format: Format, format: Format,
exclude: HashSet<String>, exclude: HashSet<String>,
exclude_regex: RegexSet,
} }
impl Logger { impl Logger {
@ -100,6 +101,7 @@ impl Logger {
Logger(Rc::new(Inner { Logger(Rc::new(Inner {
format: Format::new(format), format: Format::new(format),
exclude: HashSet::new(), exclude: HashSet::new(),
exclude_regex: RegexSet::empty(),
})) }))
} }
@ -111,6 +113,16 @@ impl Logger {
.insert(path.into()); .insert(path.into());
self self
} }
/// Ignore and do not log access info for paths that match regex
pub fn exclude_regex<T: Into<String>>(mut self, path: T) -> Self {
let inner = Rc::get_mut(&mut self.0).unwrap();
let mut patterns = inner.exclude_regex.patterns().to_vec();
patterns.push(path.into());
let regex_set = RegexSet::new(patterns).unwrap();
inner.exclude_regex = regex_set;
self
}
} }
impl Default for Logger { impl Default for Logger {
@ -123,6 +135,7 @@ impl Default for Logger {
Logger(Rc::new(Inner { Logger(Rc::new(Inner {
format: Format::default(), format: Format::default(),
exclude: HashSet::new(), exclude: HashSet::new(),
exclude_regex: RegexSet::empty(),
})) }))
} }
} }
@ -168,7 +181,9 @@ where
} }
fn call(&mut self, req: ServiceRequest) -> Self::Future { fn call(&mut self, req: ServiceRequest) -> Self::Future {
if self.inner.exclude.contains(req.path()) { if self.inner.exclude.contains(req.path())
|| self.inner.exclude_regex.is_match(req.path())
{
LoggerResponse { LoggerResponse {
fut: self.service.call(req), fut: self.service.call(req),
format: None, format: None,
@ -538,6 +553,28 @@ mod tests {
let _res = srv.call(req).await; let _res = srv.call(req).await;
} }
#[actix_rt::test]
async fn test_logger_exclude_regex() {
let srv = |req: ServiceRequest| {
ok(req.into_response(
HttpResponse::build(StatusCode::OK)
.header("X-Test", "ttt")
.finish(),
))
};
let logger = Logger::new("%% %{User-Agent}i %{X-Test}o %{HOME}e %D test")
.exclude_regex("\\w");
let mut srv = logger.new_transform(srv.into_service()).await.unwrap();
let req = TestRequest::with_header(
header::USER_AGENT,
header::HeaderValue::from_static("ACTIX-WEB"),
)
.to_srv_request();
let _res = srv.call(req).await.unwrap();
}
#[actix_rt::test] #[actix_rt::test]
async fn test_url_path() { async fn test_url_path() {
let mut format = Format::new("%T %U"); let mut format = Format::new("%T %U");

View File

@ -3,6 +3,7 @@
## Unreleased - 2020-xx-xx ## Unreleased - 2020-xx-xx
* add ability to set address for `TestServer` [#1645] * add ability to set address for `TestServer` [#1645]
* Upgrade `base64` to `0.13`.
[#1645]: https://github.com/actix/actix-web/pull/1645 [#1645]: https://github.com/actix/actix-web/pull/1645

View File

@ -38,7 +38,7 @@ actix-server = "1.0.0"
actix-testing = "1.0.0" actix-testing = "1.0.0"
awc = "2.0.0" awc = "2.0.0"
base64 = "0.12" base64 = "0.13"
bytes = "0.5.3" bytes = "0.5.3"
futures-core = { version = "0.3.5", default-features = false } futures-core = { version = "0.3.5", default-features = false }
http = "0.2.0" http = "0.2.0"