1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-07-04 01:51:30 +02:00

Compare commits

...

14 Commits

Author SHA1 Message Date
bc54cdd772 prepare actix-http release 2.2.2 2022-01-21 21:23:22 +00:00
ad7e3c06e7 migrate to brotli crate 2022-01-21 21:16:23 +00:00
0669ed0f06 soft-deprecate NormalizePath::default in v3 (#2529) 2021-12-18 22:57:23 +00:00
c9c36679e4 bump actix http version 2021-08-11 19:21:40 +01:00
655d7b4f05 sec fixes 2021-08-08 21:21:48 +01:00
24d525d978 prepare web 3.3.2 release 2020-12-01 22:22:46 +00:00
1f70ef155d Fix match_pattern() returning None for scope with resource of empty path (#1798)
* fix match_pattern function not returning pattern where scope has resource of path ""

* remove print in test

* make comparison on existing else if block

* add fix to changelog
2020-12-01 13:39:41 +00:00
7981e0068a Remove a panic in normalize middleware (#1762)
Co-authored-by: Yuki Okushi <huyuumi.dev@gmail.com>
2020-12-01 10:22:15 +09:00
32d59ca904 Upgrade socket2 dependency (#1803)
Upgrades to a version not making invalid assumptions about
the memory layout of std::net::SocketAddr
2020-12-01 04:18:02 +09:00
ea8bf36104 update web and awc changelogs 2020-11-29 16:35:35 +00:00
0b5b463cfa prepare web and awc releases
closes #1799
2020-11-29 16:33:45 +00:00
fe6ad816cc update dotgraphs 2020-11-25 00:54:00 +00:00
e72b787ba7 prepare actix-web and actix-http-test releases 2020-11-25 00:53:48 +00:00
efc317d3b0 prepare actix-http and awc releases 2020-11-25 00:07:56 +00:00
26 changed files with 289 additions and 146 deletions

View File

@ -1,12 +1,38 @@
# Changes
## Unreleased - 2020-xx-xx
## 3.3.3 - 2021-12-18
### Changed
* Soft-deprecate `NormalizePath::default()`, noting upcoming behavior change in v4. [#2529]
[#2529]: https://github.com/actix/actix-web/pull/2529
## 3.3.2 - 2020-12-01
### Fixed
* Removed an occasional `unwrap` on `None` panic in `NormalizePathNormalization`. [#1762]
* Fix `match_pattern()` returning `None` for scope with empty path resource. [#1798]
* Increase minimum `socket2` version. [#1803]
[#1762]: https://github.com/actix/actix-web/pull/1762
[#1798]: https://github.com/actix/actix-web/pull/1798
[#1803]: https://github.com/actix/actix-web/pull/1803
## 3.3.1 - 2020-11-29
* Ensure `actix-http` dependency uses same `serde_urlencoded`.
## 3.3.0 - 2020-11-25
### Added
* Add `Either<A, B>` extractor helper. [#1788]
### Changed
* Upgrade `serde_urlencoded` to `0.7`.
* Upgrade `serde_urlencoded` to `0.7`. [#1773]
[#1773]: https://github.com/actix/actix-web/pull/1773
[#1788]: https://github.com/actix/actix-web/pull/1788

View File

@ -1,8 +1,8 @@
[package]
name = "actix-web"
version = "3.2.0"
version = "3.3.3"
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"
readme = "README.md"
keywords = ["actix", "http", "web", "framework", "async"]
homepage = "https://actix.rs"
@ -85,11 +85,11 @@ actix-threadpool = "0.3.1"
actix-tls = "2.0.0"
actix-web-codegen = "0.4.0"
actix-http = "2.1.0"
awc = { version = "2.0.0", default-features = false }
actix-http = "2.2.0"
awc = { version = "2.0.3", default-features = false }
bytes = "0.5.3"
derive_more = "0.99.2"
derive_more = "0.99.5"
encoding_rs = "0.8"
futures-channel = { version = "0.3.5", default-features = false }
futures-core = { version = "0.3.5", default-features = false }
@ -97,7 +97,7 @@ futures-util = { version = "0.3.5", default-features = false }
fxhash = "0.2.1"
log = "0.4"
mime = "0.3"
socket2 = "0.3"
socket2 = "0.3.16"
pin-project = "1.0.0"
regex = "1.4"
serde = { version = "1.0", features = ["derive"] }
@ -115,7 +115,7 @@ actix-http = { version = "2.1.0", features = ["actors"] }
rand = "0.7"
env_logger = "0.8"
serde_derive = "1.0"
brotli2 = "0.3.2"
brotli = "3.3.3"
flate2 = "1.0.13"
criterion = "0.3"

View File

@ -1,15 +1,15 @@
<div align="center">
<h1>Actix web</h1>
<p>
<strong>Actix web is a powerful, pragmatic, and extremely fast web framework for Rust</strong>
<strong>Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust</strong>
</p>
<p>
[![crates.io](https://img.shields.io/crates/v/actix-web?label=latest)](https://crates.io/crates/actix-web)
[![Documentation](https://docs.rs/actix-web/badge.svg?version=3.2.0)](https://docs.rs/actix-web/3.2.0)
[![Documentation](https://docs.rs/actix-web/badge.svg?version=3.3.3)](https://docs.rs/actix-web/3.3.3)
[![Version](https://img.shields.io/badge/rustc-1.42+-ab6000.svg)](https://blog.rust-lang.org/2020/03/12/Rust-1.42.html)
![License](https://img.shields.io/crates/l/actix-web.svg)
[![Dependency Status](https://deps.rs/crate/actix-web/3.2.0/status.svg)](https://deps.rs/crate/actix-web/3.2.0)
[![Dependency Status](https://deps.rs/crate/actix-web/3.3.3/status.svg)](https://deps.rs/crate/actix-web/3.3.3)
<br />
[![Build Status](https://travis-ci.org/actix/actix-web.svg?branch=master)](https://travis-ci.org/actix/actix-web)
[![codecov](https://codecov.io/gh/actix/actix-web/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-web)

View File

@ -1,6 +1,21 @@
# Changes
## Unreleased - 2020-xx-xx
## 2.2.2 - 2022-01-21
### Changed
- Migrate to `brotli` crate. [ad7e3c06]
[ad7e3c06]: https://github.com/actix/actix-web/commit/ad7e3c06
## 2.2.1 - 2021-08-09
### Fixed
- Potential HTTP request smuggling vulnerabilities. [RUSTSEC-2021-0081](https://github.com/rustsec/advisory-db/pull/977)
## 2.2.0 - 2020-11-25
### Added
* HttpResponse builders for 1xx status codes. [#1768]
* `Accept::mime_precedence` and `Accept::mime_preference`. [#1793]
@ -10,8 +25,9 @@
* Started dropping `transfer-encoding: chunked` and `Content-Length` for 1XX and 204 responses. [#1767]
### Changed
* Upgrade `serde_urlencoded` to `0.7`.
* Upgrade `serde_urlencoded` to `0.7`. [#1773]
[#1773]: https://github.com/actix/actix-web/pull/1773
[#1767]: https://github.com/actix/actix-web/pull/1767
[#1768]: https://github.com/actix/actix-web/pull/1768
[#1793]: https://github.com/actix/actix-web/pull/1793

View File

@ -1,6 +1,6 @@
[package]
name = "actix-http"
version = "2.1.0"
version = "2.2.2"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "HTTP primitives for the Actix ecosystem"
readme = "README.md"
@ -31,7 +31,7 @@ openssl = ["actix-tls/openssl", "actix-connect/openssl"]
rustls = ["actix-tls/rustls", "actix-connect/rustls"]
# enable compressison support
compress = ["flate2", "brotli2"]
compress = ["flate2", "brotli"]
# support for secure cookies
secure-cookies = ["cookie/secure"]
@ -82,7 +82,7 @@ serde_urlencoded = "0.7"
time = { version = "0.2.7", default-features = false, features = ["std"] }
# compression
brotli2 = { version="0.3.2", optional = true }
brotli = { version = "3.3.3", optional = true }
flate2 = { version = "1.0.13", optional = true }
[dev-dependencies]

View File

@ -3,14 +3,14 @@
> HTTP primitives for the Actix ecosystem.
[![crates.io](https://img.shields.io/crates/v/actix-http?label=latest)](https://crates.io/crates/actix-http)
[![Documentation](https://docs.rs/actix-http/badge.svg?version=2.1.0)](https://docs.rs/actix-http/2.1.0)
[![Documentation](https://docs.rs/actix-http/badge.svg?version=2.2.2)](https://docs.rs/actix-http/2.2.2)
![Apache 2.0 or MIT licensed](https://img.shields.io/crates/l/actix-http)
[![Dependency Status](https://deps.rs/crate/actix-http/2.1.0/status.svg)](https://deps.rs/crate/actix-http/2.1.0)
[![Dependency Status](https://deps.rs/crate/actix-http/2.2.2/status.svg)](https://deps.rs/crate/actix-http/2.2.2)
[![Join the chat at https://gitter.im/actix/actix-web](https://badges.gitter.im/actix/actix-web.svg)](https://gitter.im/actix/actix-web?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
## Documentation & Resources
- [API Documentation](https://docs.rs/actix-http/2.1.0)
- [API Documentation](https://docs.rs/actix-http)
- [Chat on Gitter](https://gitter.im/actix/actix-web)
- Minimum Supported Rust Version (MSRV): 1.42.0

View File

@ -4,7 +4,7 @@ use std::pin::Pin;
use std::task::{Context, Poll};
use actix_threadpool::{run, CpuFuture};
use brotli2::write::BrotliDecoder;
use brotli::DecompressorWriter as BrotliDecoder;
use bytes::Bytes;
use flate2::write::{GzDecoder, ZlibDecoder};
use futures_core::{ready, Stream};
@ -31,7 +31,7 @@ where
pub fn new(stream: S, encoding: ContentEncoding) -> Decoder<S> {
let decoder = match encoding {
ContentEncoding::Br => Some(ContentDecoder::Br(Box::new(
BrotliDecoder::new(Writer::new()),
BrotliDecoder::new(Writer::new(), 8 * 1024),
))),
ContentEncoding::Deflate => Some(ContentDecoder::Deflate(Box::new(
ZlibDecoder::new(Writer::new()),

View File

@ -5,7 +5,7 @@ use std::pin::Pin;
use std::task::{Context, Poll};
use actix_threadpool::{run, CpuFuture};
use brotli2::write::BrotliEncoder;
use brotli::CompressorWriter as BrotliEncoder;
use bytes::Bytes;
use flate2::write::{GzEncoder, ZlibEncoder};
use futures_core::ready;
@ -212,9 +212,12 @@ impl ContentEncoder {
Writer::new(),
flate2::Compression::fast(),
))),
ContentEncoding::Br => {
Some(ContentEncoder::Br(BrotliEncoder::new(Writer::new(), 3)))
}
ContentEncoding::Br => Some(ContentEncoder::Br(BrotliEncoder::new(
Writer::new(),
32 * 1024,
3,
22,
))),
_ => None,
}
}
@ -230,8 +233,8 @@ impl ContentEncoder {
fn finish(self) -> Result<Bytes, io::Error> {
match self {
ContentEncoder::Br(encoder) => match encoder.finish() {
Ok(writer) => Ok(writer.buf.freeze()),
ContentEncoder::Br(mut encoder) => match encoder.flush() {
Ok(()) => Ok(encoder.into_inner().buf.freeze()),
Err(err) => Err(err),
},
ContentEncoder::Gzip(encoder) => match encoder.finish() {

View File

@ -55,7 +55,7 @@ impl Error {
/// Similar to `as_response_error` but downcasts.
pub fn as_error<T: ResponseError + 'static>(&self) -> Option<&T> {
ResponseError::downcast_ref(self.cause.as_ref())
<dyn ResponseError>::downcast_ref(self.cause.as_ref())
}
}

View File

@ -67,6 +67,7 @@ pub(crate) trait MessageType: Sized {
let mut has_upgrade_websocket = false;
let mut expect = false;
let mut chunked = false;
let mut seen_te = false;
let mut content_length = None;
{
@ -85,8 +86,17 @@ pub(crate) trait MessageType: Sized {
};
match name {
header::CONTENT_LENGTH => {
if let Ok(s) = value.to_str() {
header::CONTENT_LENGTH if content_length.is_some() => {
debug!("multiple Content-Length");
return Err(ParseError::Header);
}
header::CONTENT_LENGTH => match value.to_str() {
Ok(s) if s.trim().starts_with("+") => {
debug!("illegal Content-Length: {:?}", s);
return Err(ParseError::Header);
}
Ok(s) => {
if let Ok(len) = s.parse::<u64>() {
if len != 0 {
content_length = Some(len);
@ -95,15 +105,31 @@ pub(crate) trait MessageType: Sized {
debug!("illegal Content-Length: {:?}", s);
return Err(ParseError::Header);
}
} else {
}
Err(_) => {
debug!("illegal Content-Length: {:?}", value);
return Err(ParseError::Header);
}
}
},
// transfer-encoding
header::TRANSFER_ENCODING if seen_te => {
debug!("multiple Transfer-Encoding not allowed");
return Err(ParseError::Header);
}
header::TRANSFER_ENCODING => {
seen_te = true;
if let Ok(s) = value.to_str().map(|s| s.trim()) {
chunked = s.eq_ignore_ascii_case("chunked");
if s.eq_ignore_ascii_case("chunked") {
chunked = true;
} else if s.eq_ignore_ascii_case("identity") {
// allow silently since multiple TE headers are already checked
} else {
debug!("illegal Transfer-Encoding: {:?}", s);
return Err(ParseError::Header);
}
} else {
return Err(ParseError::Header);
}
@ -510,19 +536,11 @@ impl ChunkedState {
size: &mut u64,
) -> Poll<Result<ChunkedState, io::Error>> {
let radix = 16;
match byte!(rdr) {
b @ b'0'..=b'9' => {
*size *= radix;
*size += u64::from(b - b'0');
}
b @ b'a'..=b'f' => {
*size *= radix;
*size += u64::from(b + 10 - b'a');
}
b @ b'A'..=b'F' => {
*size *= radix;
*size += u64::from(b + 10 - b'A');
}
let rem = match byte!(rdr) {
b @ b'0'..=b'9' => b - b'0',
b @ b'a'..=b'f' => b + 10 - b'a',
b @ b'A'..=b'F' => b + 10 - b'A',
b'\t' | b' ' => return Poll::Ready(Ok(ChunkedState::SizeLws)),
b';' => return Poll::Ready(Ok(ChunkedState::Extension)),
b'\r' => return Poll::Ready(Ok(ChunkedState::SizeLf)),
@ -532,9 +550,24 @@ impl ChunkedState {
"Invalid chunk size line: Invalid Size",
)));
}
}
};
match size.checked_mul(radix) {
Some(n) => {
*size = n as u64;
*size += rem as u64;
Poll::Ready(Ok(ChunkedState::Size))
}
None => {
debug!("chunk size would overflow");
Poll::Ready(Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Invalid chunk size line: Invalid Size",
)))
}
}
}
fn read_size_lws(rdr: &mut BytesMut) -> Poll<Result<ChunkedState, io::Error>> {
trace!("read_size_lws");
@ -552,6 +585,11 @@ impl ChunkedState {
fn read_extension(rdr: &mut BytesMut) -> Poll<Result<ChunkedState, io::Error>> {
match byte!(rdr) {
b'\r' => Poll::Ready(Ok(ChunkedState::SizeLf)),
// strictly 0x20 (space) should be disallowed but we don't parse quoted strings here
0x00..=0x08 | 0x0a..=0x1f | 0x7f => Poll::Ready(Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Invalid character in chunk extension",
))),
_ => Poll::Ready(Ok(ChunkedState::Extension)), // no supported extensions
}
}
@ -977,13 +1015,7 @@ mod tests {
"GET /test HTTP/1.1\r\n\
transfer-encoding: chnked\r\n\r\n",
);
let req = parse_ready!(&mut buf);
if let Ok(val) = req.chunked() {
assert!(!val);
} else {
unreachable!("Error");
}
expect_parse_err!(&mut buf);
}
#[test]

View File

@ -80,6 +80,7 @@ pub(crate) trait MessageType: Sized {
match length {
BodySize::Stream => {
if chunked {
skip_len = true;
if camel_case {
dst.put_slice(b"\r\nTransfer-Encoding: chunked\r\n")
} else {

View File

@ -1,8 +1,19 @@
# Changes
## Unreleased - 2020-xx-xx
## 2.0.3 - 2020-11-29
### Fixed
* Ensure `actix-http` dependency uses same `serde_urlencoded`.
## 2.0.2 - 2020-11-25
### Changed
* Upgrade `serde_urlencoded` to `0.7`.
* Upgrade `serde_urlencoded` to `0.7`. [#1773]
[#1773]: https://github.com/actix/actix-web/pull/1773
## 2.0.1 - 2020-10-30
### Changed

View File

@ -1,6 +1,6 @@
[package]
name = "awc"
version = "2.0.1"
version = "2.0.3"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Async HTTP and WebSocket client library built on the Actix ecosystem"
readme = "README.md"
@ -39,7 +39,7 @@ compress = ["actix-http/compress"]
[dependencies]
actix-codec = "0.3.0"
actix-service = "1.0.6"
actix-http = "2.0.0"
actix-http = "2.2.0"
actix-rt = "1.0.0"
base64 = "0.13"
@ -65,7 +65,7 @@ actix-http-test = { version = "2.0.0", features = ["openssl"] }
actix-utils = "2.0.0"
actix-server = "1.0.0"
actix-tls = { version = "2.0.0", features = ["openssl", "rustls"] }
brotli2 = "0.3.2"
brotli = "3.3.3"
flate2 = "1.0.13"
futures-util = { version = "0.3.5", default-features = false }
env_logger = "0.7"

View File

@ -3,14 +3,14 @@
> Async HTTP and WebSocket client library.
[![crates.io](https://img.shields.io/crates/v/awc?label=latest)](https://crates.io/crates/awc)
[![Documentation](https://docs.rs/awc/badge.svg?version=2.0.1)](https://docs.rs/awc/2.0.1)
[![Documentation](https://docs.rs/awc/badge.svg?version=2.0.3)](https://docs.rs/awc/2.0.3)
![Apache 2.0 or MIT licensed](https://img.shields.io/crates/l/awc)
[![Dependency Status](https://deps.rs/crate/awc/2.0.1/status.svg)](https://deps.rs/crate/awc/2.0.1)
[![Dependency Status](https://deps.rs/crate/awc/2.0.3/status.svg)](https://deps.rs/crate/awc/2.0.3)
[![Join the chat at https://gitter.im/actix/actix-web](https://badges.gitter.im/actix/actix-web.svg)](https://gitter.im/actix/actix-web?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
## Documentation & Resources
- [API Documentation](https://docs.rs/awc/2.0.1)
- [API Documentation](https://docs.rs/awc)
- [Example Project](https://github.com/actix/examples/tree/HEAD/awc_https)
- [Chat on Gitter](https://gitter.im/actix/actix-web)
- Minimum Supported Rust Version (MSRV): 1.42.0

View File

@ -4,7 +4,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::Duration;
use brotli2::write::BrotliEncoder;
use brotli::CompressorWriter as BrotliEncoder;
use bytes::Bytes;
use flate2::read::GzDecoder;
use flate2::write::GzEncoder;
@ -506,9 +506,10 @@ async fn test_client_gzip_encoding_large_random() {
async fn test_client_brotli_encoding() {
let srv = test::start(|| {
App::new().service(web::resource("/").route(web::to(|data: Bytes| {
let mut e = BrotliEncoder::new(Vec::new(), 5);
let mut e = BrotliEncoder::new(Vec::new(), 8096, 5, 22);
e.write_all(&data).unwrap();
let data = e.finish().unwrap();
e.flush().unwrap();
let data = e.into_inner();
HttpResponse::Ok()
.header("content-encoding", "br")
.body(data)
@ -533,9 +534,9 @@ async fn test_client_brotli_encoding_large_random() {
let srv = test::start(|| {
App::new().service(web::resource("/").route(web::to(|data: Bytes| {
let mut e = BrotliEncoder::new(Vec::new(), 5);
let mut e = BrotliEncoder::new(Vec::new(), 8096, 5, 22);
e.write_all(&data).unwrap();
let data = e.finish().unwrap();
let data = e.into_inner();
HttpResponse::Ok()
.header("content-encoding", "br")
.body(data)

View File

@ -2,29 +2,31 @@ digraph {
subgraph cluster_web {
label="actix/actix-web"
"awc"
"actix-web"
"actix-files"
"actix-http"
"actix-multipart"
"actix-web-actors"
"actix-web-codegen"
"web"
"files"
"http"
"multipart"
"web-actors"
"codegen"
"http-test"
}
"actix-web" -> { "actix-codec" "actix-service" "actix-utils" "actix-router" "actix-rt" "actix-server" "actix-testing" "actix-macros" "actix-threadpool" "actix-tls" "actix-web-codegen" "actix-http" "awc" }
"awc" -> { "actix-codec" "actix-service" "actix-http" "actix-rt" }
"actix-web-actors" -> { "actix" "actix-web" "actix-http" "actix-codec" }
"actix-multipart" -> { "actix-web" "actix-service" "actix-utils" }
"actix-http" -> { "actix-service" "actix-codec" "actix-connect" "actix-utils" "actix-rt" "actix-threadpool" }
"actix-http" -> { "actix" "actix-tls" }[color=blue] // optional
"actix-files" -> { "actix-web" "actix-http" }
"web" -> { "codec" "service" "utils" "router" "rt" "server" "testing" "macros" "threadpool" "tls" "codegen" "http" "awc" }
"awc" -> { "codec" "service" "http" "rt" }
"web-actors" -> { "actix" "web" "http" "codec" }
"multipart" -> { "web" "service" "utils" }
"http" -> { "service" "codec" "connect" "utils" "rt" "threadpool" }
"http" -> { "actix" "tls" }[color=blue] // optional
"files" -> { "web" }
"http-test" -> { "service" "codec" "connect" "utils" "rt" "server" "testing" "awc" }
// net
"actix-utils" -> { "actix-service" "actix-rt" "actix-codec" }
"actix-tracing" -> { "actix-service" }
"actix-tls" -> { "actix-service" "actix-codec" "actix-utils" }
"actix-testing" -> { "actix-rt" "actix-macros" "actix-server" "actix-service" }
"actix-server" -> { "actix-service" "actix-rt" "actix-codec" "actix-utils" }
"actix-rt" -> { "actix-macros" "actix-threadpool" }
"actix-connect" -> { "actix-service" "actix-codec" "actix-utils" "actix-rt" }
"utils" -> { "service" "rt" "codec" }
"tracing" -> { "service" }
"tls" -> { "service" "codec" "utils" }
"testing" -> { "rt" "macros" "server" "service" }
"server" -> { "service" "rt" "codec" "utils" }
"rt" -> { "macros" "threadpool" }
"connect" -> { "service" "codec" "utils" "rt" }
}

View File

@ -8,6 +8,7 @@ digraph {
"actix-multipart"
"actix-web-actors"
"actix-web-codegen"
"actix-http-test"
}
"actix-web" -> { "actix-web-codegen" "actix-http" "awc" }
@ -15,5 +16,6 @@ digraph {
"actix-web-actors" -> { "actix" "actix-web" "actix-http" }
"actix-multipart" -> { "actix-web" }
"actix-http" -> { "actix" }[color=blue] // optional
"actix-files" -> { "actix-web" "actix-http" }
"actix-files" -> { "actix-web" }
"actix-http-test" -> { "awc" }
}

View File

@ -1,4 +1,4 @@
//! Actix web is a powerful, pragmatic, and extremely fast web framework for Rust.
//! Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust.
//!
//! ## Example
//!

View File

@ -31,7 +31,7 @@ impl Default for TrailingSlash {
}
}
#[derive(Default, Clone, Copy)]
#[derive(Clone, Copy)]
/// `Middleware` to normalize request's URI in place
///
/// Performs following:
@ -56,6 +56,18 @@ impl Default for TrailingSlash {
pub struct NormalizePath(TrailingSlash);
impl Default for NormalizePath {
fn default() -> Self {
log::warn!(
"`NormalizePath::default()` is deprecated. The default trailing slash behavior will \
change in v4 from `Always` to `Trim`. Update your call to `NormalizePath::new(...)` to \
avoid inaccessible routes when upgrading."
);
Self(TrailingSlash::default())
}
}
impl NormalizePath {
/// Create new `NormalizePath` middleware with the specified trailing slash style.
pub fn new(trailing_slash_style: TrailingSlash) -> Self {
@ -137,9 +149,9 @@ where
// so the change can not be deduced from the length comparison
if path != original_path {
let mut parts = head.uri.clone().into_parts();
let pq = parts.path_and_query.as_ref().unwrap();
let query = parts.path_and_query.as_ref().and_then(|pq| pq.query());
let path = if let Some(q) = pq.query() {
let path = if let Some(q) = query {
Bytes::from(format!("{}?{}", path, q))
} else {
Bytes::copy_from_slice(path.as_bytes())

View File

@ -675,4 +675,40 @@ mod tests {
let res = call_service(&mut srv, req).await;
assert_eq!(res.status(), StatusCode::OK);
}
#[actix_rt::test]
async fn extract_path_pattern_complex() {
let mut srv = init_service(
App::new()
.service(web::scope("/user").service(web::scope("/{id}").service(
web::resource("").to(move |req: HttpRequest| {
assert_eq!(req.match_pattern(), Some("/user/{id}".to_owned()));
HttpResponse::Ok().finish()
}),
)))
.service(web::resource("/").to(move |req: HttpRequest| {
assert_eq!(req.match_pattern(), Some("/".to_owned()));
HttpResponse::Ok().finish()
}))
.default_service(web::to(move |req: HttpRequest| {
assert!(req.match_pattern().is_none());
HttpResponse::Ok().finish()
})),
)
.await;
let req = TestRequest::get().uri("/user/test").to_request();
let res = call_service(&mut srv, req).await;
assert_eq!(res.status(), StatusCode::OK);
let req = TestRequest::get().uri("/").to_request();
let res = call_service(&mut srv, req).await;
assert_eq!(res.status(), StatusCode::OK);
let req = TestRequest::get().uri("/not-exist").to_request();
let res = call_service(&mut srv, req).await;
assert_eq!(res.status(), StatusCode::OK);
}
}

View File

@ -86,7 +86,7 @@ impl ResourceMap {
if let Some(plen) = pattern.is_prefix_match(path) {
return rmap.has_resource(&path[plen..]);
}
} else if pattern.is_match(path) {
} else if pattern.is_match(path) || pattern.pattern() == "" && path == "/" {
return true;
}
}

View File

@ -2,15 +2,20 @@
## Unreleased - 2020-xx-xx
* add ability to set address for `TestServer` [#1645]
* Upgrade `base64` to `0.13`.
* Upgrade `serde_urlencoded` to `0.7`.
## 2.1.0 - 2020-11-25
* Add ability to set address for `TestServer`. [#1645]
* Upgrade `base64` to `0.13`.
* Upgrade `serde_urlencoded` to `0.7`. [#1773]
[#1773]: https://github.com/actix/actix-web/pull/1773
[#1645]: https://github.com/actix/actix-web/pull/1645
## 2.0.0 - 2020-09-11
* Update actix-codec and actix-utils dependencies.
## 2.0.0-alpha.1 - 2020-05-23
* Update the `time` dependency to 0.2.7
* Update `actix-connect` dependency to 2.0.0-alpha.2
@ -20,74 +25,56 @@
* Update `base64` dependency to 0.12
* Update `env_logger` dependency to 0.7
## [1.0.0] - 2019-12-13
### Changed
## 1.0.0 - 2019-12-13
* Replaced `TestServer::start()` with `test_server()`
## [1.0.0-alpha.3] - 2019-12-07
### Changed
## 1.0.0-alpha.3 - 2019-12-07
* Migrate to `std::future`
## [0.2.5] - 2019-09-17
### Changed
## 0.2.5 - 2019-09-17
* Update serde_urlencoded to "0.6.1"
* Increase TestServerRuntime timeouts from 500ms to 3000ms
### Fixed
* Do not override current `System`
## [0.2.4] - 2019-07-18
## 0.2.4 - 2019-07-18
* Update actix-server to 0.6
## [0.2.3] - 2019-07-16
## 0.2.3 - 2019-07-16
* Add `delete`, `options`, `patch` methods to `TestServerRunner`
## [0.2.2] - 2019-06-16
## 0.2.2 - 2019-06-16
* Add .put() and .sput() methods
## [0.2.1] - 2019-06-05
## 0.2.1 - 2019-06-05
* Add license files
## [0.2.0] - 2019-05-12
## 0.2.0 - 2019-05-12
* Update awc and actix-http deps
## [0.1.1] - 2019-04-24
## 0.1.1 - 2019-04-24
* Always make new connection for http client
## [0.1.0] - 2019-04-16
## 0.1.0 - 2019-04-16
* No changes
## [0.1.0-alpha.3] - 2019-04-02
## 0.1.0-alpha.3 - 2019-04-02
* Request functions accept path #743
## [0.1.0-alpha.2] - 2019-03-29
## 0.1.0-alpha.2 - 2019-03-29
* Added TestServerRuntime::load_body() method
* Update actix-http and awc libraries
## [0.1.0-alpha.1] - 2019-03-28
## 0.1.0-alpha.1 - 2019-03-28
* Initial impl

View File

@ -1,8 +1,8 @@
[package]
name = "actix-http-test"
version = "2.0.0"
version = "2.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix HTTP test server"
description = "Various helpers for Actix applications to use during testing"
readme = "README.md"
keywords = ["http", "web", "framework", "async", "futures"]
homepage = "https://actix.rs"

View File

@ -1,9 +1,15 @@
# Actix http test server [![Build Status](https://travis-ci.org/actix/actix-web.svg?branch=master)](https://travis-ci.org/actix/actix-web) [![codecov](https://codecov.io/gh/actix/actix-web/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-web) [![crates.io](https://meritbadge.herokuapp.com/actix-http-test)](https://crates.io/crates/actix-http-test) [![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
# actix-http-test
## Documentation & community resources
> Various helpers for Actix applications to use during testing.
* [User Guide](https://actix.rs/docs/)
* [API Documentation](https://docs.rs/actix-http-test/)
* [Chat on gitter](https://gitter.im/actix/actix)
* Cargo package: [actix-http-test](https://crates.io/crates/actix-http-test)
* Minimum supported Rust version: 1.40 or later
[![crates.io](https://img.shields.io/crates/v/actix-http-test?label=latest)](https://crates.io/crates/actix-http-test)
[![Documentation](https://docs.rs/actix-http-test/badge.svg?version=2.1.0)](https://docs.rs/actix-http-test/2.1.0)
![Apache 2.0 or MIT licensed](https://img.shields.io/crates/l/actix-http-test)
[![Dependency Status](https://deps.rs/crate/actix-http-test/2.1.0/status.svg)](https://deps.rs/crate/actix-http-test/2.1.0)
[![Join the chat at https://gitter.im/actix/actix-web](https://badges.gitter.im/actix/actix-web.svg)](https://gitter.im/actix/actix-web?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
## Documentation & Resources
- [API Documentation](https://docs.rs/actix-http-test)
- [Chat on Gitter](https://gitter.im/actix/actix-web)
- Minimum Supported Rust Version (MSRV): 1.42.0

View File

@ -1,4 +1,9 @@
//! Various helpers for Actix applications to use during testing.
#![deny(rust_2018_idioms)]
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
use std::sync::mpsc;
use std::{net, thread, time};

View File

@ -7,7 +7,8 @@ use actix_http::http::header::{
ContentEncoding, ACCEPT_ENCODING, CONTENT_ENCODING, CONTENT_LENGTH,
TRANSFER_ENCODING,
};
use brotli2::write::{BrotliDecoder, BrotliEncoder};
use brotli::{CompressorWriter as BrotliEncoder, DecompressorWriter as BrotliDecoder};
use bytes::Bytes;
use flate2::read::GzDecoder;
use flate2::write::{GzEncoder, ZlibDecoder, ZlibEncoder};
@ -340,9 +341,9 @@ async fn test_body_br_streaming() {
println!("TEST: {:?}", bytes.len());
// decode br
let mut e = BrotliDecoder::new(Vec::with_capacity(2048));
let mut e = BrotliDecoder::new(Vec::with_capacity(2048), 8096);
e.write_all(bytes.as_ref()).unwrap();
let dec = e.finish().unwrap();
let dec = e.into_inner().unwrap();
println!("T: {:?}", Bytes::copy_from_slice(&dec));
assert_eq!(Bytes::from(dec), Bytes::from_static(STR.as_ref()));
}
@ -439,9 +440,9 @@ async fn test_body_brotli() {
let bytes = response.body().await.unwrap();
// decode brotli
let mut e = BrotliDecoder::new(Vec::with_capacity(2048));
let mut e = BrotliDecoder::new(Vec::with_capacity(2048), 8096);
e.write_all(bytes.as_ref()).unwrap();
let dec = e.finish().unwrap();
let dec = e.into_inner().unwrap();
assert_eq!(Bytes::from(dec), Bytes::from_static(STR.as_ref()));
}
@ -650,9 +651,10 @@ async fn test_brotli_encoding() {
)
});
let mut e = BrotliEncoder::new(Vec::new(), 5);
let mut e = BrotliEncoder::new(Vec::new(), 8096, 5, 22);
e.write_all(STR.as_ref()).unwrap();
let enc = e.finish().unwrap();
e.flush().unwrap();
let enc = e.into_inner();
// client request
let request = srv
@ -684,9 +686,10 @@ async fn test_brotli_encoding_large() {
)
});
let mut e = BrotliEncoder::new(Vec::new(), 5);
let mut e = BrotliEncoder::new(Vec::new(), 8096, 5, 22);
e.write_all(data.as_ref()).unwrap();
let enc = e.finish().unwrap();
e.flush().unwrap();
let enc = e.into_inner();
// client request
let request = srv
@ -724,9 +727,9 @@ async fn test_brotli_encoding_large_openssl() {
});
// body
let mut e = BrotliEncoder::new(Vec::new(), 3);
let mut e = BrotliEncoder::new(Vec::new(), 8096, 5, 22);
e.write_all(data.as_ref()).unwrap();
let enc = e.finish().unwrap();
let enc = e.into_inner();
// client request
let mut response = srv