1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-07-23 17:28:19 +02:00

Compare commits

...

68 Commits

Author SHA1 Message Date
Nikolay Kim
48476362a3 update changes 2019-12-20 17:59:34 +06:00
Nikolay Kim
2b4256baab add links to configs 2019-12-20 17:49:05 +06:00
Nikolay Kim
e5a50f423d Make web::Data deref to Arc<T> #1214 2019-12-20 17:45:35 +06:00
Nikolay Kim
8b8a9a995d bump ver 2019-12-20 17:36:48 +06:00
Nikolay Kim
74fa4060c2 fix awc tests 2019-12-20 17:27:32 +06:00
Nikolay Kim
c877840c07 rename App::register_data to App::app_data and HttpRequest::app_data returns Option<&T> instead of Option<&Data<T>> 2019-12-20 17:13:09 +06:00
Nikolay Kim
20248daeda Allow to set peer_addr for TestRequest #1074 2019-12-20 16:11:51 +06:00
Nikolay Kim
a08d8dab70 AppConfig::secure() is always false. #1202 2019-12-20 16:04:51 +06:00
tglman
fbbb4a86e9 feat: add access to the session also from immutable references (#1225) 2019-12-20 13:59:07 +06:00
Nikolay Kim
1d12ba9d5f Replace brotli with brotli2 #1224 2019-12-20 13:50:07 +06:00
Nikolay Kim
8c54054844 Use .advance() intead of .split_to() 2019-12-19 09:56:14 +06:00
Nikolay Kim
1732ae8c79 fix Bodyencoding trait usage 2019-12-18 09:30:14 +06:00
Rajasekharan Vengalil
3b860ebdc7 Fix poll_ready call for WebSockets upgrade (#1219)
* Fix poll_ready call for WebSockets upgrade

* Poll upgrade service from H1ServiceHandler too
2019-12-17 13:34:25 +06:00
Nikolay Kim
29ac6463e1 Merge branch 'master' of github.com:actix/actix-web 2019-12-16 17:22:49 +06:00
Nikolay Kim
01613f334b Move BodyEncoding to dev module #1220 2019-12-16 17:22:26 +06:00
Andrii Radyk
30dcaf9da0 fix deprecated Error::description (#1218) 2019-12-16 07:43:19 +06:00
Nikolay Kim
b0aa9395da prep actix-web alpha.6 release 2019-12-15 22:51:14 +06:00
Nikolay Kim
a153374b61 migrate actix-web-actors 2019-12-15 22:45:38 +06:00
Nikolay Kim
a791aab418 prep awc release 2019-12-15 13:36:05 +06:00
Nikolay Kim
cb705317b8 compile with default-features off 2019-12-15 13:28:54 +06:00
Nikolay Kim
e8e0f98f96 fix docs.rs features list 2019-12-13 12:41:48 +06:00
Nikolay Kim
c878f66d05 fix docs.rs features list 2019-12-13 12:40:22 +06:00
Nikolay Kim
fac6dec3c9 update deps 2019-12-13 12:36:15 +06:00
Nikolay Kim
232f71b3b5 update changes 2019-12-13 12:18:30 +06:00
Nikolay Kim
8881c13e60 update changes 2019-12-13 12:16:43 +06:00
Nikolay Kim
d006a7b31f update changes 2019-12-13 12:10:45 +06:00
Nikolay Kim
3d64d565d9 fix warnings 2019-12-13 11:46:02 +06:00
Nikolay Kim
c1deaaeb2f cleanup imports 2019-12-13 11:24:57 +06:00
Nikolay Kim
b81417c2fa fix warnings 2019-12-13 10:59:02 +06:00
Nikolay Kim
4937c9f9c2 refactor http-test server 2019-12-12 23:08:38 +06:00
Nikolay Kim
db1d6b7963 refactor test server impl 2019-12-12 22:28:47 +06:00
Nikolay Kim
fa07415721 Replace flate2-xxx features with compress 2019-12-12 15:08:08 +06:00
Nikolay Kim
b4b3350b3e Add websockets continuation frame support 2019-12-12 14:06:54 +06:00
Jonathan Speiser
4a1695f719 fixes missing import in example (#1210) 2019-12-12 07:06:22 +06:00
0x1793d1
1b8d747937 Fix extra line feed (#1209) 2019-12-12 07:05:39 +06:00
Emilio González
a43a005f59 Log path if it is not a directory (#1208) 2019-12-12 07:04:53 +06:00
Alexander Larsson
a612b74aeb actix-multipart: Fix multipart boundary reading (#1205)
* actix-multipart: Fix multipart boundary reading

If we're not ready to read the first line after the multipart field
(which should be a "\r\n" line) then return Pending instead of Ready(None)
so that we will get called again to read that line.

Without this I was getting MultipartError::Boundary from read_boundary()
because it got the "\r\n" line instead of the boundary.

Also tweaks the test_stream test to test partial reads.

This is a forward port of #1189 from 1.0

* actix-multipart: Update changes for boundary fix
2019-12-12 07:03:44 +06:00
Nikolay Kim
131c897099 upgrade to actix-net release 2019-12-11 19:20:20 +06:00
Nikolay Kim
ef3a33b9d6 use std mutext instead of parking_lot 2019-12-10 09:00:51 +06:00
Nikolay Kim
5132257b0d Fix buffer remaining capacity calcualtion 2019-12-09 21:55:22 +06:00
Nikolay Kim
0c1f5f9edc Check Upgrade service readiness before calling it 2019-12-09 17:40:15 +06:00
Sameer Dhar
e4382e4fc1 Fix broken docs (#1204)
Fixed un escaped brackets in lib.rs, and reflowed links to ConnectionInfo in app, config, and server.rs
2019-12-09 10:02:43 +06:00
Nikolay Kim
a3ce371312 ws ping and pong uses bytes #1049 2019-12-09 07:01:22 +06:00
Nikolay Kim
42258ee289 deps 2019-12-08 20:22:39 +06:00
Nikolay Kim
b92eafb839 prepare actix-http release 2019-12-08 20:15:51 +06:00
Nikolay Kim
3b2e78db47 add link to chat 2019-12-08 19:27:06 +06:00
Nikolay Kim
63da1a5560 Merge branch 'master' of github.com:actix/actix-web 2019-12-08 19:26:12 +06:00
Nikolay Kim
1f3ffe38e8 update actix-service dep 2019-12-08 19:25:24 +06:00
krircc
c23b6b3879 Merge pull request #1192 from krircc/master
Add rich project metadata
2019-12-08 16:03:39 +08:00
Yuki Okushi
909c7c8b5b Merge branch 'master' into master 2019-12-08 16:26:35 +09:00
Nikolay Kim
4a8a9ef405 update tests and clippy warnings 2019-12-08 12:31:16 +06:00
Nikolay Kim
6c9f9fff73 clippy warnings 2019-12-08 00:46:51 +06:00
Nikolay Kim
8df33f7a81 remove HttpServer::run() as it is not useful with async/await 2019-12-08 00:06:04 +06:00
Nikolay Kim
7ec5ca88a1 update changes 2019-12-07 22:01:55 +06:00
daxpedda
e5f3d88a4e Switch brotli compressor to rust. (#1197)
* Switch to a rustified version of brotli.

* Some memory optimizations.

* Make brotli not optional anymore.
2019-12-07 21:55:41 +06:00
Nikolay Kim
0ba125444a Add impl ResponseBuilder for Error 2019-12-07 21:41:34 +06:00
Nikolay Kim
6c226e47bd prepare actix-web-actors release 2019-12-07 20:10:36 +06:00
Vlad Frolov
8c3f58db9d Allow comma-separated websocket subprotocols without spaces (#1172)
* Allow comma-separated websocket subprotocols without spaces

* [CHANGES] Added an entry to CHANGES.md
2019-12-07 20:08:06 +06:00
daxpedda
4921243add Fix rustls build. (#1195) 2019-12-07 16:14:09 +06:00
daxpedda
91b3fcf85c Fix dependency features. (#1196) 2019-12-07 16:13:26 +06:00
Yuki Okushi
f2ba389496 Merge branch 'master' into master 2019-12-06 16:57:42 +09:00
krircc
439f02b6b1 Update README.md 2019-12-06 14:59:11 +08:00
krircc
e32da08a26 Update README.md 2019-12-06 14:34:14 +08:00
krircc
82110e0927 Update README.md 2019-12-06 14:29:10 +08:00
krircc
7b3354a9ad Update README.md 2019-12-06 14:26:23 +08:00
krircc
5243e8baca Update README.md 2019-12-06 14:23:28 +08:00
krircc
98903028c7 Update README.md 2019-12-06 14:22:29 +08:00
krircc
b7d44d6c4c Merge pull request #1 from actix/master
git pull
2019-12-01 16:56:42 +08:00
144 changed files with 2959 additions and 2236 deletions

View File

@@ -1,5 +1,42 @@
# Changes
## [2.0.0-rc] - 2019-12-20
### Changed
* Move `BodyEncoding` to `dev` module #1220
* Allow to set `peer_addr` for TestRequest #1074
* Make web::Data deref to Arc<T> #1214
* Rename `App::register_data()` to `App::app_data()`
* `HttpRequest::app_data<T>()` returns `Option<&T>` instead of `Option<&Data<T>>`
### Fixed
* Fix `AppConfig::secure()` is always false. #1202
## [2.0.0-alpha.6] - 2019-12-15
### Fixed
* Fixed compilation with default features off
## [2.0.0-alpha.5] - 2019-12-13
### Added
* Add test server, `test::start()` and `test::start_with()`
## [2.0.0-alpha.4] - 2019-12-08
### Deleted
* Delete HttpServer::run(), it is not useful witht async/await
## [2.0.0-alpha.3] - 2019-12-07
### Changed

View File

@@ -1,6 +1,6 @@
[package]
name = "actix-web"
version = "2.0.0-alpha.3"
version = "2.0.0-rc"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix web is a simple, pragmatic and extremely fast web framework for Rust."
readme = "README.md"
@@ -12,11 +12,10 @@ categories = ["network-programming", "asynchronous",
"web-programming::http-server",
"web-programming::websocket"]
license = "MIT/Apache-2.0"
exclude = [".gitignore", ".travis.yml", ".cargo/config", "appveyor.yml"]
edition = "2018"
[package.metadata.docs.rs]
features = ["openssl", "brotli", "flate2-zlib", "secure-cookies", "client"]
features = ["openssl", "rustls", "compress", "secure-cookies"]
[badges]
travis-ci = { repository = "actix/actix-web", branch = "master" }
@@ -43,47 +42,39 @@ members = [
]
[features]
default = ["brotli", "flate2-zlib", "client", "fail"]
default = ["compress", "failure"]
# http client
client = ["awc"]
# brotli encoding, requires c compiler
brotli = ["actix-http/brotli"]
# miniz-sys backend for flate2 crate
flate2-zlib = ["actix-http/flate2-zlib"]
# rust backend for flate2 crate
flate2-rust = ["actix-http/flate2-rust"]
# content-encoding support
compress = ["actix-http/compress", "awc/compress"]
# sessions feature, session require "ring" crate and c compiler
secure-cookies = ["actix-http/secure-cookies"]
fail = ["actix-http/fail"]
failure = ["actix-http/failure"]
# openssl
openssl = ["open-ssl", "actix-tls/openssl", "awc/openssl"]
openssl = ["actix-tls/openssl", "awc/openssl", "open-ssl"]
# rustls
rustls = ["rust-tls", "actix-tls/rustls", "awc/rustls"]
rustls = ["actix-tls/rustls", "awc/rustls", "rust-tls"]
[dependencies]
actix-codec = "0.2.0-alpha.3"
actix-service = "1.0.0-alpha.3"
actix-utils = "1.0.0-alpha.3"
actix-codec = "0.2.0"
actix-service = "1.0.0"
actix-utils = "1.0.3"
actix-router = "0.2.0"
actix-rt = "1.0.0-alpha.3"
actix-server = "1.0.0-alpha.3"
actix-testing = "1.0.0-alpha.3"
actix-rt = "1.0.0"
actix-server = "1.0.0"
actix-testing = "1.0.0"
actix-macros = "0.1.0"
actix-threadpool = "0.3.0"
actix-tls = { version = "1.0.0-alpha.3" }
actix-tls = "1.0.0"
actix-web-codegen = "0.2.0-alpha.2"
actix-http = "1.0.0-alpha.3"
awc = { version = "1.0.0-alpha.3", optional = true }
actix-web-codegen = "0.2.0"
actix-http = "1.0.0"
awc = { version = "1.0.1", default-features = false }
bytes = "0.5.2"
bytes = "0.5.3"
derive_more = "0.99.2"
encoding_rs = "0.8"
futures = "0.3.1"
@@ -91,7 +82,6 @@ fxhash = "0.2.1"
log = "0.4"
mime = "0.3"
net2 = "0.2.33"
parking_lot = "0.9"
pin-project = "0.4.6"
regex = "1.3"
serde = { version = "1.0", features=["derive"] }
@@ -99,20 +89,16 @@ serde_json = "1.0"
serde_urlencoded = "0.6.1"
time = "0.1.42"
url = "2.1"
# ssl support
open-ssl = { version="0.10", package="openssl", optional = true }
rust-tls = { version = "0.16", package="rustls", optional = true }
open-ssl = { version="0.10", package = "openssl", optional = true }
rust-tls = { version = "0.16.0", package = "rustls", optional = true }
[dev-dependencies]
# actix = "0.8.3"
actix-connect = "1.0.0-alpha.3"
actix-http-test = "1.0.0-alpha.3"
actix = "0.9.0-alpha.2"
rand = "0.7"
env_logger = "0.6"
serde_derive = "1.0"
brotli2 = "0.3.2"
flate2 = "1.0.2"
flate2 = "1.0.13"
[profile.release]
lto = true

View File

@@ -1,5 +1,10 @@
## 2.0.0
* `App::register_data()` renamed to `App::app_data()` and accepts any type `T: 'static`.
Stored data is available via `HttpRequest::app_data()` method at runtime.
* Extractor configuration must be registered with `App::app_data()` instead of `App::data()`
* Sync handlers has been removed. `.to_async()` method has been renamed to `.to()`
replace `fn` with `async fn` to convert sync handler to async

View File

@@ -1,4 +1,28 @@
# Actix web [![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-web)](https://crates.io/crates/actix-web) [![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)
<div align="center">
<p><h1>Actix web</h1> </p>
<p><strong>Actix web is a small, pragmatic, and extremely fast rust web framework</strong> </p>
<p>
[![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-web)](https://crates.io/crates/actix-web)
[![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)
[![Documentation](https://docs.rs/actix-web/badge.svg)](https://docs.rs/actix-web)
[![Download](https://img.shields.io/crates/d/actix-web.svg)](https://crates.io/crates/actix-web)
[![Version](https://img.shields.io/badge/rustc-1.39+-lightgray.svg)](https://blog.rust-lang.org/2019/11/07/Rust-1.39.0.html)
![License](https://img.shields.io/crates/l/actix-web.svg)
</p>
<h3>
<a href="https://actix.rs">Website</a>
<span> | </span>
<a href="https://gitter.im/actix/actix">Chat</a>
<span> | </span>
<a href="https://github.com/actix/examples">Examples</a>
</h3>
</div>
<br>
Actix web is a simple, pragmatic and extremely fast web framework for Rust.
@@ -15,18 +39,10 @@ Actix web is a simple, pragmatic and extremely fast web framework for Rust.
* Includes an asynchronous [HTTP client](https://actix.rs/actix-web/actix_web/client/index.html)
* Supports [Actix actor framework](https://github.com/actix/actix)
## Documentation & community resources
* [User Guide](https://actix.rs/docs/)
* [API Documentation (1.0)](https://docs.rs/actix-web/)
* [Chat on gitter](https://gitter.im/actix/actix)
* Cargo package: [actix-web](https://crates.io/crates/actix-web)
* Minimum supported Rust version: 1.39 or later
## Example
```rust
use actix_web::{get, App, HttpServer, Responder};
use actix_web::{get, web, App, HttpServer, Responder};
#[get("/{id}/{name}/index.html")]
async fn index(info: web::Path<(u32, String)>) -> impl Responder {

View File

@@ -1,5 +1,9 @@
# Changes
## [0.2.0] - 2019-12-20
* Release
## [0.2.0-alpha.3] - 2019-12-07
* Migrate to actix-web 2.0.0

View File

@@ -1,6 +1,6 @@
[package]
name = "actix-cors"
version = "0.2.0-alpha.3"
version = "0.2.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Cross-origin resource sharing (CORS) for Actix applications."
readme = "README.md"
@@ -17,10 +17,10 @@ name = "actix_cors"
path = "src/lib.rs"
[dependencies]
actix-web = "2.0.0-alpha.3"
actix-service = "1.0.0-alpha.3"
actix-web = "2.0.0-rc"
actix-service = "1.0.0"
derive_more = "0.99.2"
futures = "0.3.1"
[dev-dependencies]
actix-rt = "1.0.0-alpha.3"
actix-rt = "1.0.0"

View File

@@ -822,7 +822,7 @@ where
#[cfg(test)]
mod tests {
use actix_service::{service_fn2, Transform};
use actix_service::{fn_service, Transform};
use actix_web::test::{self, TestRequest};
use super::*;
@@ -1083,7 +1083,7 @@ mod tests {
.expose_headers(exposed_headers.clone())
.allowed_header(header::CONTENT_TYPE)
.finish()
.new_transform(service_fn2(|req: ServiceRequest| {
.new_transform(fn_service(|req: ServiceRequest| {
ok(req.into_response(
HttpResponse::Ok().header(header::VARY, "Accept").finish(),
))

View File

@@ -1,6 +1,10 @@
# Changes
## [0.2.0-alpha.7] - 2019-12-07
## [0.2.0] - 2019-12-20
* Fix BodyEncoding trait import #1220
## [0.2.0-alpha.1] - 2019-12-07
* Migrate to `std::future`

View File

@@ -1,6 +1,6 @@
[package]
name = "actix-files"
version = "0.2.0-alpha.3"
version = "0.2.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Static files support for actix web."
readme = "README.md"
@@ -18,11 +18,11 @@ name = "actix_files"
path = "src/lib.rs"
[dependencies]
actix-web = { version = "2.0.0-alpha.3", default-features = false }
actix-http = "1.0.0-alpha.3"
actix-service = "1.0.0-alpha.3"
actix-web = { version = "2.0.0-rc", default-features = false }
actix-http = "1.0.1"
actix-service = "1.0.0"
bitflags = "1"
bytes = "0.5.2"
bytes = "0.5.3"
futures = "0.3.1"
derive_more = "0.99.2"
log = "0.4"
@@ -32,5 +32,5 @@ percent-encoding = "2.1"
v_htmlescape = "0.4"
[dev-dependencies]
actix-rt = "1.0.0-alpha.3"
actix-web = { version = "2.0.0-alpha.3", features=["openssl"] }
actix-rt = "1.0.0"
actix-web = { version = "2.0.0-rc", features=["openssl"] }

View File

@@ -274,10 +274,14 @@ impl Files {
/// By default pool with 5x threads of available cpus is used.
/// Pool size can be changed by setting ACTIX_CPU_POOL environment variable.
pub fn new<T: Into<PathBuf>>(path: &str, dir: T) -> Files {
let dir = dir.into().canonicalize().unwrap_or_else(|_| PathBuf::new());
if !dir.is_dir() {
log::error!("Specified path is not a directory: {:?}", dir);
}
let orig_dir = dir.into();
let dir = match orig_dir.canonicalize() {
Ok(canon_dir) => canon_dir,
Err(_) => {
log::error!("Specified path is not a directory: {:?}", orig_dir);
PathBuf::new()
}
};
Files {
path: path.to_string(),

View File

@@ -12,11 +12,11 @@ use mime;
use mime_guess::from_path;
use actix_http::body::SizedStream;
use actix_web::dev::BodyEncoding;
use actix_web::http::header::{
self, Charset, ContentDisposition, DispositionParam, DispositionType, ExtendedValue,
};
use actix_web::http::{ContentEncoding, StatusCode};
use actix_web::middleware::BodyEncoding;
use actix_web::{Error, HttpMessage, HttpRequest, HttpResponse, Responder};
use futures::future::{ready, Ready};

View File

@@ -1,6 +1,6 @@
[package]
name = "actix-framed"
version = "0.3.0-alpha.1"
version = "0.3.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix framed app server"
readme = "README.md"
@@ -20,19 +20,19 @@ name = "actix_framed"
path = "src/lib.rs"
[dependencies]
actix-codec = "0.2.0-alpha.3"
actix-service = "1.0.0-alpha.3"
actix-codec = "0.2.0"
actix-service = "1.0.0"
actix-router = "0.2.0"
actix-rt = "1.0.0-alpha.3"
actix-http = "1.0.0-alpha.3"
actix-rt = "1.0.0"
actix-http = "1.0.0"
bytes = "0.5.2"
bytes = "0.5.3"
futures = "0.3.1"
pin-project = "0.4.6"
log = "0.4"
[dev-dependencies]
actix-server = { version = "1.0.0-alpha.3" }
actix-connect = { version = "1.0.0-alpha.3", features=["openssl"] }
actix-http-test = { version = "1.0.0-alpha.3", features=["openssl"] }
actix-utils = "1.0.0-alpha.3"
actix-server = "1.0.0"
actix-connect = { version = "1.0.0", features=["openssl"] }
actix-http-test = { version = "1.0.0", features=["openssl"] }
actix-utils = "1.0.3"

View File

@@ -1,9 +1,9 @@
use actix_codec::{AsyncRead, AsyncWrite};
use actix_http::{body, http::StatusCode, ws, Error, HttpService, Response};
use actix_http_test::TestServer;
use actix_http_test::test_server;
use actix_service::{pipeline_factory, IntoServiceFactory, ServiceFactory};
use actix_utils::framed::FramedTransport;
use bytes::BytesMut;
use actix_utils::framed::Dispatcher;
use bytes::Bytes;
use futures::{future, SinkExt, StreamExt};
use actix_framed::{FramedApp, FramedRequest, FramedRoute, SendError, VerifyWebSockets};
@@ -18,7 +18,7 @@ async fn ws_service<T: AsyncRead + AsyncWrite>(
.send((res, body::BodySize::None).into())
.await
.unwrap();
FramedTransport::new(framed.into_framed(ws::Codec::new()), service)
Dispatcher::new(framed.into_framed(ws::Codec::new()), service)
.await
.unwrap();
@@ -29,9 +29,9 @@ async fn service(msg: ws::Frame) -> Result<ws::Message, Error> {
let msg = match msg {
ws::Frame::Ping(msg) => ws::Message::Pong(msg),
ws::Frame::Text(text) => {
ws::Message::Text(String::from_utf8_lossy(&text.unwrap()).to_string())
ws::Message::Text(String::from_utf8_lossy(&text).to_string())
}
ws::Frame::Binary(bin) => ws::Message::Binary(bin.unwrap().freeze()),
ws::Frame::Binary(bin) => ws::Message::Binary(bin),
ws::Frame::Close(reason) => ws::Message::Close(reason),
_ => panic!(),
};
@@ -40,7 +40,7 @@ async fn service(msg: ws::Frame) -> Result<ws::Message, Error> {
#[actix_rt::test]
async fn test_simple() {
let mut srv = TestServer::start(|| {
let mut srv = test_server(|| {
HttpService::build()
.upgrade(
FramedApp::new().service(FramedRoute::get("/index.html").to(ws_service)),
@@ -60,7 +60,7 @@ async fn test_simple() {
let (item, mut framed) = framed.into_future().await;
assert_eq!(
item.unwrap().unwrap(),
ws::Frame::Text(Some(BytesMut::from("text")))
ws::Frame::Text(Bytes::from_static(b"text"))
);
framed
@@ -70,7 +70,7 @@ async fn test_simple() {
let (item, mut framed) = framed.into_future().await;
assert_eq!(
item.unwrap().unwrap(),
ws::Frame::Binary(Some(BytesMut::from(&b"text"[..])))
ws::Frame::Binary(Bytes::from_static(b"text"))
);
framed.send(ws::Message::Ping("text".into())).await.unwrap();
@@ -94,7 +94,7 @@ async fn test_simple() {
#[actix_rt::test]
async fn test_service() {
let mut srv = TestServer::start(|| {
let mut srv = test_server(|| {
pipeline_factory(actix_http::h1::OneRequest::new().map_err(|_| ())).and_then(
pipeline_factory(
pipeline_factory(VerifyWebSockets::default())
@@ -126,7 +126,7 @@ async fn test_service() {
let (item, mut framed) = framed.into_future().await;
assert_eq!(
item.unwrap().unwrap(),
ws::Frame::Text(Some(BytesMut::from("text")))
ws::Frame::Text(Bytes::from_static(b"text"))
);
framed
@@ -136,7 +136,7 @@ async fn test_service() {
let (item, mut framed) = framed.into_future().await;
assert_eq!(
item.unwrap().unwrap(),
ws::Frame::Binary(Some(BytesMut::from(&b"text"[..])))
ws::Frame::Binary(Bytes::from_static(b"text"))
);
framed.send(ws::Message::Ping("text".into())).await.unwrap();

View File

@@ -1,5 +1,45 @@
# Changes
## [1.0.1] - 2019-12-20
### Fixed
* Poll upgrade service's readiness from HTTP service handlers
* Replace brotli with brotli2 #1224
## [1.0.0] - 2019-12-13
### Added
* Add websockets continuation frame support
### Changed
* Replace `flate2-xxx` features with `compress`
## [1.0.0-alpha.5] - 2019-12-09
### Fixed
* Check `Upgrade` service readiness before calling it
* Fix buffer remaining capacity calcualtion
### Changed
* Websockets: Ping and Pong should have binary data #1049
## [1.0.0-alpha.4] - 2019-12-08
### Added
* Add impl ResponseBuilder for Error
### Changed
* Use rust based brotli compression library
## [1.0.0-alpha.3] - 2019-12-07
### Changed

View File

@@ -1,6 +1,6 @@
[package]
name = "actix-http"
version = "1.0.0-alpha.3"
version = "1.0.1"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix http primitives"
readme = "README.md"
@@ -13,10 +13,9 @@ categories = ["network-programming", "asynchronous",
"web-programming::websocket"]
license = "MIT/Apache-2.0"
edition = "2018"
workspace = ".."
[package.metadata.docs.rs]
features = ["openssl", "rustls", "fail", "brotli", "flate2-zlib", "secure-cookies"]
features = ["openssl", "rustls", "failure", "compress", "secure-cookies"]
[lib]
name = "actix_http"
@@ -31,45 +30,41 @@ openssl = ["actix-tls/openssl", "actix-connect/openssl"]
# rustls support
rustls = ["actix-tls/rustls", "actix-connect/rustls"]
# brotli encoding, requires c compiler
brotli = ["brotli2"]
# miniz-sys backend for flate2 crate
flate2-zlib = ["flate2/miniz-sys"]
# rust backend for flate2 crate
flate2-rust = ["flate2/rust_backend"]
# enable compressison support
compress = ["flate2", "brotli2"]
# failure integration. actix does not use failure anymore
fail = ["failure"]
failure = ["fail-ure"]
# support for secure cookies
secure-cookies = ["ring"]
[dependencies]
actix-service = "1.0.0-alpha.3"
actix-codec = "0.2.0-alpha.3"
actix-connect = "1.0.0-alpha.3"
actix-utils = "1.0.0-alpha.3"
actix-rt = "1.0.0-alpha.3"
actix-threadpool = "0.3.0"
actix-tls = { version = "1.0.0-alpha.3", optional = true }
actix-service = "1.0.0"
actix-codec = "0.2.0"
actix-connect = "1.0.1"
actix-utils = "1.0.3"
actix-rt = "1.0.0"
actix-threadpool = "0.3.1"
actix-tls = { version = "1.0.0", optional = true }
base64 = "0.11"
bitflags = "1.0"
bytes = "0.5.2"
bitflags = "1.2"
bytes = "0.5.3"
copyless = "0.1.4"
chrono = "0.4.6"
derive_more = "0.99.2"
either = "1.5.2"
either = "1.5.3"
encoding_rs = "0.8"
futures = "0.3.1"
futures-core = "0.3.1"
futures-util = "0.3.1"
futures-channel = "0.3.1"
fxhash = "0.2.1"
h2 = "0.2.1"
http = "0.2.0"
httparse = "1.3"
indexmap = "1.2"
lazy_static = "1.0"
indexmap = "1.3"
lazy_static = "1.4"
language-tags = "0.2"
log = "0.4"
mime = "0.3"
@@ -89,16 +84,17 @@ ring = { version = "0.16.9", optional = true }
# compression
brotli2 = { version="0.3.2", optional = true }
flate2 = { version="1.0.7", optional = true, default-features = false }
flate2 = { version = "1.0.13", optional = true }
# optional deps
failure = { version = "0.1.5", optional = true }
fail-ure = { version = "0.1.5", package="failure", optional = true }
[dev-dependencies]
actix-server = { version = "1.0.0-alpha.3" }
actix-connect = { version = "1.0.0-alpha.3", features=["openssl"] }
actix-http-test = { version = "1.0.0-alpha.3", features=["openssl"] }
actix-tls = { version = "1.0.0-alpha.3", features=["openssl"] }
actix-server = "1.0.0"
actix-connect = { version = "1.0.0", features=["openssl"] }
actix-http-test = { version = "1.0.0", features=["openssl"] }
actix-tls = { version = "1.0.0", features=["openssl"] }
futures = "0.3.1"
env_logger = "0.6"
serde_derive = "1.0"
open-ssl = { version="0.10", package = "openssl" }

View File

@@ -4,7 +4,7 @@ use std::task::{Context, Poll};
use std::{fmt, mem};
use bytes::{Bytes, BytesMut};
use futures::Stream;
use futures_core::Stream;
use pin_project::{pin_project, project};
use crate::error::Error;
@@ -35,7 +35,7 @@ impl BodySize {
pub trait MessageBody {
fn size(&self) -> BodySize;
fn poll_next(&mut self, cx: &mut Context) -> Poll<Option<Result<Bytes, Error>>>;
fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Bytes, Error>>>;
}
impl MessageBody for () {
@@ -43,7 +43,7 @@ impl MessageBody for () {
BodySize::Empty
}
fn poll_next(&mut self, _: &mut Context) -> Poll<Option<Result<Bytes, Error>>> {
fn poll_next(&mut self, _: &mut Context<'_>) -> Poll<Option<Result<Bytes, Error>>> {
Poll::Ready(None)
}
}
@@ -53,7 +53,7 @@ impl<T: MessageBody> MessageBody for Box<T> {
self.as_ref().size()
}
fn poll_next(&mut self, cx: &mut Context) -> Poll<Option<Result<Bytes, Error>>> {
fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Bytes, Error>>> {
self.as_mut().poll_next(cx)
}
}
@@ -97,7 +97,7 @@ impl<B: MessageBody> MessageBody for ResponseBody<B> {
}
}
fn poll_next(&mut self, cx: &mut Context) -> Poll<Option<Result<Bytes, Error>>> {
fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Bytes, Error>>> {
match self {
ResponseBody::Body(ref mut body) => body.poll_next(cx),
ResponseBody::Other(ref mut body) => body.poll_next(cx),
@@ -109,7 +109,10 @@ impl<B: MessageBody> Stream for ResponseBody<B> {
type Item = Result<Bytes, Error>;
#[project]
fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Self::Item>> {
#[project]
match self.project() {
ResponseBody::Body(ref mut body) => body.poll_next(cx),
@@ -152,7 +155,7 @@ impl MessageBody for Body {
}
}
fn poll_next(&mut self, cx: &mut Context) -> Poll<Option<Result<Bytes, Error>>> {
fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Bytes, Error>>> {
match self {
Body::None => Poll::Ready(None),
Body::Empty => Poll::Ready(None),
@@ -190,7 +193,7 @@ impl PartialEq for Body {
}
impl fmt::Debug for Body {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Body::None => write!(f, "Body::None"),
Body::Empty => write!(f, "Body::Empty"),
@@ -272,7 +275,7 @@ impl MessageBody for Bytes {
BodySize::Sized(self.len())
}
fn poll_next(&mut self, _: &mut Context) -> Poll<Option<Result<Bytes, Error>>> {
fn poll_next(&mut self, _: &mut Context<'_>) -> Poll<Option<Result<Bytes, Error>>> {
if self.is_empty() {
Poll::Ready(None)
} else {
@@ -286,7 +289,7 @@ impl MessageBody for BytesMut {
BodySize::Sized(self.len())
}
fn poll_next(&mut self, _: &mut Context) -> Poll<Option<Result<Bytes, Error>>> {
fn poll_next(&mut self, _: &mut Context<'_>) -> Poll<Option<Result<Bytes, Error>>> {
if self.is_empty() {
Poll::Ready(None)
} else {
@@ -300,7 +303,7 @@ impl MessageBody for &'static str {
BodySize::Sized(self.len())
}
fn poll_next(&mut self, _: &mut Context) -> Poll<Option<Result<Bytes, Error>>> {
fn poll_next(&mut self, _: &mut Context<'_>) -> Poll<Option<Result<Bytes, Error>>> {
if self.is_empty() {
Poll::Ready(None)
} else {
@@ -316,7 +319,7 @@ impl MessageBody for &'static [u8] {
BodySize::Sized(self.len())
}
fn poll_next(&mut self, _: &mut Context) -> Poll<Option<Result<Bytes, Error>>> {
fn poll_next(&mut self, _: &mut Context<'_>) -> Poll<Option<Result<Bytes, Error>>> {
if self.is_empty() {
Poll::Ready(None)
} else {
@@ -330,7 +333,7 @@ impl MessageBody for Vec<u8> {
BodySize::Sized(self.len())
}
fn poll_next(&mut self, _: &mut Context) -> Poll<Option<Result<Bytes, Error>>> {
fn poll_next(&mut self, _: &mut Context<'_>) -> Poll<Option<Result<Bytes, Error>>> {
if self.is_empty() {
Poll::Ready(None)
} else {
@@ -344,7 +347,7 @@ impl MessageBody for String {
BodySize::Sized(self.len())
}
fn poll_next(&mut self, _: &mut Context) -> Poll<Option<Result<Bytes, Error>>> {
fn poll_next(&mut self, _: &mut Context<'_>) -> Poll<Option<Result<Bytes, Error>>> {
if self.is_empty() {
Poll::Ready(None)
} else {
@@ -386,7 +389,7 @@ where
BodySize::Stream
}
fn poll_next(&mut self, cx: &mut Context) -> Poll<Option<Result<Bytes, Error>>> {
fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Bytes, Error>>> {
unsafe { Pin::new_unchecked(self) }
.project()
.stream
@@ -421,7 +424,7 @@ where
BodySize::Sized64(self.size)
}
fn poll_next(&mut self, cx: &mut Context) -> Poll<Option<Result<Bytes, Error>>> {
fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Bytes, Error>>> {
unsafe { Pin::new_unchecked(self) }
.project()
.stream
@@ -432,7 +435,7 @@ where
#[cfg(test)]
mod tests {
use super::*;
use futures::future::poll_fn;
use futures_util::future::poll_fn;
impl Body {
pub(crate) fn get_ref(&self) -> &[u8] {

View File

@@ -4,7 +4,7 @@ use std::{fmt, io, mem, time};
use actix_codec::{AsyncRead, AsyncWrite, Framed};
use bytes::{Buf, Bytes};
use futures::future::{err, Either, Future, FutureExt, LocalBoxFuture, Ready};
use futures_util::future::{err, Either, Future, FutureExt, LocalBoxFuture, Ready};
use h2::client::SendRequest;
use pin_project::{pin_project, project};
@@ -63,7 +63,7 @@ impl<T> fmt::Debug for IoConnection<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.io {
Some(ConnectionType::H1(ref io)) => write!(f, "H1Connection({:?})", io),
Some(ConnectionType::H2(_)) => write!(f, "H2Connection"),
@@ -247,7 +247,7 @@ where
#[project]
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
#[project]

View File

@@ -62,7 +62,7 @@ trait Io: AsyncRead + AsyncWrite + Unpin {}
impl<T: AsyncRead + AsyncWrite + Unpin> Io for T {}
impl Connector<(), ()> {
#[allow(clippy::new_ret_no_self)]
#[allow(clippy::new_ret_no_self, clippy::let_unit_value)]
pub fn new() -> Connector<
impl Service<
Request = TcpConnect<Uri>,
@@ -87,9 +87,9 @@ impl Connector<(), ()> {
let protos = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
let mut config = ClientConfig::new();
config.set_protocols(&protos);
config.root_store.add_server_trust_anchors(
&actix_connect::ssl::rustls::TLS_SERVER_ROOTS,
);
config
.root_store
.add_server_trust_anchors(&actix_tls::rustls::TLS_SERVER_ROOTS);
SslConnector::Rustls(Arc::new(config))
}
#[cfg(not(any(feature = "openssl", feature = "rustls")))]
@@ -337,7 +337,7 @@ where
mod connect_impl {
use std::task::{Context, Poll};
use futures::future::{err, Either, Ready};
use futures_util::future::{err, Either, Ready};
use super::*;
use crate::client::connection::IoConnection;
@@ -378,7 +378,7 @@ mod connect_impl {
Ready<Result<IoConnection<Io>, ConnectError>>,
>;
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.tcp_pool.poll_ready(cx)
}
@@ -400,8 +400,8 @@ mod connect_impl {
use std::pin::Pin;
use std::task::{Context, Poll};
use futures::future::Either;
use futures::ready;
use futures_core::ready;
use futures_util::future::Either;
use super::*;
use crate::client::connection::EitherConnection;
@@ -451,7 +451,7 @@ mod connect_impl {
InnerConnectorResponseB<T2, Io1, Io2>,
>;
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.tcp_pool.poll_ready(cx)
}
@@ -490,10 +490,10 @@ mod connect_impl {
{
type Output = Result<EitherConnection<Io1, Io2>, ConnectError>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Poll::Ready(
ready!(Pin::new(&mut self.get_mut().fut).poll(cx))
.map(|res| EitherConnection::A(res)),
.map(EitherConnection::A),
)
}
}
@@ -519,10 +519,10 @@ mod connect_impl {
{
type Output = Result<EitherConnection<Io1, Io2>, ConnectError>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Poll::Ready(
ready!(Pin::new(&mut self.get_mut().fut).poll(cx))
.map(|res| EitherConnection::B(res)),
.map(EitherConnection::B),
)
}
}

View File

@@ -6,8 +6,9 @@ use std::{io, mem, time};
use actix_codec::{AsyncRead, AsyncWrite, Framed};
use bytes::buf::BufMutExt;
use bytes::{Bytes, BytesMut};
use futures::future::poll_fn;
use futures::{SinkExt, Stream, StreamExt};
use futures_core::Stream;
use futures_util::future::poll_fn;
use futures_util::{SinkExt, StreamExt};
use crate::error::PayloadError;
use crate::h1;
@@ -234,7 +235,7 @@ impl<T: AsyncRead + AsyncWrite + Unpin + 'static> AsyncWrite for H1Connection<T>
fn poll_shutdown(
mut self: Pin<&mut Self>,
cx: &mut Context,
cx: &mut Context<'_>,
) -> Poll<Result<(), io::Error>> {
Pin::new(self.io.as_mut().unwrap()).poll_shutdown(cx)
}
@@ -255,7 +256,10 @@ impl<Io: ConnectionLifetime> PlStream<Io> {
impl<Io: ConnectionLifetime> Stream for PlStream<Io> {
type Item = Result<Bytes, PayloadError>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Self::Item>> {
let this = self.get_mut();
match this.framed.as_mut().unwrap().next_item(cx)? {

View File

@@ -3,7 +3,7 @@ use std::time;
use actix_codec::{AsyncRead, AsyncWrite};
use bytes::Bytes;
use futures::future::poll_fn;
use futures_util::future::poll_fn;
use h2::{client::SendRequest, SendStream};
use http::header::{HeaderValue, CONNECTION, CONTENT_LENGTH, TRANSFER_ENCODING};
use http::{request::Request, Method, Version};

View File

@@ -11,7 +11,7 @@ use actix_rt::time::{delay_for, Delay};
use actix_service::Service;
use actix_utils::{oneshot, task::LocalWaker};
use bytes::Bytes;
use futures::future::{poll_fn, FutureExt, LocalBoxFuture};
use futures_util::future::{poll_fn, FutureExt, LocalBoxFuture};
use fxhash::FxHashMap;
use h2::client::{handshake, Connection, SendRequest};
use http::uri::Authority;
@@ -93,7 +93,7 @@ where
type Error = ConnectError;
type Future = LocalBoxFuture<'static, Result<IoConnection<Io>, ConnectError>>;
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.0.poll_ready(cx)
}
@@ -308,7 +308,7 @@ where
(rx, token)
}
fn acquire(&mut self, key: &Key, cx: &mut Context) -> Acquire<Io> {
fn acquire(&mut self, key: &Key, cx: &mut Context<'_>) -> Acquire<Io> {
// check limits
if self.limit > 0 && self.acquired >= self.limit {
return Acquire::NotAvailable;
@@ -409,7 +409,7 @@ where
{
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> {
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
let this = self.get_mut();
match Pin::new(&mut this.timeout).poll(cx) {
@@ -438,7 +438,7 @@ where
{
type Output = ();
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 = unsafe { self.get_unchecked_mut() };
let mut inner = this.inner.as_ref().borrow_mut();
@@ -545,7 +545,7 @@ where
{
type Output = ();
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 = unsafe { self.get_unchecked_mut() };
if let Some(ref mut h2) = this.h2 {

View File

@@ -32,7 +32,7 @@ where
type Error = T::Error;
type Future = T::Future;
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
unsafe { &mut *self.0.as_ref().get() }.poll_ready(cx)
}

View File

@@ -6,7 +6,7 @@ use std::{fmt, net};
use actix_rt::time::{delay_for, delay_until, Delay, Instant};
use bytes::BytesMut;
use futures::{future, FutureExt};
use futures_util::{future, FutureExt};
use time;
// "Sun, 06 Nov 1994 08:49:37 GMT".len()

View File

@@ -18,7 +18,6 @@ use super::{Cookie, SameSite};
/// ```rust
/// use actix_http::cookie::Cookie;
///
/// # fn main() {
/// let cookie: Cookie = Cookie::build("name", "value")
/// .domain("www.rust-lang.org")
/// .path("/")
@@ -26,7 +25,6 @@ use super::{Cookie, SameSite};
/// .http_only(true)
/// .max_age(84600)
/// .finish();
/// # }
/// ```
#[derive(Debug, Clone)]
pub struct CookieBuilder {
@@ -65,13 +63,11 @@ impl CookieBuilder {
/// ```rust
/// use actix_http::cookie::Cookie;
///
/// # fn main() {
/// let c = Cookie::build("foo", "bar")
/// .expires(time::now())
/// .finish();
///
/// assert!(c.expires().is_some());
/// # }
/// ```
#[inline]
pub fn expires(mut self, when: Tm) -> CookieBuilder {
@@ -86,13 +82,11 @@ impl CookieBuilder {
/// ```rust
/// use actix_http::cookie::Cookie;
///
/// # fn main() {
/// let c = Cookie::build("foo", "bar")
/// .max_age(1800)
/// .finish();
///
/// assert_eq!(c.max_age(), Some(time::Duration::seconds(30 * 60)));
/// # }
/// ```
#[inline]
pub fn max_age(self, seconds: i64) -> CookieBuilder {
@@ -106,13 +100,11 @@ impl CookieBuilder {
/// ```rust
/// use actix_http::cookie::Cookie;
///
/// # fn main() {
/// let c = Cookie::build("foo", "bar")
/// .max_age_time(time::Duration::minutes(30))
/// .finish();
///
/// assert_eq!(c.max_age(), Some(time::Duration::seconds(30 * 60)));
/// # }
/// ```
#[inline]
pub fn max_age_time(mut self, value: Duration) -> CookieBuilder {
@@ -222,14 +214,12 @@ impl CookieBuilder {
/// use actix_http::cookie::Cookie;
/// use chrono::Duration;
///
/// # fn main() {
/// let c = Cookie::build("foo", "bar")
/// .permanent()
/// .finish();
///
/// assert_eq!(c.max_age(), Some(Duration::days(365 * 20)));
/// # assert!(c.expires().is_some());
/// # }
/// ```
#[inline]
pub fn permanent(mut self) -> CookieBuilder {

View File

@@ -88,7 +88,7 @@ impl SameSite {
}
impl fmt::Display for SameSite {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
SameSite::Strict => write!(f, "Strict"),
SameSite::Lax => write!(f, "Lax"),

View File

@@ -190,7 +190,6 @@ impl CookieJar {
/// use actix_http::cookie::{CookieJar, Cookie};
/// use chrono::Duration;
///
/// # fn main() {
/// let mut jar = CookieJar::new();
///
/// // Assume this cookie originally had a path of "/" and domain of "a.b".
@@ -204,7 +203,6 @@ impl CookieJar {
/// assert_eq!(delta.len(), 1);
/// assert_eq!(delta[0].name(), "name");
/// assert_eq!(delta[0].max_age(), Some(Duration::seconds(0)));
/// # }
/// ```
///
/// Removing a new cookie does not result in a _removal_ cookie:
@@ -243,7 +241,6 @@ impl CookieJar {
/// use actix_http::cookie::{CookieJar, Cookie};
/// use chrono::Duration;
///
/// # fn main() {
/// let mut jar = CookieJar::new();
///
/// // Add an original cookie and a new cookie.
@@ -261,7 +258,6 @@ impl CookieJar {
/// jar.force_remove(Cookie::new("key", "value"));
/// assert_eq!(jar.delta().count(), 0);
/// assert_eq!(jar.iter().count(), 0);
/// # }
/// ```
pub fn force_remove<'a>(&mut self, cookie: Cookie<'a>) {
self.original_cookies.remove(cookie.name());
@@ -307,7 +303,7 @@ impl CookieJar {
/// // Delta contains two new cookies ("new", "yac") and a removal ("name").
/// assert_eq!(jar.delta().count(), 3);
/// ```
pub fn delta(&self) -> Delta {
pub fn delta(&self) -> Delta<'_> {
Delta {
iter: self.delta_cookies.iter(),
}
@@ -343,7 +339,7 @@ impl CookieJar {
/// }
/// }
/// ```
pub fn iter(&self) -> Iter {
pub fn iter(&self) -> Iter<'_> {
Iter {
delta_cookies: self
.delta_cookies
@@ -386,7 +382,7 @@ impl CookieJar {
/// assert!(jar.get("private").is_some());
/// ```
#[cfg(feature = "secure-cookies")]
pub fn private(&mut self, key: &Key) -> PrivateJar {
pub fn private(&mut self, key: &Key) -> PrivateJar<'_> {
PrivateJar::new(self, key)
}
@@ -424,7 +420,7 @@ impl CookieJar {
/// assert!(jar.get("signed").is_some());
/// ```
#[cfg(feature = "secure-cookies")]
pub fn signed(&mut self, key: &Key) -> SignedJar {
pub fn signed(&mut self, key: &Key) -> SignedJar<'_> {
SignedJar::new(self, key)
}
}

View File

@@ -110,7 +110,7 @@ impl CookieStr {
/// # Panics
///
/// Panics if `self` is an indexed string and `string` is None.
fn to_str<'s>(&'s self, string: Option<&'s Cow<str>>) -> &'s str {
fn to_str<'s>(&'s self, string: Option<&'s Cow<'_, str>>) -> &'s str {
match *self {
CookieStr::Indexed(i, j) => {
let s = string.expect(
@@ -647,13 +647,11 @@ impl<'c> Cookie<'c> {
/// use actix_http::cookie::Cookie;
/// use chrono::Duration;
///
/// # fn main() {
/// let mut c = Cookie::new("name", "value");
/// assert_eq!(c.max_age(), None);
///
/// c.set_max_age(Duration::hours(10));
/// assert_eq!(c.max_age(), Some(Duration::hours(10)));
/// # }
/// ```
#[inline]
pub fn set_max_age(&mut self, value: Duration) {
@@ -701,7 +699,6 @@ impl<'c> Cookie<'c> {
/// ```rust
/// use actix_http::cookie::Cookie;
///
/// # fn main() {
/// let mut c = Cookie::new("name", "value");
/// assert_eq!(c.expires(), None);
///
@@ -710,7 +707,6 @@ impl<'c> Cookie<'c> {
///
/// c.set_expires(now);
/// assert!(c.expires().is_some())
/// # }
/// ```
#[inline]
pub fn set_expires(&mut self, time: Tm) {
@@ -726,7 +722,6 @@ impl<'c> Cookie<'c> {
/// use actix_http::cookie::Cookie;
/// use chrono::Duration;
///
/// # fn main() {
/// let mut c = Cookie::new("foo", "bar");
/// assert!(c.expires().is_none());
/// assert!(c.max_age().is_none());
@@ -734,7 +729,6 @@ impl<'c> Cookie<'c> {
/// c.make_permanent();
/// assert!(c.expires().is_some());
/// assert_eq!(c.max_age(), Some(Duration::days(365 * 20)));
/// # }
/// ```
pub fn make_permanent(&mut self) {
let twenty_years = Duration::days(365 * 20);
@@ -742,7 +736,7 @@ impl<'c> Cookie<'c> {
self.set_expires(time::now() + twenty_years);
}
fn fmt_parameters(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt_parameters(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(true) = self.http_only() {
write!(f, "; HttpOnly")?;
}
@@ -924,10 +918,10 @@ impl<'c> Cookie<'c> {
/// let mut c = Cookie::new("my name", "this; value?");
/// assert_eq!(&c.encoded().to_string(), "my%20name=this%3B%20value%3F");
/// ```
pub struct EncodedCookie<'a, 'c: 'a>(&'a Cookie<'c>);
pub struct EncodedCookie<'a, 'c>(&'a Cookie<'c>);
impl<'a, 'c: 'a> fmt::Display for EncodedCookie<'a, 'c> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Percent-encode the name and value.
let name = percent_encode(self.0.name().as_bytes(), USERINFO);
let value = percent_encode(self.0.value().as_bytes(), USERINFO);
@@ -952,7 +946,7 @@ impl<'c> fmt::Display for Cookie<'c> {
///
/// assert_eq!(&cookie.to_string(), "foo=bar; Path=/");
/// ```
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}={}", self.name(), self.value())?;
self.fmt_parameters(f)
}

View File

@@ -40,7 +40,7 @@ impl ParseError {
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
@@ -51,11 +51,7 @@ impl From<Utf8Error> for ParseError {
}
}
impl Error for ParseError {
fn description(&self) -> &str {
self.as_str()
}
}
impl Error for ParseError {}
fn indexes_of(needle: &str, haystack: &str) -> Option<(usize, usize)> {
let haystack_start = haystack.as_ptr() as usize;

View File

@@ -10,7 +10,7 @@ use crate::cookie::{Cookie, CookieJar};
// Keep these in sync, and keep the key len synced with the `private` docs as
// well as the `KEYS_INFO` const in secure::Key.
static ALGO: &'static Algorithm = &AES_256_GCM;
static ALGO: &Algorithm = &AES_256_GCM;
const NONCE_LEN: usize = 12;
pub const KEY_LEN: usize = 32;
@@ -159,7 +159,7 @@ Please change it as soon as possible."
/// Encrypts the cookie's value with
/// authenticated encryption assuring confidentiality, integrity, and authenticity.
fn encrypt_cookie(&self, cookie: &mut Cookie) {
fn encrypt_cookie(&self, cookie: &mut Cookie<'_>) {
let name = cookie.name().as_bytes();
let value = cookie.value().as_bytes();
let data = encrypt_name_value(name, value, &self.key);

View File

@@ -129,7 +129,7 @@ impl<'a> SignedJar<'a> {
}
/// Signs the cookie's value assuring integrity and authenticity.
fn sign_cookie(&self, cookie: &mut Cookie) {
fn sign_cookie(&self, cookie: &mut Cookie<'_>) {
let digest = sign(&self.key, cookie.value().as_bytes());
let mut new_value = base64::encode(digest.as_ref());
new_value.push_str(cookie.value());

View File

@@ -4,12 +4,10 @@ use std::pin::Pin;
use std::task::{Context, Poll};
use actix_threadpool::{run, CpuFuture};
#[cfg(feature = "brotli")]
use brotli2::write::BrotliDecoder;
use bytes::Bytes;
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
use flate2::write::{GzDecoder, ZlibDecoder};
use futures::{ready, Stream};
use futures_core::{ready, Stream};
use super::Writer;
use crate::error::PayloadError;
@@ -32,15 +30,12 @@ where
#[inline]
pub fn new(stream: S, encoding: ContentEncoding) -> Decoder<S> {
let decoder = match encoding {
#[cfg(feature = "brotli")]
ContentEncoding::Br => Some(ContentDecoder::Br(Box::new(
BrotliDecoder::new(Writer::new()),
))),
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
ContentEncoding::Deflate => Some(ContentDecoder::Deflate(Box::new(
ZlibDecoder::new(Writer::new()),
))),
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
ContentEncoding::Gzip => Some(ContentDecoder::Gzip(Box::new(
GzDecoder::new(Writer::new()),
))),
@@ -80,7 +75,7 @@ where
fn poll_next(
mut self: Pin<&mut Self>,
cx: &mut Context,
cx: &mut Context<'_>,
) -> Poll<Option<Self::Item>> {
loop {
if let Some(ref mut fut) = self.fut {
@@ -140,22 +135,17 @@ where
}
enum ContentDecoder {
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
Deflate(Box<ZlibDecoder<Writer>>),
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
Gzip(Box<GzDecoder<Writer>>),
#[cfg(feature = "brotli")]
Br(Box<BrotliDecoder<Writer>>),
}
impl ContentDecoder {
#[allow(unreachable_patterns)]
fn feed_eof(&mut self) -> io::Result<Option<Bytes>> {
match self {
#[cfg(feature = "brotli")]
ContentDecoder::Br(ref mut decoder) => match decoder.finish() {
Ok(mut writer) => {
let b = writer.take();
ContentDecoder::Br(ref mut decoder) => match decoder.flush() {
Ok(()) => {
let b = decoder.get_mut().take();
if !b.is_empty() {
Ok(Some(b))
} else {
@@ -164,7 +154,6 @@ impl ContentDecoder {
}
Err(e) => Err(e),
},
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
ContentDecoder::Gzip(ref mut decoder) => match decoder.try_finish() {
Ok(_) => {
let b = decoder.get_mut().take();
@@ -176,7 +165,6 @@ impl ContentDecoder {
}
Err(e) => Err(e),
},
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
ContentDecoder::Deflate(ref mut decoder) => match decoder.try_finish() {
Ok(_) => {
let b = decoder.get_mut().take();
@@ -188,14 +176,11 @@ impl ContentDecoder {
}
Err(e) => Err(e),
},
_ => Ok(None),
}
}
#[allow(unreachable_patterns)]
fn feed_data(&mut self, data: Bytes) -> io::Result<Option<Bytes>> {
match self {
#[cfg(feature = "brotli")]
ContentDecoder::Br(ref mut decoder) => match decoder.write_all(&data) {
Ok(_) => {
decoder.flush()?;
@@ -208,7 +193,6 @@ impl ContentDecoder {
}
Err(e) => Err(e),
},
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
ContentDecoder::Gzip(ref mut decoder) => match decoder.write_all(&data) {
Ok(_) => {
decoder.flush()?;
@@ -221,7 +205,6 @@ impl ContentDecoder {
}
Err(e) => Err(e),
},
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
ContentDecoder::Deflate(ref mut decoder) => match decoder.write_all(&data) {
Ok(_) => {
decoder.flush()?;
@@ -234,7 +217,6 @@ impl ContentDecoder {
}
Err(e) => Err(e),
},
_ => Ok(Some(data)),
}
}
}

View File

@@ -5,11 +5,10 @@ use std::pin::Pin;
use std::task::{Context, Poll};
use actix_threadpool::{run, CpuFuture};
#[cfg(feature = "brotli")]
use brotli2::write::BrotliEncoder;
use bytes::Bytes;
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
use flate2::write::{GzEncoder, ZlibEncoder};
use futures_core::ready;
use crate::body::{Body, BodySize, MessageBody, ResponseBody};
use crate::http::header::{ContentEncoding, CONTENT_ENCODING};
@@ -18,7 +17,7 @@ use crate::{Error, ResponseHead};
use super::Writer;
const INPLACE: usize = 2049;
const INPLACE: usize = 1024;
pub struct Encoder<B> {
eof: bool,
@@ -96,14 +95,14 @@ impl<B: MessageBody> MessageBody for Encoder<B> {
}
}
fn poll_next(&mut self, cx: &mut Context) -> Poll<Option<Result<Bytes, Error>>> {
fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Bytes, Error>>> {
loop {
if self.eof {
return Poll::Ready(None);
}
if let Some(ref mut fut) = self.fut {
let mut encoder = match futures::ready!(Pin::new(fut).poll(cx)) {
let mut encoder = match ready!(Pin::new(fut).poll(cx)) {
Ok(item) => item,
Err(e) => return Poll::Ready(Some(Err(e.into()))),
};
@@ -173,28 +172,22 @@ fn update_head(encoding: ContentEncoding, head: &mut ResponseHead) {
}
enum ContentEncoder {
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
Deflate(ZlibEncoder<Writer>),
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
Gzip(GzEncoder<Writer>),
#[cfg(feature = "brotli")]
Br(BrotliEncoder<Writer>),
}
impl ContentEncoder {
fn encoder(encoding: ContentEncoding) -> Option<Self> {
match encoding {
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
ContentEncoding::Deflate => Some(ContentEncoder::Deflate(ZlibEncoder::new(
Writer::new(),
flate2::Compression::fast(),
))),
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
ContentEncoding::Gzip => Some(ContentEncoder::Gzip(GzEncoder::new(
Writer::new(),
flate2::Compression::fast(),
))),
#[cfg(feature = "brotli")]
ContentEncoding::Br => {
Some(ContentEncoder::Br(BrotliEncoder::new(Writer::new(), 3)))
}
@@ -205,28 +198,22 @@ impl ContentEncoder {
#[inline]
pub(crate) fn take(&mut self) -> Bytes {
match *self {
#[cfg(feature = "brotli")]
ContentEncoder::Br(ref mut encoder) => encoder.get_mut().take(),
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
ContentEncoder::Deflate(ref mut encoder) => encoder.get_mut().take(),
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
ContentEncoder::Gzip(ref mut encoder) => encoder.get_mut().take(),
}
}
fn finish(self) -> Result<Bytes, io::Error> {
match self {
#[cfg(feature = "brotli")]
ContentEncoder::Br(encoder) => match encoder.finish() {
Ok(writer) => Ok(writer.buf.freeze()),
Err(err) => Err(err),
},
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
ContentEncoder::Gzip(encoder) => match encoder.finish() {
Ok(writer) => Ok(writer.buf.freeze()),
Err(err) => Err(err),
},
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
ContentEncoder::Deflate(encoder) => match encoder.finish() {
Ok(writer) => Ok(writer.buf.freeze()),
Err(err) => Err(err),
@@ -236,7 +223,6 @@ impl ContentEncoder {
fn write(&mut self, data: &[u8]) -> Result<(), io::Error> {
match *self {
#[cfg(feature = "brotli")]
ContentEncoder::Br(ref mut encoder) => match encoder.write_all(data) {
Ok(_) => Ok(()),
Err(err) => {
@@ -244,7 +230,6 @@ impl ContentEncoder {
Err(err)
}
},
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
ContentEncoder::Gzip(ref mut encoder) => match encoder.write_all(data) {
Ok(_) => Ok(()),
Err(err) => {
@@ -252,7 +237,6 @@ impl ContentEncoder {
Err(err)
}
},
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
ContentEncoder::Deflate(ref mut encoder) => match encoder.write_all(data) {
Ok(_) => Ok(()),
Err(err) => {

View File

@@ -19,6 +19,7 @@ impl Writer {
buf: BytesMut::with_capacity(8192),
}
}
fn take(&mut self) -> Bytes {
self.buf.split().freeze()
}
@@ -29,6 +30,7 @@ impl io::Write for Writer {
self.buf.extend_from_slice(buf);
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}

View File

@@ -6,11 +6,13 @@ use std::str::Utf8Error;
use std::string::FromUtf8Error;
use std::{fmt, io, result};
use actix_codec::{Decoder, Encoder};
pub use actix_threadpool::BlockingError;
use actix_utils::framed::DispatcherError as FramedDispatcherError;
use actix_utils::timeout::TimeoutError;
use bytes::BytesMut;
use derive_more::{Display, From};
pub use futures::channel::oneshot::Canceled;
pub use futures_channel::oneshot::Canceled;
use http::uri::InvalidUri;
use http::{header, Error as HttpError, StatusCode};
use httparse;
@@ -22,7 +24,7 @@ use serde_urlencoded::ser::Error as FormError;
use crate::body::Body;
pub use crate::cookie::ParseError as CookieParseError;
use crate::helpers::Writer;
use crate::response::Response;
use crate::response::{Response, ResponseBuilder};
/// A specialized [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html)
/// for actix web operations
@@ -102,22 +104,18 @@ impl dyn ResponseError + 'static {
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.cause, f)
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "{:?}", &self.cause)
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", &self.cause)
}
}
impl std::error::Error for Error {
fn description(&self) -> &str {
"actix-http::Error"
}
fn cause(&self) -> Option<&dyn std::error::Error> {
None
}
@@ -157,6 +155,20 @@ impl<T: ResponseError + 'static> From<T> for Error {
}
}
/// Convert Response to a Error
impl From<Response> for Error {
fn from(res: Response) -> Error {
InternalError::from_response("", res).into()
}
}
/// Convert ResponseBuilder to a Error
impl From<ResponseBuilder> for Error {
fn from(mut res: ResponseBuilder) -> Error {
InternalError::from_response("", res.finish()).into()
}
}
/// Return `GATEWAY_TIMEOUT` for `TimeoutError`
impl<E: ResponseError> ResponseError for TimeoutError<E> {
fn status_code(&self) -> StatusCode {
@@ -453,6 +465,14 @@ impl ResponseError for ContentTypeError {
}
}
impl<E, U: Encoder + Decoder> ResponseError for FramedDispatcherError<E, U>
where
E: fmt::Debug + fmt::Display,
<U as Encoder>::Error: fmt::Debug,
<U as Decoder>::Error: fmt::Debug,
{
}
/// Helper type that can wrap any error and generate custom response.
///
/// In following example any `io::Error` will be converted into "BAD REQUEST"
@@ -460,14 +480,12 @@ impl ResponseError for ContentTypeError {
/// default.
///
/// ```rust
/// # extern crate actix_http;
/// # use std::io;
/// # use actix_http::*;
///
/// fn index(req: Request) -> Result<&'static str> {
/// Err(error::ErrorBadRequest(io::Error::new(io::ErrorKind::Other, "error")))
/// }
/// # fn main() {}
/// ```
pub struct InternalError<T> {
cause: T,
@@ -501,7 +519,7 @@ impl<T> fmt::Debug for InternalError<T>
where
T: fmt::Debug + 'static,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.cause, f)
}
}
@@ -510,7 +528,7 @@ impl<T> fmt::Display for InternalError<T>
where
T: fmt::Display + 'static,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.cause, f)
}
}
@@ -555,13 +573,6 @@ where
}
}
/// Convert Response to a Error
impl From<Response> for Error {
fn from(res: Response) -> Error {
InternalError::from_response("", res).into()
}
}
/// Helper function that creates wrapper of any error and generate *BAD
/// REQUEST* response.
#[allow(non_snake_case)]
@@ -952,20 +963,15 @@ where
InternalError::new(err, StatusCode::NETWORK_AUTHENTICATION_REQUIRED).into()
}
#[cfg(feature = "fail")]
mod failure_integration {
use super::*;
/// Compatibility for `failure::Error`
impl ResponseError for failure::Error {}
}
#[cfg(feature = "failure")]
/// Compatibility for `failure::Error`
impl ResponseError for fail_ure::Error {}
#[cfg(test)]
mod tests {
use super::*;
use http::{Error as HttpError, StatusCode};
use httparse;
use std::error::Error as StdError;
use std::io;
#[test]
@@ -994,7 +1000,7 @@ mod tests {
#[test]
fn test_error_cause() {
let orig = io::Error::new(io::ErrorKind::Other, "other");
let desc = orig.description().to_owned();
let desc = orig.to_string();
let e = Error::from(orig);
assert_eq!(format!("{}", e.as_response_error()), desc);
}
@@ -1002,7 +1008,7 @@ mod tests {
#[test]
fn test_error_display() {
let orig = io::Error::new(io::ErrorKind::Other, "other");
let desc = orig.description().to_owned();
let desc = orig.to_string();
let e = Error::from(orig);
assert_eq!(format!("{}", e), desc);
}
@@ -1044,7 +1050,7 @@ mod tests {
match ParseError::from($from) {
e @ $error => {
let desc = format!("{}", e);
assert_eq!(desc, format!("IO error: {}", $from.description()));
assert_eq!(desc, format!("IO error: {}", $from));
}
_ => unreachable!("{:?}", $from),
}

View File

@@ -65,7 +65,7 @@ impl Extensions {
}
impl fmt::Debug for Extensions {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Extensions").finish()
}
}

View File

@@ -1,13 +1,8 @@
#![allow(unused_imports, unused_variables, dead_code)]
use std::io::{self, Write};
use std::rc::Rc;
use std::io;
use actix_codec::{Decoder, Encoder};
use bitflags::bitflags;
use bytes::{BufMut, Bytes, BytesMut};
use http::header::{
HeaderValue, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING, UPGRADE,
};
use bytes::{Bytes, BytesMut};
use http::{Method, Version};
use super::decoder::{PayloadDecoder, PayloadItem, PayloadType};
@@ -16,11 +11,7 @@ use super::{Message, MessageType};
use crate::body::BodySize;
use crate::config::ServiceConfig;
use crate::error::{ParseError, PayloadError};
use crate::header::HeaderMap;
use crate::helpers;
use crate::message::{
ConnectionType, Head, MessagePool, RequestHead, RequestHeadType, ResponseHead,
};
use crate::message::{ConnectionType, RequestHeadType, ResponseHead};
bitflags! {
struct Flags: u8 {
@@ -30,8 +21,6 @@ bitflags! {
}
}
const AVERAGE_HEADER_SIZE: usize = 30;
/// HTTP/1 Codec
pub struct ClientCodec {
inner: ClientCodecInner,
@@ -51,7 +40,6 @@ struct ClientCodecInner {
// encoder part
flags: Flags,
headers_size: u32,
encoder: encoder::MessageEncoder<RequestHeadType>,
}
@@ -80,7 +68,6 @@ impl ClientCodec {
ctype: ConnectionType::Close,
flags,
headers_size: 0,
encoder: encoder::MessageEncoder::default(),
},
}

View File

@@ -1,12 +1,9 @@
#![allow(unused_imports, unused_variables, dead_code)]
use std::io::Write;
use std::{fmt, io, net};
use std::{fmt, io};
use actix_codec::{Decoder, Encoder};
use bitflags::bitflags;
use bytes::{BufMut, Bytes, BytesMut};
use http::header::{HeaderValue, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING};
use http::{Method, StatusCode, Version};
use bytes::BytesMut;
use http::{Method, Version};
use super::decoder::{PayloadDecoder, PayloadItem, PayloadType};
use super::{decoder, encoder};
@@ -14,8 +11,7 @@ use super::{Message, MessageType};
use crate::body::BodySize;
use crate::config::ServiceConfig;
use crate::error::ParseError;
use crate::helpers;
use crate::message::{ConnectionType, Head, ResponseHead};
use crate::message::ConnectionType;
use crate::request::Request;
use crate::response::Response;
@@ -27,8 +23,6 @@ bitflags! {
}
}
const AVERAGE_HEADER_SIZE: usize = 30;
/// HTTP/1 Codec
pub struct Codec {
config: ServiceConfig,
@@ -49,7 +43,7 @@ impl Default for Codec {
}
impl fmt::Debug for Codec {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "h1::Codec({:?})", self.flags)
}
}
@@ -176,7 +170,6 @@ impl Encoder for Codec {
};
// encode message
let len = dst.len();
self.encoder.encode(
dst,
&mut res,
@@ -202,17 +195,11 @@ impl Encoder for Codec {
#[cfg(test)]
mod tests {
use std::{cmp, io};
use actix_codec::{AsyncRead, AsyncWrite};
use bytes::{Buf, Bytes, BytesMut};
use http::{Method, Version};
use bytes::BytesMut;
use http::Method;
use super::*;
use crate::error::ParseError;
use crate::h1::Message;
use crate::httpmessage::HttpMessage;
use crate::request::Request;
#[test]
fn test_http_request_chunked_payload_and_next_message() {

View File

@@ -5,7 +5,7 @@ use std::mem::MaybeUninit;
use std::task::Poll;
use actix_codec::Decoder;
use bytes::{Bytes, BytesMut};
use bytes::{Buf, Bytes, BytesMut};
use http::header::{HeaderName, HeaderValue};
use http::{header, Method, StatusCode, Uri, Version};
use httparse;
@@ -185,6 +185,7 @@ impl MessageType for Request {
&mut self.head_mut().headers
}
#[allow(clippy::uninit_assumed_init)]
fn decode(src: &mut BytesMut) -> Result<Option<(Self, PayloadType)>, ParseError> {
// Unsafe: we read only this data only after httparse parses headers into.
// performance bump for pipeline benchmarks.
@@ -192,7 +193,7 @@ impl MessageType for Request {
unsafe { MaybeUninit::uninit().assume_init() };
let (len, method, uri, ver, h_len) = {
let mut parsed: [httparse::Header; MAX_HEADERS] =
let mut parsed: [httparse::Header<'_>; MAX_HEADERS] =
unsafe { MaybeUninit::uninit().assume_init() };
let mut req = httparse::Request::new(&mut parsed);
@@ -260,6 +261,7 @@ impl MessageType for ResponseHead {
&mut self.headers
}
#[allow(clippy::uninit_assumed_init)]
fn decode(src: &mut BytesMut) -> Result<Option<(Self, PayloadType)>, ParseError> {
// Unsafe: we read only this data only after httparse parses headers into.
// performance bump for pipeline benchmarks.
@@ -267,7 +269,7 @@ impl MessageType for ResponseHead {
unsafe { MaybeUninit::uninit().assume_init() };
let (len, ver, status, h_len) = {
let mut parsed: [httparse::Header; MAX_HEADERS] =
let mut parsed: [httparse::Header<'_>; MAX_HEADERS] =
unsafe { MaybeUninit::uninit().assume_init() };
let mut res = httparse::Response::new(&mut parsed);
@@ -326,7 +328,7 @@ pub(crate) struct HeaderIndex {
impl HeaderIndex {
pub(crate) fn record(
bytes: &[u8],
headers: &[httparse::Header],
headers: &[httparse::Header<'_>],
indices: &mut [HeaderIndex],
) {
let bytes_ptr = bytes.as_ptr() as usize;
@@ -475,7 +477,7 @@ macro_rules! byte (
($rdr:ident) => ({
if $rdr.len() > 0 {
let b = $rdr[0];
$rdr.split_to(1);
$rdr.advance(1);
b
} else {
return Poll::Pending

View File

@@ -8,7 +8,7 @@ use actix_codec::{AsyncRead, AsyncWrite, Decoder, Encoder, Framed, FramedParts};
use actix_rt::time::{delay_until, Delay, Instant};
use actix_service::Service;
use bitflags::bitflags;
use bytes::{BufMut, BytesMut};
use bytes::{Buf, BytesMut};
use log::{error, trace};
use crate::body::{Body, BodySize, MessageBody, ResponseBody};
@@ -264,7 +264,7 @@ where
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display,
{
fn can_read(&self, cx: &mut Context) -> bool {
fn can_read(&self, cx: &mut Context<'_>) -> bool {
if self
.flags
.intersects(Flags::READ_DISCONNECT | Flags::UPGRADE)
@@ -290,7 +290,7 @@ where
///
/// true - got whouldblock
/// false - didnt get whouldblock
fn poll_flush(&mut self, cx: &mut Context) -> Result<bool, DispatchError> {
fn poll_flush(&mut self, cx: &mut Context<'_>) -> Result<bool, DispatchError> {
if self.write_buf.is_empty() {
return Ok(false);
}
@@ -312,7 +312,7 @@ where
}
Poll::Pending => {
if written > 0 {
let _ = self.write_buf.split_to(written);
self.write_buf.advance(written);
}
return Ok(true);
}
@@ -322,7 +322,7 @@ where
if written == self.write_buf.len() {
unsafe { self.write_buf.set_len(0) }
} else {
let _ = self.write_buf.split_to(written);
self.write_buf.advance(written);
}
Ok(false)
}
@@ -355,7 +355,7 @@ where
fn poll_response(
&mut self,
cx: &mut Context,
cx: &mut Context<'_>,
) -> Result<PollResponse, DispatchError> {
loop {
let state = match self.state {
@@ -459,7 +459,7 @@ where
fn handle_request(
&mut self,
req: Request,
cx: &mut Context,
cx: &mut Context<'_>,
) -> Result<State<S, B, X>, DispatchError> {
// Handle `EXPECT: 100-Continue` header
let req = if req.head().expect() {
@@ -500,7 +500,7 @@ where
/// Process one incoming requests
pub(self) fn poll_request(
&mut self,
cx: &mut Context,
cx: &mut Context<'_>,
) -> Result<bool, DispatchError> {
// limit a mount of non processed requests
if self.messages.len() >= MAX_PIPELINED_MESSAGES || !self.can_read(cx) {
@@ -604,7 +604,7 @@ where
}
/// keep-alive timer
fn poll_keepalive(&mut self, cx: &mut Context) -> Result<(), DispatchError> {
fn poll_keepalive(&mut self, cx: &mut Context<'_>) -> Result<(), DispatchError> {
if self.ka_timer.is_none() {
// shutdown timeout
if self.flags.contains(Flags::SHUTDOWN) {
@@ -710,7 +710,7 @@ where
type Output = Result<(), DispatchError>;
#[inline]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.as_mut().inner {
DispatcherState::Normal(ref mut inner) => {
inner.poll_keepalive(cx)?;
@@ -750,8 +750,10 @@ where
};
loop {
if inner.write_buf.remaining_mut() < LW_BUFFER_SIZE {
inner.write_buf.reserve(HW_BUFFER_SIZE);
let remaining =
inner.write_buf.capacity() - inner.write_buf.len();
if remaining < LW_BUFFER_SIZE {
inner.write_buf.reserve(HW_BUFFER_SIZE - remaining);
}
let result = inner.poll_response(cx)?;
let drain = result == PollResponse::DrainWriteBuf;
@@ -832,7 +834,7 @@ where
}
fn read_available<T>(
cx: &mut Context,
cx: &mut Context<'_>,
io: &mut T,
buf: &mut BytesMut,
) -> Result<Option<bool>, io::Error>
@@ -841,8 +843,9 @@ where
{
let mut read_some = false;
loop {
if buf.remaining_mut() < LW_BUFFER_SIZE {
buf.reserve(HW_BUFFER_SIZE);
let remaining = buf.capacity() - buf.len();
if remaining < LW_BUFFER_SIZE {
buf.reserve(HW_BUFFER_SIZE - remaining);
}
match read(cx, io, buf) {
@@ -874,7 +877,7 @@ where
}
fn read<T>(
cx: &mut Context,
cx: &mut Context<'_>,
io: &mut T,
buf: &mut BytesMut,
) -> Poll<Result<usize, io::Error>>
@@ -887,7 +890,7 @@ where
#[cfg(test)]
mod tests {
use actix_service::IntoService;
use futures::future::{lazy, ok};
use futures_util::future::{lazy, ok};
use super::*;
use crate::error::Error;

View File

@@ -1,25 +1,18 @@
#![allow(unused_imports, unused_variables, dead_code)]
use std::fmt::Write as FmtWrite;
use std::io::Write;
use std::marker::PhantomData;
use std::ptr::copy_nonoverlapping;
use std::rc::Rc;
use std::slice::from_raw_parts_mut;
use std::str::FromStr;
use std::{cmp, fmt, io, mem};
use std::{cmp, io};
use bytes::{buf::BufMutExt, BufMut, Bytes, BytesMut};
use bytes::{buf::BufMutExt, BufMut, BytesMut};
use crate::body::BodySize;
use crate::config::ServiceConfig;
use crate::header::{map, ContentEncoding};
use crate::header::map;
use crate::helpers;
use crate::http::header::{
HeaderValue, ACCEPT_ENCODING, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING,
};
use crate::http::{HeaderMap, Method, StatusCode, Version};
use crate::message::{ConnectionType, Head, RequestHead, RequestHeadType, ResponseHead};
use crate::request::Request;
use crate::http::header::{CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING};
use crate::http::{HeaderMap, StatusCode, Version};
use crate::message::{ConnectionType, RequestHeadType};
use crate::response::Response;
const AVERAGE_HEADER_SIZE: usize = 30;
@@ -108,6 +101,7 @@ pub(crate) trait MessageType: Sized {
} else {
dst.put_slice(b"\r\ncontent-length: ");
}
#[allow(clippy::write_with_newline)]
write!(dst.writer(), "{}\r\n", len)?;
}
BodySize::None => dst.put_slice(b"\r\n"),
@@ -527,12 +521,14 @@ fn write_camel_case(value: &[u8], buffer: &mut [u8]) {
#[cfg(test)]
mod tests {
use std::rc::Rc;
use bytes::Bytes;
//use std::rc::Rc;
use http::header::AUTHORIZATION;
use super::*;
use crate::http::header::{HeaderValue, CONTENT_TYPE};
use http::header::AUTHORIZATION;
use crate::RequestHead;
#[test]
fn test_chunked_te() {

View File

@@ -1,7 +1,7 @@
use std::task::{Context, Poll};
use actix_service::{Service, ServiceFactory};
use futures::future::{ok, Ready};
use futures_util::future::{ok, Ready};
use crate::error::Error;
use crate::request::Request;
@@ -28,7 +28,7 @@ impl Service for ExpectHandler {
type Error = Error;
type Future = Ready<Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}

View File

@@ -7,7 +7,7 @@ use std::task::{Context, Poll};
use actix_utils::task::LocalWaker;
use bytes::Bytes;
use futures::Stream;
use futures_core::Stream;
use crate::error::PayloadError;
@@ -82,7 +82,7 @@ impl Payload {
#[inline]
pub fn readany(
&mut self,
cx: &mut Context,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Bytes, PayloadError>>> {
self.inner.borrow_mut().readany(cx)
}
@@ -93,7 +93,7 @@ impl Stream for Payload {
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Bytes, PayloadError>>> {
self.inner.borrow_mut().readany(cx)
}
@@ -127,7 +127,7 @@ impl PayloadSender {
}
#[inline]
pub fn need_read(&self, cx: &mut Context) -> PayloadStatus {
pub fn need_read(&self, cx: &mut Context<'_>) -> PayloadStatus {
// we check need_read only if Payload (other side) is alive,
// otherwise always return true (consume payload)
if let Some(shared) = self.inner.upgrade() {
@@ -194,7 +194,7 @@ impl Inner {
fn readany(
&mut self,
cx: &mut Context,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Bytes, PayloadError>>> {
if let Some(data) = self.items.pop_front() {
self.len -= data.len();
@@ -226,7 +226,7 @@ impl Inner {
#[cfg(test)]
mod tests {
use super::*;
use futures::future::poll_fn;
use futures_util::future::poll_fn;
#[actix_rt::test]
async fn test_unread_data() {

View File

@@ -8,8 +8,8 @@ use std::{fmt, net};
use actix_codec::{AsyncRead, AsyncWrite, Framed};
use actix_rt::net::TcpStream;
use actix_service::{pipeline_factory, IntoServiceFactory, Service, ServiceFactory};
use futures::future::{ok, Ready};
use futures::ready;
use futures_core::ready;
use futures_util::future::{ok, Ready};
use crate::body::MessageBody;
use crate::cloneable::CloneableService;
@@ -72,7 +72,7 @@ where
Request = (Request, Framed<TcpStream, Codec>),
Response = (),
>,
U::Error: fmt::Display,
U::Error: fmt::Display + Into<Error>,
U::InitError: fmt::Debug,
{
/// Create simple tcp stream service
@@ -115,7 +115,7 @@ mod openssl {
Request = (Request, Framed<SslStream<TcpStream>, Codec>),
Response = (),
>,
U::Error: fmt::Display,
U::Error: fmt::Display + Into<Error>,
U::InitError: fmt::Debug,
{
/// Create openssl based service
@@ -165,7 +165,7 @@ mod rustls {
Request = (Request, Framed<TlsStream<TcpStream>, Codec>),
Response = (),
>,
U::Error: fmt::Display,
U::Error: fmt::Display + Into<Error>,
U::InitError: fmt::Debug,
{
/// Create rustls based service
@@ -255,7 +255,7 @@ where
X::Error: Into<Error>,
X::InitError: fmt::Debug,
U: ServiceFactory<Config = (), Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display,
U::Error: fmt::Display + Into<Error>,
U::InitError: fmt::Debug,
{
type Config = ();
@@ -324,7 +324,7 @@ where
{
type Output = Result<H1ServiceHandler<T, S::Service, B, X::Service, U::Service>, ()>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut this = self.as_mut().project();
if let Some(fut) = this.fut_ex.as_pin_mut() {
@@ -412,14 +412,14 @@ where
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display,
U::Error: fmt::Display + Into<Error>,
{
type Request = (T, Option<net::SocketAddr>);
type Response = ();
type Error = DispatchError;
type Future = Dispatcher<T, S, B, X, U>;
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
let ready = self
.expect
.poll_ready(cx)
@@ -441,6 +441,19 @@ where
.is_ready()
&& ready;
let ready = if let Some(ref mut upg) = self.upgrade {
upg.poll_ready(cx)
.map_err(|e| {
let e = e.into();
log::error!("Http service readiness error: {:?}", e);
DispatchError::Service(e)
})?
.is_ready()
&& ready
} else {
ready
};
if ready {
Poll::Ready(Ok(()))
} else {
@@ -523,7 +536,7 @@ where
type Error = ParseError;
type Future = OneRequestServiceResponse<T>;
fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
@@ -548,7 +561,7 @@ where
{
type Output = Result<(Request, Framed<T, Codec>), ParseError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.framed.as_mut().unwrap().next_item(cx) {
Poll::Ready(Some(Ok(req))) => match req {
Message::Item(req) => {

View File

@@ -3,7 +3,7 @@ use std::task::{Context, Poll};
use actix_codec::Framed;
use actix_service::{Service, ServiceFactory};
use futures::future::Ready;
use futures_util::future::Ready;
use crate::error::Error;
use crate::h1::Codec;
@@ -31,7 +31,7 @@ impl<T> Service for UpgradeHandler<T> {
type Error = Error;
type Future = Ready<Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}

View File

@@ -39,7 +39,7 @@ where
{
type Output = Result<Framed<T, Codec>, 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.get_mut();
loop {

View File

@@ -1,28 +1,23 @@
use std::collections::VecDeque;
use std::convert::TryFrom;
use std::future::Future;
use std::marker::PhantomData;
use std::net;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::{fmt, mem, net};
use actix_codec::{AsyncRead, AsyncWrite};
use actix_rt::time::{Delay, Instant};
use actix_service::Service;
use bitflags::bitflags;
use bytes::{Bytes, BytesMut};
use futures::{ready, Sink, Stream};
use h2::server::{Connection, SendResponse};
use h2::{RecvStream, SendStream};
use http::header::{
HeaderValue, ACCEPT_ENCODING, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING,
};
use log::{debug, error, trace};
use h2::SendStream;
use http::header::{HeaderValue, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING};
use log::{error, trace};
use crate::body::{Body, BodySize, MessageBody, ResponseBody};
use crate::body::{BodySize, MessageBody, ResponseBody};
use crate::cloneable::CloneableService;
use crate::config::ServiceConfig;
use crate::error::{DispatchError, Error, ParseError, PayloadError, ResponseError};
use crate::error::{DispatchError, Error};
use crate::helpers::DataFactory;
use crate::httpmessage::HttpMessage;
use crate::message::ResponseHead;
@@ -106,7 +101,7 @@ where
type Output = Result<(), DispatchError>;
#[inline]
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.get_mut();
loop {
@@ -252,7 +247,7 @@ where
{
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut this = self.as_mut().project();
match this.state {

View File

@@ -1,11 +1,9 @@
#![allow(dead_code, unused_imports)]
use std::fmt;
use std::future::Future;
//! HTTP/2 implementation
use std::pin::Pin;
use std::task::{Context, Poll};
use bytes::Bytes;
use futures::Stream;
use futures_core::Stream;
use h2::RecvStream;
mod dispatcher;
@@ -29,7 +27,10 @@ impl Payload {
impl Stream for Payload {
type Item = Result<Bytes, PayloadError>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Self::Item>> {
let this = self.get_mut();
match Pin::new(&mut this.pl).poll_data(cx) {

View File

@@ -1,32 +1,28 @@
use std::fmt::Debug;
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::{io, net, rc};
use std::{net, rc};
use actix_codec::{AsyncRead, AsyncWrite, Framed};
use actix_codec::{AsyncRead, AsyncWrite};
use actix_rt::net::TcpStream;
use actix_service::{
factory_fn, pipeline_factory, service_fn2, IntoServiceFactory, Service,
fn_factory, fn_service, pipeline_factory, IntoServiceFactory, Service,
ServiceFactory,
};
use bytes::Bytes;
use futures::future::{ok, Ready};
use futures::{ready, Stream};
use h2::server::{self, Connection, Handshake};
use h2::RecvStream;
use futures_core::ready;
use futures_util::future::ok;
use h2::server::{self, Handshake};
use log::error;
use crate::body::MessageBody;
use crate::cloneable::CloneableService;
use crate::config::{KeepAlive, ServiceConfig};
use crate::error::{DispatchError, Error, ParseError, ResponseError};
use crate::config::ServiceConfig;
use crate::error::{DispatchError, Error};
use crate::helpers::DataFactory;
use crate::payload::Payload;
use crate::request::Request;
use crate::response::Response;
use crate::Protocol;
use super::dispatcher::Dispatcher;
@@ -87,9 +83,9 @@ where
Error = DispatchError,
InitError = S::InitError,
> {
pipeline_factory(factory_fn(|| {
pipeline_factory(fn_factory(|| {
async {
Ok::<_, S::InitError>(service_fn2(|io: TcpStream| {
Ok::<_, S::InitError>(fn_service(|io: TcpStream| {
let peer_addr = io.peer_addr().ok();
ok::<_, DispatchError>((io, peer_addr))
}))
@@ -101,7 +97,7 @@ where
#[cfg(feature = "openssl")]
mod openssl {
use actix_service::{factory_fn, service_fn2};
use actix_service::{fn_factory, fn_service};
use actix_tls::openssl::{Acceptor, SslAcceptor, SslStream};
use actix_tls::{openssl::HandshakeError, SslError};
@@ -131,8 +127,8 @@ mod openssl {
.map_err(SslError::Ssl)
.map_init_err(|_| panic!()),
)
.and_then(factory_fn(|| {
ok::<_, S::InitError>(service_fn2(|io: SslStream<TcpStream>| {
.and_then(fn_factory(|| {
ok::<_, S::InitError>(fn_service(|io: SslStream<TcpStream>| {
let peer_addr = io.get_ref().peer_addr().ok();
ok((io, peer_addr))
}))
@@ -145,9 +141,9 @@ mod openssl {
#[cfg(feature = "rustls")]
mod rustls {
use super::*;
use actix_tls::rustls::{Acceptor, ServerConfig, Session, TlsStream};
use actix_tls::rustls::{Acceptor, ServerConfig, TlsStream};
use actix_tls::SslError;
use std::{fmt, io};
use std::io;
impl<S, B> H2Service<TlsStream<TcpStream>, S, B>
where
@@ -176,8 +172,8 @@ mod rustls {
.map_err(SslError::Ssl)
.map_init_err(|_| panic!()),
)
.and_then(factory_fn(|| {
ok::<_, S::InitError>(service_fn2(|io: TlsStream<TcpStream>| {
.and_then(fn_factory(|| {
ok::<_, S::InitError>(fn_service(|io: TlsStream<TcpStream>| {
let peer_addr = io.get_ref().0.peer_addr().ok();
ok((io, peer_addr))
}))
@@ -235,7 +231,7 @@ where
{
type Output = Result<H2ServiceHandler<T, S::Service, B>, S::InitError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.as_mut().project();
Poll::Ready(ready!(this.fut.poll(cx)).map(|service| {
@@ -293,7 +289,7 @@ where
type Error = DispatchError;
type Future = H2ServiceHandlerResponse<T, S, B>;
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.srv.poll_ready(cx).map_err(|e| {
let e = e.into();
error!("Service readiness error: {:?}", e);
@@ -358,7 +354,7 @@ where
{
type Output = Result<(), DispatchError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.state {
State::Incoming(ref mut disp) => Pin::new(disp).poll(cx),
State::Handshake(

View File

@@ -74,7 +74,7 @@ impl Header for CacheControl {
}
impl fmt::Display for CacheControl {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt_comma_delimited(f, &self[..])
}
}
@@ -126,7 +126,7 @@ pub enum CacheDirective {
}
impl fmt::Display for CacheDirective {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use self::CacheDirective::*;
fmt::Display::fmt(
match *self {

View File

@@ -486,7 +486,7 @@ impl Header for ContentDisposition {
}
impl fmt::Display for DispositionType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DispositionType::Inline => write!(f, "inline"),
DispositionType::Attachment => write!(f, "attachment"),
@@ -497,7 +497,7 @@ impl fmt::Display for DispositionType {
}
impl fmt::Display for DispositionParam {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// All ASCII control characters (0-30, 127) including horizontal tab, double quote, and
// backslash should be escaped in quoted-string (i.e. "foobar").
// Ref: RFC6266 S4.1 -> RFC2616 S3.6
@@ -555,7 +555,7 @@ impl fmt::Display for DispositionParam {
}
impl fmt::Display for ContentDisposition {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.disposition)?;
self.parameters
.iter()

View File

@@ -166,7 +166,7 @@ impl FromStr for ContentRangeSpec {
}
impl Display for ContentRangeSpec {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
ContentRangeSpec::Bytes {
range,

View File

@@ -87,7 +87,7 @@ impl Header for IfRange {
}
impl Display for IfRange {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
IfRange::EntityTag(ref x) => Display::fmt(x, f),
IfRange::Date(ref x) => Display::fmt(x, f),

View File

@@ -159,7 +159,7 @@ macro_rules! header {
}
impl std::fmt::Display for $id {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter) -> ::std::fmt::Result {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> ::std::fmt::Result {
$crate::http::header::fmt_comma_delimited(f, &self.0[..])
}
}
@@ -195,7 +195,7 @@ macro_rules! header {
}
impl std::fmt::Display for $id {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
$crate::http::header::fmt_comma_delimited(f, &self.0[..])
}
}
@@ -231,7 +231,7 @@ macro_rules! header {
}
impl std::fmt::Display for $id {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, f)
}
}
@@ -276,7 +276,7 @@ macro_rules! header {
}
impl std::fmt::Display for $id {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match *self {
$id::Any => f.write_str("*"),
$id::Items(ref fields) => $crate::http::header::fmt_comma_delimited(

View File

@@ -143,7 +143,7 @@ impl HeaderMap {
/// Returns `None` if there are no values associated with the key.
///
/// [`GetAll`]: struct.GetAll.html
pub fn get_all<N: AsName>(&self, name: N) -> GetAll {
pub fn get_all<N: AsName>(&self, name: N) -> GetAll<'_> {
GetAll {
idx: 0,
item: self.get2(name),
@@ -187,7 +187,7 @@ impl HeaderMap {
/// The iteration order is arbitrary, but consistent across platforms for
/// the same crate version. Each key will be yielded once per associated
/// value. So, if a key has 3 associated values, it will be yielded 3 times.
pub fn iter(&self) -> Iter {
pub fn iter(&self) -> Iter<'_> {
Iter::new(self.inner.iter())
}
@@ -196,7 +196,7 @@ impl HeaderMap {
/// The iteration order is arbitrary, but consistent across platforms for
/// the same crate version. Each key will be yielded only once even if it
/// has multiple associated values.
pub fn keys(&self) -> Keys {
pub fn keys(&self) -> Keys<'_> {
Keys(self.inner.keys())
}

View File

@@ -217,7 +217,7 @@ impl fmt::Write for Writer {
}
#[inline]
fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result {
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
fmt::write(self, args)
}
}
@@ -259,7 +259,7 @@ pub fn from_one_raw_str<T: FromStr>(val: Option<&HeaderValue>) -> Result<T, Pars
#[inline]
#[doc(hidden)]
/// Format an array into a comma-delimited string.
pub fn fmt_comma_delimited<T>(f: &mut fmt::Formatter, parts: &[T]) -> fmt::Result
pub fn fmt_comma_delimited<T>(f: &mut fmt::Formatter<'_>, parts: &[T]) -> fmt::Result
where
T: fmt::Display,
{
@@ -361,7 +361,7 @@ pub fn parse_extended_value(
}
impl fmt::Display for ExtendedValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let encoded_value =
percent_encoding::percent_encode(&self.value[..], HTTP_VALUE);
if let Some(ref lang) = self.language_tag {
@@ -376,7 +376,7 @@ impl fmt::Display for ExtendedValue {
/// [https://tools.ietf.org/html/rfc5987#section-3.2][url]
///
/// [url]: https://tools.ietf.org/html/rfc5987#section-3.2
pub fn http_percent_encode(f: &mut fmt::Formatter, bytes: &[u8]) -> fmt::Result {
pub fn http_percent_encode(f: &mut fmt::Formatter<'_>, bytes: &[u8]) -> fmt::Result {
let encoded = percent_encoding::percent_encode(bytes, HTTP_VALUE);
fmt::Display::fmt(&encoded, f)
}

View File

@@ -98,7 +98,7 @@ impl Charset {
}
impl Display for Charset {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.label())
}
}

View File

@@ -27,7 +27,7 @@ pub enum Encoding {
}
impl fmt::Display for Encoding {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match *self {
Chunked => "chunked",
Brotli => "br",

View File

@@ -113,7 +113,7 @@ impl EntityTag {
}
impl Display for EntityTag {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.weak {
write!(f, "W/\"{}\"", self.tag)
} else {

View File

@@ -28,7 +28,7 @@ impl FromStr for HttpDate {
}
impl Display for HttpDate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0.to_utc().rfc822(), f)
}
}

View File

@@ -53,7 +53,7 @@ impl<T: PartialEq> cmp::PartialOrd for QualityItem<T> {
}
impl<T: fmt::Display> fmt::Display for QualityItem<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.item, f)?;
match self.quality.0 {
1000 => Ok(()),

View File

@@ -25,10 +25,10 @@ pub trait HttpMessage: Sized {
fn take_payload(&mut self) -> Payload<Self::Stream>;
/// Request's extensions container
fn extensions(&self) -> Ref<Extensions>;
fn extensions(&self) -> Ref<'_, Extensions>;
/// Mutable reference to a the request's extensions container
fn extensions_mut(&self) -> RefMut<Extensions>;
fn extensions_mut(&self) -> RefMut<'_, Extensions>;
#[doc(hidden)]
/// Get a header
@@ -105,7 +105,7 @@ pub trait HttpMessage: Sized {
/// Load request cookies.
#[inline]
fn cookies(&self) -> Result<Ref<Vec<Cookie<'static>>>, CookieParseError> {
fn cookies(&self) -> Result<Ref<'_, Vec<Cookie<'static>>>, CookieParseError> {
if self.extensions().get::<Cookies>().is_none() {
let mut cookies = Vec::new();
for hdr in self.headers().get_all(header::COOKIE) {
@@ -153,12 +153,12 @@ where
}
/// Request's extensions container
fn extensions(&self) -> Ref<Extensions> {
fn extensions(&self) -> Ref<'_, Extensions> {
(**self).extensions()
}
/// Mutable reference to a the request's extensions container
fn extensions_mut(&self) -> RefMut<Extensions> {
fn extensions_mut(&self) -> RefMut<'_, Extensions> {
(**self).extensions_mut()
}
}

View File

@@ -1,10 +1,10 @@
//! Basic http primitives for actix-net framework.
#![deny(rust_2018_idioms, warnings)]
#![allow(
clippy::type_complexity,
clippy::too_many_arguments,
clippy::new_without_default,
clippy::borrow_interior_mutable_const,
clippy::write_with_newline
clippy::borrow_interior_mutable_const
)]
#[macro_use]
@@ -15,6 +15,7 @@ mod builder;
pub mod client;
mod cloneable;
mod config;
#[cfg(feature = "compress")]
pub mod encoding;
mod extensions;
mod header;

View File

@@ -78,13 +78,13 @@ impl Head for RequestHead {
impl RequestHead {
/// Message extensions
#[inline]
pub fn extensions(&self) -> Ref<Extensions> {
pub fn extensions(&self) -> Ref<'_, Extensions> {
self.extensions.borrow()
}
/// Mutable reference to a the message's extensions
#[inline]
pub fn extensions_mut(&self) -> RefMut<Extensions> {
pub fn extensions_mut(&self) -> RefMut<'_, Extensions> {
self.extensions.borrow_mut()
}
@@ -237,13 +237,13 @@ impl ResponseHead {
/// Message extensions
#[inline]
pub fn extensions(&self) -> Ref<Extensions> {
pub fn extensions(&self) -> Ref<'_, Extensions> {
self.extensions.borrow()
}
/// Mutable reference to a the message's extensions
#[inline]
pub fn extensions_mut(&self) -> RefMut<Extensions> {
pub fn extensions_mut(&self) -> RefMut<'_, Extensions> {
self.extensions.borrow_mut()
}

View File

@@ -2,7 +2,7 @@ use std::pin::Pin;
use std::task::{Context, Poll};
use bytes::Bytes;
use futures::Stream;
use futures_core::Stream;
use h2::RecvStream;
use crate::error::PayloadError;
@@ -56,7 +56,10 @@ where
type Item = Result<Bytes, PayloadError>;
#[inline]
fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Self::Item>> {
match self.get_mut() {
Payload::None => Poll::Ready(None),
Payload::H1(ref mut pl) => pl.readany(cx),

View File

@@ -25,13 +25,13 @@ impl<P> HttpMessage for Request<P> {
/// Request extensions
#[inline]
fn extensions(&self) -> Ref<Extensions> {
fn extensions(&self) -> Ref<'_, Extensions> {
self.head.extensions()
}
/// Mutable reference to a the request's extensions
#[inline]
fn extensions_mut(&self) -> RefMut<Extensions> {
fn extensions_mut(&self) -> RefMut<'_, Extensions> {
self.head.extensions_mut()
}
@@ -165,7 +165,7 @@ impl<P> Request<P> {
}
impl<P> fmt::Debug for Request<P> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(
f,
"\nRequest {:?} {}:{}",

View File

@@ -7,7 +7,7 @@ use std::task::{Context, Poll};
use std::{fmt, str};
use bytes::{Bytes, BytesMut};
use futures::stream::Stream;
use futures_core::Stream;
use serde::Serialize;
use serde_json;
@@ -130,7 +130,7 @@ impl<B> Response<B> {
/// Get an iterator for the cookies set by this response
#[inline]
pub fn cookies(&self) -> CookieIter {
pub fn cookies(&self) -> CookieIter<'_> {
CookieIter {
iter: self.head.headers.get_all(header::SET_COOKIE),
}
@@ -138,7 +138,7 @@ impl<B> Response<B> {
/// Add a cookie to this response
#[inline]
pub fn add_cookie(&mut self, cookie: &Cookie) -> Result<(), HttpError> {
pub fn add_cookie(&mut self, cookie: &Cookie<'_>) -> Result<(), HttpError> {
let h = &mut self.head.headers;
HeaderValue::from_str(&cookie.to_string())
.map(|c| {
@@ -186,13 +186,13 @@ impl<B> Response<B> {
/// Responses extensions
#[inline]
pub fn extensions(&self) -> Ref<Extensions> {
pub fn extensions(&self) -> Ref<'_, Extensions> {
self.head.extensions.borrow()
}
/// Mutable reference to a the response's extensions
#[inline]
pub fn extensions_mut(&mut self) -> RefMut<Extensions> {
pub fn extensions_mut(&mut self) -> RefMut<'_, Extensions> {
self.head.extensions.borrow_mut()
}
@@ -265,7 +265,7 @@ impl<B> Response<B> {
}
impl<B: MessageBody> fmt::Debug for Response<B> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let res = writeln!(
f,
"\nResponse {:?} {}{}",
@@ -285,7 +285,7 @@ impl<B: MessageBody> fmt::Debug for Response<B> {
impl Future for Response {
type Output = Result<Response, 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> {
Poll::Ready(Ok(Response {
head: self.head.take(),
body: self.body.take_body(),
@@ -354,7 +354,6 @@ impl ResponseBuilder {
/// ))
/// .finish())
/// }
/// fn main() {}
/// ```
#[doc(hidden)]
pub fn set<H: Header>(&mut self, hdr: H) -> &mut Self {
@@ -380,7 +379,6 @@ impl ResponseBuilder {
/// .header(http::header::CONTENT_TYPE, "application/json")
/// .finish()
/// }
/// fn main() {}
/// ```
pub fn header<K, V>(&mut self, key: K, value: V) -> &mut Self
where
@@ -413,7 +411,6 @@ impl ResponseBuilder {
/// .set_header(http::header::CONTENT_TYPE, "application/json")
/// .finish()
/// }
/// fn main() {}
/// ```
pub fn set_header<K, V>(&mut self, key: K, value: V) -> &mut Self
where
@@ -588,14 +585,14 @@ impl ResponseBuilder {
/// Responses extensions
#[inline]
pub fn extensions(&self) -> Ref<Extensions> {
pub fn extensions(&self) -> Ref<'_, Extensions> {
let head = self.head.as_ref().expect("cannot reuse response builder");
head.extensions.borrow()
}
/// Mutable reference to a the response's extensions
#[inline]
pub fn extensions_mut(&mut self) -> RefMut<Extensions> {
pub fn extensions_mut(&mut self) -> RefMut<'_, Extensions> {
let head = self.head.as_ref().expect("cannot reuse response builder");
head.extensions.borrow_mut()
}
@@ -765,13 +762,13 @@ impl<'a> From<&'a ResponseHead> for ResponseBuilder {
impl Future for ResponseBuilder {
type Output = Result<Response, 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> {
Poll::Ready(Ok(self.finish()))
}
}
impl fmt::Debug for ResponseBuilder {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let head = self.head.as_ref().unwrap();
let res = writeln!(

View File

@@ -7,7 +7,8 @@ use actix_codec::{AsyncRead, AsyncWrite, Framed};
use actix_rt::net::TcpStream;
use actix_service::{pipeline_factory, IntoServiceFactory, Service, ServiceFactory};
use bytes::Bytes;
use futures::{future::ok, ready, Future};
use futures_core::{ready, Future};
use futures_util::future::ok;
use h2::server::{self, Handshake};
use pin_project::{pin_project, project};
@@ -168,7 +169,7 @@ where
Request = (Request, Framed<TcpStream, h1::Codec>),
Response = (),
>,
U::Error: fmt::Display,
U::Error: fmt::Display + Into<Error>,
U::InitError: fmt::Debug,
<U::Service as Service>::Future: 'static,
{
@@ -213,7 +214,7 @@ mod openssl {
Request = (Request, Framed<SslStream<TcpStream>, h1::Codec>),
Response = (),
>,
U::Error: fmt::Display,
U::Error: fmt::Display + Into<Error>,
U::InitError: fmt::Debug,
<U::Service as Service>::Future: 'static,
{
@@ -275,7 +276,7 @@ mod rustls {
Request = (Request, Framed<TlsStream<TcpStream>, h1::Codec>),
Response = (),
>,
U::Error: fmt::Display,
U::Error: fmt::Display + Into<Error>,
U::InitError: fmt::Debug,
<U::Service as Service>::Future: 'static,
{
@@ -334,7 +335,7 @@ where
Request = (Request, Framed<T, h1::Codec>),
Response = (),
>,
U::Error: fmt::Display,
U::Error: fmt::Display + Into<Error>,
U::InitError: fmt::Debug,
<U::Service as Service>::Future: 'static,
{
@@ -403,7 +404,7 @@ where
type Output =
Result<HttpServiceHandler<T, S::Service, B, X::Service, U::Service>, ()>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut this = self.as_mut().project();
if let Some(fut) = this.fut_ex.as_pin_mut() {
@@ -492,14 +493,14 @@ where
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
U: Service<Request = (Request, Framed<T, h1::Codec>), Response = ()>,
U::Error: fmt::Display,
U::Error: fmt::Display + Into<Error>,
{
type Request = (T, Protocol, Option<net::SocketAddr>);
type Response = ();
type Error = DispatchError;
type Future = HttpServiceHandlerResponse<T, S, B, X, U>;
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
let ready = self
.expect
.poll_ready(cx)
@@ -521,6 +522,19 @@ where
.is_ready()
&& ready;
let ready = if let Some(ref mut upg) = self.upgrade {
upg.poll_ready(cx)
.map_err(|e| {
let e = e.into();
log::error!("Http service readiness error: {:?}", e);
DispatchError::Service(e)
})?
.is_ready()
&& ready
} else {
ready
};
if ready {
Poll::Ready(Ok(()))
} else {
@@ -619,7 +633,7 @@ where
{
type Output = Result<(), DispatchError>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.project().state.poll(cx)
}
}
@@ -639,7 +653,7 @@ where
#[project]
fn poll(
mut self: Pin<&mut Self>,
cx: &mut Context,
cx: &mut Context<'_>,
) -> Poll<Result<(), DispatchError>> {
#[project]
match self.as_mut().project() {

View File

@@ -21,8 +21,6 @@ use crate::Request;
/// Test `Request` builder
///
/// ```rust,ignore
/// # extern crate http;
/// # extern crate actix_web;
/// # use http::{header, StatusCode};
/// # use actix_web::*;
/// use actix_web::test::TestRequest;
@@ -35,15 +33,13 @@ use crate::Request;
/// }
/// }
///
/// fn main() {
/// let resp = TestRequest::with_header("content-type", "text/plain")
/// .run(&index)
/// .unwrap();
/// assert_eq!(resp.status(), StatusCode::OK);
/// let resp = TestRequest::with_header("content-type", "text/plain")
/// .run(&index)
/// .unwrap();
/// assert_eq!(resp.status(), StatusCode::OK);
///
/// let resp = TestRequest::default().run(&index).unwrap();
/// assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
/// }
/// let resp = TestRequest::default().run(&index).unwrap();
/// assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
/// ```
pub struct TestRequest(Option<Inner>);

View File

@@ -12,10 +12,12 @@ pub enum Message {
Text(String),
/// Binary message
Binary(Bytes),
/// Continuation
Continuation(Item),
/// Ping message
Ping(String),
Ping(Bytes),
/// Pong message
Pong(String),
Pong(Bytes),
/// Close message with optional reason
Close(Option<CloseReason>),
/// No-op. Useful for actix-net services
@@ -26,22 +28,41 @@ pub enum Message {
#[derive(Debug, PartialEq)]
pub enum Frame {
/// Text frame, codec does not verify utf8 encoding
Text(Option<BytesMut>),
Text(Bytes),
/// Binary frame
Binary(Option<BytesMut>),
Binary(Bytes),
/// Continuation
Continuation(Item),
/// Ping message
Ping(String),
Ping(Bytes),
/// Pong message
Pong(String),
Pong(Bytes),
/// Close message with optional reason
Close(Option<CloseReason>),
}
/// `WebSocket` continuation item
#[derive(Debug, PartialEq)]
pub enum Item {
FirstText(Bytes),
FirstBinary(Bytes),
Continue(Bytes),
Last(Bytes),
}
#[derive(Debug, Copy, Clone)]
/// WebSockets protocol codec
pub struct Codec {
flags: Flags,
max_size: usize,
server: bool,
}
bitflags::bitflags! {
struct Flags: u8 {
const SERVER = 0b0000_0001;
const CONTINUATION = 0b0000_0010;
const W_CONTINUATION = 0b0000_0100;
}
}
impl Codec {
@@ -49,7 +70,7 @@ impl Codec {
pub fn new() -> Codec {
Codec {
max_size: 65_536,
server: true,
flags: Flags::SERVER,
}
}
@@ -65,7 +86,7 @@ impl Codec {
///
/// By default decoder works in server mode.
pub fn client_mode(mut self) -> Self {
self.server = false;
self.flags.remove(Flags::SERVER);
self
}
}
@@ -76,19 +97,94 @@ impl Encoder for Codec {
fn encode(&mut self, item: Message, dst: &mut BytesMut) -> Result<(), Self::Error> {
match item {
Message::Text(txt) => {
Parser::write_message(dst, txt, OpCode::Text, true, !self.server)
Message::Text(txt) => Parser::write_message(
dst,
txt,
OpCode::Text,
true,
!self.flags.contains(Flags::SERVER),
),
Message::Binary(bin) => Parser::write_message(
dst,
bin,
OpCode::Binary,
true,
!self.flags.contains(Flags::SERVER),
),
Message::Ping(txt) => Parser::write_message(
dst,
txt,
OpCode::Ping,
true,
!self.flags.contains(Flags::SERVER),
),
Message::Pong(txt) => Parser::write_message(
dst,
txt,
OpCode::Pong,
true,
!self.flags.contains(Flags::SERVER),
),
Message::Close(reason) => {
Parser::write_close(dst, reason, !self.flags.contains(Flags::SERVER))
}
Message::Binary(bin) => {
Parser::write_message(dst, bin, OpCode::Binary, true, !self.server)
}
Message::Ping(txt) => {
Parser::write_message(dst, txt, OpCode::Ping, true, !self.server)
}
Message::Pong(txt) => {
Parser::write_message(dst, txt, OpCode::Pong, true, !self.server)
}
Message::Close(reason) => Parser::write_close(dst, reason, !self.server),
Message::Continuation(cont) => match cont {
Item::FirstText(data) => {
if self.flags.contains(Flags::W_CONTINUATION) {
return Err(ProtocolError::ContinuationStarted);
} else {
self.flags.insert(Flags::W_CONTINUATION);
Parser::write_message(
dst,
&data[..],
OpCode::Binary,
false,
!self.flags.contains(Flags::SERVER),
)
}
}
Item::FirstBinary(data) => {
if self.flags.contains(Flags::W_CONTINUATION) {
return Err(ProtocolError::ContinuationStarted);
} else {
self.flags.insert(Flags::W_CONTINUATION);
Parser::write_message(
dst,
&data[..],
OpCode::Text,
false,
!self.flags.contains(Flags::SERVER),
)
}
}
Item::Continue(data) => {
if self.flags.contains(Flags::W_CONTINUATION) {
Parser::write_message(
dst,
&data[..],
OpCode::Continue,
false,
!self.flags.contains(Flags::SERVER),
)
} else {
return Err(ProtocolError::ContinuationNotStarted);
}
}
Item::Last(data) => {
if self.flags.contains(Flags::W_CONTINUATION) {
self.flags.remove(Flags::W_CONTINUATION);
Parser::write_message(
dst,
&data[..],
OpCode::Continue,
true,
!self.flags.contains(Flags::SERVER),
)
} else {
return Err(ProtocolError::ContinuationNotStarted);
}
}
},
Message::Nop => (),
}
Ok(())
@@ -100,15 +196,64 @@ impl Decoder for Codec {
type Error = ProtocolError;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
match Parser::parse(src, self.server, self.max_size) {
match Parser::parse(src, self.flags.contains(Flags::SERVER), self.max_size) {
Ok(Some((finished, opcode, payload))) => {
// continuation is not supported
if !finished {
return Err(ProtocolError::NoContinuation);
return match opcode {
OpCode::Continue => {
if self.flags.contains(Flags::CONTINUATION) {
Ok(Some(Frame::Continuation(Item::Continue(
payload
.map(|pl| pl.freeze())
.unwrap_or_else(Bytes::new),
))))
} else {
Err(ProtocolError::ContinuationNotStarted)
}
}
OpCode::Binary => {
if !self.flags.contains(Flags::CONTINUATION) {
self.flags.insert(Flags::CONTINUATION);
Ok(Some(Frame::Continuation(Item::FirstBinary(
payload
.map(|pl| pl.freeze())
.unwrap_or_else(Bytes::new),
))))
} else {
Err(ProtocolError::ContinuationStarted)
}
}
OpCode::Text => {
if !self.flags.contains(Flags::CONTINUATION) {
self.flags.insert(Flags::CONTINUATION);
Ok(Some(Frame::Continuation(Item::FirstText(
payload
.map(|pl| pl.freeze())
.unwrap_or_else(Bytes::new),
))))
} else {
Err(ProtocolError::ContinuationStarted)
}
}
_ => {
error!("Unfinished fragment {:?}", opcode);
Err(ProtocolError::ContinuationFragment(opcode))
}
};
}
match opcode {
OpCode::Continue => Err(ProtocolError::NoContinuation),
OpCode::Continue => {
if self.flags.contains(Flags::CONTINUATION) {
self.flags.remove(Flags::CONTINUATION);
Ok(Some(Frame::Continuation(Item::Last(
payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
))))
} else {
Err(ProtocolError::ContinuationNotStarted)
}
}
OpCode::Bad => Err(ProtocolError::BadOpCode),
OpCode::Close => {
if let Some(ref pl) = payload {
@@ -118,29 +263,18 @@ impl Decoder for Codec {
Ok(Some(Frame::Close(None)))
}
}
OpCode::Ping => {
if let Some(ref pl) = payload {
Ok(Some(Frame::Ping(String::from_utf8_lossy(pl).into())))
} else {
Ok(Some(Frame::Ping(String::new())))
}
}
OpCode::Pong => {
if let Some(ref pl) = payload {
Ok(Some(Frame::Pong(String::from_utf8_lossy(pl).into())))
} else {
Ok(Some(Frame::Pong(String::new())))
}
}
OpCode::Binary => Ok(Some(Frame::Binary(payload))),
OpCode::Text => {
Ok(Some(Frame::Text(payload)))
//let tmp = Vec::from(payload.as_ref());
//match String::from_utf8(tmp) {
// Ok(s) => Ok(Some(Message::Text(s))),
// Err(_) => Err(ProtocolError::BadEncoding),
//}
}
OpCode::Ping => Ok(Some(Frame::Ping(
payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
))),
OpCode::Pong => Ok(Some(Frame::Pong(
payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
))),
OpCode::Binary => Ok(Some(Frame::Binary(
payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
))),
OpCode::Text => Ok(Some(Frame::Text(
payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
))),
}
}
Ok(None) => Ok(None),

View File

@@ -4,19 +4,19 @@ use std::task::{Context, Poll};
use actix_codec::{AsyncRead, AsyncWrite, Framed};
use actix_service::{IntoService, Service};
use actix_utils::framed::{FramedTransport, FramedTransportError};
use actix_utils::framed;
use super::{Codec, Frame, Message};
pub struct Transport<S, T>
pub struct Dispatcher<S, T>
where
S: Service<Request = Frame, Response = Message> + 'static,
T: AsyncRead + AsyncWrite,
{
inner: FramedTransport<S, T, Codec>,
inner: framed::Dispatcher<S, T, Codec>,
}
impl<S, T> Transport<S, T>
impl<S, T> Dispatcher<S, T>
where
T: AsyncRead + AsyncWrite,
S: Service<Request = Frame, Response = Message>,
@@ -24,28 +24,28 @@ where
S::Error: 'static,
{
pub fn new<F: IntoService<S>>(io: T, service: F) -> Self {
Transport {
inner: FramedTransport::new(Framed::new(io, Codec::new()), service),
Dispatcher {
inner: framed::Dispatcher::new(Framed::new(io, Codec::new()), service),
}
}
pub fn with<F: IntoService<S>>(framed: Framed<T, Codec>, service: F) -> Self {
Transport {
inner: FramedTransport::new(framed, service),
Dispatcher {
inner: framed::Dispatcher::new(framed, service),
}
}
}
impl<S, T> Future for Transport<S, T>
impl<S, T> Future for Dispatcher<S, T>
where
T: AsyncRead + AsyncWrite,
S: Service<Request = Frame, Response = Message>,
S::Future: 'static,
S::Error: 'static,
{
type Output = Result<(), FramedTransportError<S::Error, Codec>>;
type Output = Result<(), framed::DispatcherError<S::Error, Codec>>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Pin::new(&mut self.inner).poll(cx)
}
}

View File

@@ -1,6 +1,6 @@
use std::convert::TryFrom;
use bytes::{BufMut, Bytes, BytesMut};
use bytes::{Buf, BufMut, BytesMut};
use log::debug;
use rand;
@@ -108,7 +108,7 @@ impl Parser {
}
// remove prefix
src.split_to(idx);
src.advance(idx);
// no need for body
if length == 0 {
@@ -154,14 +154,14 @@ impl Parser {
}
/// Generate binary representation
pub fn write_message<B: Into<Bytes>>(
pub fn write_message<B: AsRef<[u8]>>(
dst: &mut BytesMut,
pl: B,
op: OpCode,
fin: bool,
mask: bool,
) {
let payload = pl.into();
let payload = pl.as_ref();
let one: u8 = if fin {
0x80 | Into::<u8>::into(op)
} else {

View File

@@ -51,7 +51,7 @@ pub(crate) fn apply_mask(buf: &mut [u8], mask_u32: u32) {
// inefficient, it could be done better. The compiler does not understand that
// a `ShortSlice` must be smaller than a u64.
#[allow(clippy::needless_pass_by_value)]
fn xor_short(buf: ShortSlice, mask: u64) {
fn xor_short(buf: ShortSlice<'_>, mask: u64) {
// Unsafe: we know that a `ShortSlice` fits in a u64
unsafe {
let (ptr, len) = (buf.0.as_mut_ptr(), buf.0.len());
@@ -77,7 +77,7 @@ unsafe fn cast_slice(buf: &mut [u8]) -> &mut [u64] {
#[inline]
// Splits a slice into three parts: an unaligned short head and tail, plus an aligned
// u64 mid section.
fn align_buf(buf: &mut [u8]) -> (ShortSlice, &mut [u64], ShortSlice) {
fn align_buf(buf: &mut [u8]) -> (ShortSlice<'_>, &mut [u64], ShortSlice<'_>) {
let start_ptr = buf.as_ptr() as usize;
let end_ptr = start_ptr + buf.len();

View File

@@ -13,15 +13,15 @@ use crate::message::RequestHead;
use crate::response::{Response, ResponseBuilder};
mod codec;
mod dispatcher;
mod frame;
mod mask;
mod proto;
mod transport;
pub use self::codec::{Codec, Frame, Message};
pub use self::codec::{Codec, Frame, Item, Message};
pub use self::dispatcher::Dispatcher;
pub use self::frame::Parser;
pub use self::proto::{hash_key, CloseCode, CloseReason, OpCode};
pub use self::transport::Transport;
/// Websocket protocol errors
#[derive(Debug, Display, From)]
@@ -44,12 +44,15 @@ pub enum ProtocolError {
/// A payload reached size limit.
#[display(fmt = "A payload reached size limit.")]
Overflow,
/// Continuation is not supported
#[display(fmt = "Continuation is not supported.")]
NoContinuation,
/// Bad utf-8 encoding
#[display(fmt = "Bad utf-8 encoding.")]
BadEncoding,
/// Continuation is not started
#[display(fmt = "Continuation is not started.")]
ContinuationNotStarted,
/// Received new continuation but it is already started
#[display(fmt = "Received new continuation but it is already started")]
ContinuationStarted,
/// Unknown continuation fragment
#[display(fmt = "Unknown continuation fragment.")]
ContinuationFragment(OpCode),
/// Io error
#[display(fmt = "io error: {}", _0)]
Io(io::Error),

View File

@@ -24,7 +24,7 @@ pub enum OpCode {
}
impl fmt::Display for OpCode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Continue => write!(f, "CONTINUE"),
Text => write!(f, "TEXT"),
@@ -95,7 +95,7 @@ pub enum CloseCode {
Abnormal,
/// Indicates that an endpoint is terminating the connection
/// because it has received data within a message that was not
/// consistent with the type of the message (e.g., non-UTF-8 [RFC3629]
/// consistent with the type of the message (e.g., non-UTF-8 \[RFC3629\]
/// data within a text message).
Invalid,
/// Indicates that an endpoint is terminating the connection

View File

@@ -3,7 +3,7 @@ use bytes::Bytes;
use futures::future::{self, ok};
use actix_http::{http, HttpService, Request, Response};
use actix_http_test::TestServer;
use actix_http_test::test_server;
const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
@@ -29,7 +29,7 @@ const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
#[actix_rt::test]
async fn test_h1_v2() {
let srv = TestServer::start(move || {
let srv = test_server(move || {
HttpService::build()
.finish(|_| future::ok::<_, ()>(Response::Ok().body(STR)))
.tcp()
@@ -56,7 +56,7 @@ async fn test_h1_v2() {
#[actix_rt::test]
async fn test_connection_close() {
let srv = TestServer::start(move || {
let srv = test_server(move || {
HttpService::build()
.finish(|_| ok::<_, ()>(Response::Ok().body(STR)))
.tcp()
@@ -69,7 +69,7 @@ async fn test_connection_close() {
#[actix_rt::test]
async fn test_with_query_parameter() {
let srv = TestServer::start(move || {
let srv = test_server(move || {
HttpService::build()
.finish(|req: Request| {
if req.uri().query().unwrap().contains("qp=") {

View File

@@ -1,8 +1,8 @@
#![cfg(feature = "openssl")]
use std::io;
use actix_http_test::TestServer;
use actix_service::{service_fn, ServiceFactory};
use actix_http_test::test_server;
use actix_service::{fn_service, ServiceFactory};
use bytes::{Bytes, BytesMut};
use futures::future::{err, ok, ready};
@@ -62,7 +62,7 @@ fn ssl_acceptor() -> SslAcceptor {
#[actix_rt::test]
async fn test_h2() -> io::Result<()> {
let srv = TestServer::start(move || {
let srv = test_server(move || {
HttpService::build()
.h2(|_| ok::<_, Error>(Response::Ok().finish()))
.openssl(ssl_acceptor())
@@ -76,7 +76,7 @@ async fn test_h2() -> io::Result<()> {
#[actix_rt::test]
async fn test_h2_1() -> io::Result<()> {
let srv = TestServer::start(move || {
let srv = test_server(move || {
HttpService::build()
.finish(|req: Request| {
assert!(req.peer_addr().is_some());
@@ -95,7 +95,7 @@ async fn test_h2_1() -> io::Result<()> {
#[actix_rt::test]
async fn test_h2_body() -> io::Result<()> {
let data = "HELLOWORLD".to_owned().repeat(64 * 1024);
let mut srv = TestServer::start(move || {
let mut srv = test_server(move || {
HttpService::build()
.h2(|mut req: Request<_>| {
async move {
@@ -117,7 +117,7 @@ async fn test_h2_body() -> io::Result<()> {
#[actix_rt::test]
async fn test_h2_content_length() {
let srv = TestServer::start(move || {
let srv = test_server(move || {
HttpService::build()
.h2(|req: Request| {
let indx: usize = req.uri().path()[1..].parse().unwrap();
@@ -168,7 +168,7 @@ async fn test_h2_headers() {
let data = STR.repeat(10);
let data2 = data.clone();
let mut srv = TestServer::start(move || {
let mut srv = test_server(move || {
let data = data.clone();
HttpService::build().h2(move |_| {
let mut builder = Response::Ok();
@@ -228,7 +228,7 @@ const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
#[actix_rt::test]
async fn test_h2_body2() {
let mut srv = TestServer::start(move || {
let mut srv = test_server(move || {
HttpService::build()
.h2(|_| ok::<_, ()>(Response::Ok().body(STR)))
.openssl(ssl_acceptor())
@@ -245,7 +245,7 @@ async fn test_h2_body2() {
#[actix_rt::test]
async fn test_h2_head_empty() {
let mut srv = TestServer::start(move || {
let mut srv = test_server(move || {
HttpService::build()
.finish(|_| ok::<_, ()>(Response::Ok().body(STR)))
.openssl(ssl_acceptor())
@@ -268,7 +268,7 @@ async fn test_h2_head_empty() {
#[actix_rt::test]
async fn test_h2_head_binary() {
let mut srv = TestServer::start(move || {
let mut srv = test_server(move || {
HttpService::build()
.h2(|_| {
ok::<_, ()>(Response::Ok().content_length(STR.len() as u64).body(STR))
@@ -292,7 +292,7 @@ async fn test_h2_head_binary() {
#[actix_rt::test]
async fn test_h2_head_binary2() {
let srv = TestServer::start(move || {
let srv = test_server(move || {
HttpService::build()
.h2(|_| ok::<_, ()>(Response::Ok().body(STR)))
.openssl(ssl_acceptor())
@@ -310,7 +310,7 @@ async fn test_h2_head_binary2() {
#[actix_rt::test]
async fn test_h2_body_length() {
let mut srv = TestServer::start(move || {
let mut srv = test_server(move || {
HttpService::build()
.h2(|_| {
let body = once(ok(Bytes::from_static(STR.as_ref())));
@@ -332,7 +332,7 @@ async fn test_h2_body_length() {
#[actix_rt::test]
async fn test_h2_body_chunked_explicit() {
let mut srv = TestServer::start(move || {
let mut srv = test_server(move || {
HttpService::build()
.h2(|_| {
let body = once(ok::<_, Error>(Bytes::from_static(STR.as_ref())));
@@ -359,9 +359,9 @@ async fn test_h2_body_chunked_explicit() {
#[actix_rt::test]
async fn test_h2_response_http_error_handling() {
let mut srv = TestServer::start(move || {
let mut srv = test_server(move || {
HttpService::build()
.h2(service_fn(|_| {
.h2(fn_service(|_| {
let broken_header = Bytes::from_static(b"\0\0\0");
ok::<_, ()>(
Response::Ok()
@@ -383,7 +383,7 @@ async fn test_h2_response_http_error_handling() {
#[actix_rt::test]
async fn test_h2_service_error() {
let mut srv = TestServer::start(move || {
let mut srv = test_server(move || {
HttpService::build()
.h2(|_| err::<Response, Error>(ErrorBadRequest("error")))
.openssl(ssl_acceptor())
@@ -400,7 +400,7 @@ async fn test_h2_service_error() {
#[actix_rt::test]
async fn test_h2_on_connect() {
let srv = TestServer::start(move || {
let srv = test_server(move || {
HttpService::build()
.on_connect(|_| 10usize)
.h2(|req: Request| {

View File

@@ -3,8 +3,8 @@ use actix_http::error::PayloadError;
use actix_http::http::header::{self, HeaderName, HeaderValue};
use actix_http::http::{Method, StatusCode, Version};
use actix_http::{body, error, Error, HttpService, Request, Response};
use actix_http_test::TestServer;
use actix_service::{factory_fn_cfg, service_fn2};
use actix_http_test::test_server;
use actix_service::{fn_factory_with_config, fn_service};
use bytes::{Bytes, BytesMut};
use futures::future::{self, err, ok};
@@ -41,7 +41,7 @@ fn ssl_acceptor() -> RustlsServerConfig {
#[actix_rt::test]
async fn test_h1() -> io::Result<()> {
let srv = TestServer::start(move || {
let srv = test_server(move || {
HttpService::build()
.h1(|_| future::ok::<_, Error>(Response::Ok().finish()))
.rustls(ssl_acceptor())
@@ -54,7 +54,7 @@ async fn test_h1() -> io::Result<()> {
#[actix_rt::test]
async fn test_h2() -> io::Result<()> {
let srv = TestServer::start(move || {
let srv = test_server(move || {
HttpService::build()
.h2(|_| future::ok::<_, Error>(Response::Ok().finish()))
.rustls(ssl_acceptor())
@@ -67,7 +67,7 @@ async fn test_h2() -> io::Result<()> {
#[actix_rt::test]
async fn test_h1_1() -> io::Result<()> {
let srv = TestServer::start(move || {
let srv = test_server(move || {
HttpService::build()
.h1(|req: Request| {
assert!(req.peer_addr().is_some());
@@ -84,7 +84,7 @@ async fn test_h1_1() -> io::Result<()> {
#[actix_rt::test]
async fn test_h2_1() -> io::Result<()> {
let srv = TestServer::start(move || {
let srv = test_server(move || {
HttpService::build()
.finish(|req: Request| {
assert!(req.peer_addr().is_some());
@@ -102,7 +102,7 @@ async fn test_h2_1() -> io::Result<()> {
#[actix_rt::test]
async fn test_h2_body1() -> io::Result<()> {
let data = "HELLOWORLD".to_owned().repeat(64 * 1024);
let mut srv = TestServer::start(move || {
let mut srv = test_server(move || {
HttpService::build()
.h2(|mut req: Request<_>| {
async move {
@@ -123,7 +123,7 @@ async fn test_h2_body1() -> io::Result<()> {
#[actix_rt::test]
async fn test_h2_content_length() {
let srv = TestServer::start(move || {
let srv = test_server(move || {
HttpService::build()
.h2(|req: Request| {
let indx: usize = req.uri().path()[1..].parse().unwrap();
@@ -172,7 +172,7 @@ async fn test_h2_headers() {
let data = STR.repeat(10);
let data2 = data.clone();
let mut srv = TestServer::start(move || {
let mut srv = test_server(move || {
let data = data.clone();
HttpService::build().h2(move |_| {
let mut config = Response::Ok();
@@ -231,7 +231,7 @@ const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
#[actix_rt::test]
async fn test_h2_body2() {
let mut srv = TestServer::start(move || {
let mut srv = test_server(move || {
HttpService::build()
.h2(|_| future::ok::<_, ()>(Response::Ok().body(STR)))
.rustls(ssl_acceptor())
@@ -247,7 +247,7 @@ async fn test_h2_body2() {
#[actix_rt::test]
async fn test_h2_head_empty() {
let mut srv = TestServer::start(move || {
let mut srv = test_server(move || {
HttpService::build()
.finish(|_| ok::<_, ()>(Response::Ok().body(STR)))
.rustls(ssl_acceptor())
@@ -272,7 +272,7 @@ async fn test_h2_head_empty() {
#[actix_rt::test]
async fn test_h2_head_binary() {
let mut srv = TestServer::start(move || {
let mut srv = test_server(move || {
HttpService::build()
.h2(|_| {
ok::<_, ()>(Response::Ok().content_length(STR.len() as u64).body(STR))
@@ -298,7 +298,7 @@ async fn test_h2_head_binary() {
#[actix_rt::test]
async fn test_h2_head_binary2() {
let srv = TestServer::start(move || {
let srv = test_server(move || {
HttpService::build()
.h2(|_| ok::<_, ()>(Response::Ok().body(STR)))
.rustls(ssl_acceptor())
@@ -318,7 +318,7 @@ async fn test_h2_head_binary2() {
#[actix_rt::test]
async fn test_h2_body_length() {
let mut srv = TestServer::start(move || {
let mut srv = test_server(move || {
HttpService::build()
.h2(|_| {
let body = once(ok(Bytes::from_static(STR.as_ref())));
@@ -339,7 +339,7 @@ async fn test_h2_body_length() {
#[actix_rt::test]
async fn test_h2_body_chunked_explicit() {
let mut srv = TestServer::start(move || {
let mut srv = test_server(move || {
HttpService::build()
.h2(|_| {
let body = once(ok::<_, Error>(Bytes::from_static(STR.as_ref())));
@@ -365,10 +365,10 @@ async fn test_h2_body_chunked_explicit() {
#[actix_rt::test]
async fn test_h2_response_http_error_handling() {
let mut srv = TestServer::start(move || {
let mut srv = test_server(move || {
HttpService::build()
.h2(factory_fn_cfg(|_: ()| {
ok::<_, ()>(service_fn2(|_| {
.h2(fn_factory_with_config(|_: ()| {
ok::<_, ()>(fn_service(|_| {
let broken_header = Bytes::from_static(b"\0\0\0");
ok::<_, ()>(
Response::Ok()
@@ -390,7 +390,7 @@ async fn test_h2_response_http_error_handling() {
#[actix_rt::test]
async fn test_h2_service_error() {
let mut srv = TestServer::start(move || {
let mut srv = test_server(move || {
HttpService::build()
.h2(|_| err::<Response, Error>(error::ErrorBadRequest("error")))
.rustls(ssl_acceptor())
@@ -406,7 +406,7 @@ async fn test_h2_service_error() {
#[actix_rt::test]
async fn test_h1_service_error() {
let mut srv = TestServer::start(move || {
let mut srv = test_server(move || {
HttpService::build()
.h1(|_| err::<Response, Error>(error::ErrorBadRequest("error")))
.rustls(ssl_acceptor())

View File

@@ -2,9 +2,9 @@ use std::io::{Read, Write};
use std::time::Duration;
use std::{net, thread};
use actix_http_test::TestServer;
use actix_http_test::test_server;
use actix_rt::time::delay_for;
use actix_service::service_fn;
use actix_service::fn_service;
use bytes::Bytes;
use futures::future::{self, err, ok, ready, FutureExt};
use futures::stream::{once, StreamExt};
@@ -17,7 +17,7 @@ use actix_http::{
#[actix_rt::test]
async fn test_h1() {
let srv = TestServer::start(|| {
let srv = test_server(|| {
HttpService::build()
.keep_alive(KeepAlive::Disabled)
.client_timeout(1000)
@@ -35,7 +35,7 @@ async fn test_h1() {
#[actix_rt::test]
async fn test_h1_2() {
let srv = TestServer::start(|| {
let srv = test_server(|| {
HttpService::build()
.keep_alive(KeepAlive::Disabled)
.client_timeout(1000)
@@ -54,9 +54,9 @@ async fn test_h1_2() {
#[actix_rt::test]
async fn test_expect_continue() {
let srv = TestServer::start(|| {
let srv = test_server(|| {
HttpService::build()
.expect(service_fn(|req: Request| {
.expect(fn_service(|req: Request| {
if req.head().uri.query() == Some("yes=") {
ok(req)
} else {
@@ -82,9 +82,9 @@ async fn test_expect_continue() {
#[actix_rt::test]
async fn test_expect_continue_h1() {
let srv = TestServer::start(|| {
let srv = test_server(|| {
HttpService::build()
.expect(service_fn(|req: Request| {
.expect(fn_service(|req: Request| {
delay_for(Duration::from_millis(20)).then(move |_| {
if req.head().uri.query() == Some("yes=") {
ok(req)
@@ -93,7 +93,7 @@ async fn test_expect_continue_h1() {
}
})
}))
.h1(service_fn(|_| future::ok::<_, ()>(Response::Ok().finish())))
.h1(fn_service(|_| future::ok::<_, ()>(Response::Ok().finish())))
.tcp()
});
@@ -115,9 +115,9 @@ async fn test_chunked_payload() {
let chunk_sizes = vec![32768, 32, 32768];
let total_size: usize = chunk_sizes.iter().sum();
let srv = TestServer::start(|| {
let srv = test_server(|| {
HttpService::build()
.h1(service_fn(|mut request: Request| {
.h1(fn_service(|mut request: Request| {
request
.take_payload()
.map(|res| match res {
@@ -167,7 +167,7 @@ async fn test_chunked_payload() {
#[actix_rt::test]
async fn test_slow_request() {
let srv = TestServer::start(|| {
let srv = test_server(|| {
HttpService::build()
.client_timeout(100)
.finish(|_| future::ok::<_, ()>(Response::Ok().finish()))
@@ -183,7 +183,7 @@ async fn test_slow_request() {
#[actix_rt::test]
async fn test_http1_malformed_request() {
let srv = TestServer::start(|| {
let srv = test_server(|| {
HttpService::build()
.h1(|_| future::ok::<_, ()>(Response::Ok().finish()))
.tcp()
@@ -198,7 +198,7 @@ async fn test_http1_malformed_request() {
#[actix_rt::test]
async fn test_http1_keepalive() {
let srv = TestServer::start(|| {
let srv = test_server(|| {
HttpService::build()
.h1(|_| future::ok::<_, ()>(Response::Ok().finish()))
.tcp()
@@ -218,7 +218,7 @@ async fn test_http1_keepalive() {
#[actix_rt::test]
async fn test_http1_keepalive_timeout() {
let srv = TestServer::start(|| {
let srv = test_server(|| {
HttpService::build()
.keep_alive(1)
.h1(|_| future::ok::<_, ()>(Response::Ok().finish()))
@@ -239,7 +239,7 @@ async fn test_http1_keepalive_timeout() {
#[actix_rt::test]
async fn test_http1_keepalive_close() {
let srv = TestServer::start(|| {
let srv = test_server(|| {
HttpService::build()
.h1(|_| future::ok::<_, ()>(Response::Ok().finish()))
.tcp()
@@ -259,7 +259,7 @@ async fn test_http1_keepalive_close() {
#[actix_rt::test]
async fn test_http10_keepalive_default_close() {
let srv = TestServer::start(|| {
let srv = test_server(|| {
HttpService::build()
.h1(|_| future::ok::<_, ()>(Response::Ok().finish()))
.tcp()
@@ -278,7 +278,7 @@ async fn test_http10_keepalive_default_close() {
#[actix_rt::test]
async fn test_http10_keepalive() {
let srv = TestServer::start(|| {
let srv = test_server(|| {
HttpService::build()
.h1(|_| future::ok::<_, ()>(Response::Ok().finish()))
.tcp()
@@ -304,7 +304,7 @@ async fn test_http10_keepalive() {
#[actix_rt::test]
async fn test_http1_keepalive_disabled() {
let srv = TestServer::start(|| {
let srv = test_server(|| {
HttpService::build()
.keep_alive(KeepAlive::Disabled)
.h1(|_| future::ok::<_, ()>(Response::Ok().finish()))
@@ -329,7 +329,7 @@ async fn test_content_length() {
StatusCode,
};
let srv = TestServer::start(|| {
let srv = test_server(|| {
HttpService::build()
.h1(|req: Request| {
let indx: usize = req.uri().path()[1..].parse().unwrap();
@@ -373,7 +373,7 @@ async fn test_h1_headers() {
let data = STR.repeat(10);
let data2 = data.clone();
let mut srv = TestServer::start(move || {
let mut srv = test_server(move || {
let data = data.clone();
HttpService::build().h1(move |_| {
let mut builder = Response::Ok();
@@ -431,7 +431,7 @@ const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
#[actix_rt::test]
async fn test_h1_body() {
let mut srv = TestServer::start(|| {
let mut srv = test_server(|| {
HttpService::build()
.h1(|_| ok::<_, ()>(Response::Ok().body(STR)))
.tcp()
@@ -447,7 +447,7 @@ async fn test_h1_body() {
#[actix_rt::test]
async fn test_h1_head_empty() {
let mut srv = TestServer::start(|| {
let mut srv = test_server(|| {
HttpService::build()
.h1(|_| ok::<_, ()>(Response::Ok().body(STR)))
.tcp()
@@ -471,7 +471,7 @@ async fn test_h1_head_empty() {
#[actix_rt::test]
async fn test_h1_head_binary() {
let mut srv = TestServer::start(|| {
let mut srv = test_server(|| {
HttpService::build()
.h1(|_| {
ok::<_, ()>(Response::Ok().content_length(STR.len() as u64).body(STR))
@@ -497,7 +497,7 @@ async fn test_h1_head_binary() {
#[actix_rt::test]
async fn test_h1_head_binary2() {
let srv = TestServer::start(|| {
let srv = test_server(|| {
HttpService::build()
.h1(|_| ok::<_, ()>(Response::Ok().body(STR)))
.tcp()
@@ -517,7 +517,7 @@ async fn test_h1_head_binary2() {
#[actix_rt::test]
async fn test_h1_body_length() {
let mut srv = TestServer::start(|| {
let mut srv = test_server(|| {
HttpService::build()
.h1(|_| {
let body = once(ok(Bytes::from_static(STR.as_ref())));
@@ -538,7 +538,7 @@ async fn test_h1_body_length() {
#[actix_rt::test]
async fn test_h1_body_chunked_explicit() {
let mut srv = TestServer::start(|| {
let mut srv = test_server(|| {
HttpService::build()
.h1(|_| {
let body = once(ok::<_, Error>(Bytes::from_static(STR.as_ref())));
@@ -572,7 +572,7 @@ async fn test_h1_body_chunked_explicit() {
#[actix_rt::test]
async fn test_h1_body_chunked_implicit() {
let mut srv = TestServer::start(|| {
let mut srv = test_server(|| {
HttpService::build()
.h1(|_| {
let body = once(ok::<_, Error>(Bytes::from_static(STR.as_ref())));
@@ -600,9 +600,9 @@ async fn test_h1_body_chunked_implicit() {
#[actix_rt::test]
async fn test_h1_response_http_error_handling() {
let mut srv = TestServer::start(|| {
let mut srv = test_server(|| {
HttpService::build()
.h1(service_fn(|_| {
.h1(fn_service(|_| {
let broken_header = Bytes::from_static(b"\0\0\0");
ok::<_, ()>(
Response::Ok()
@@ -623,7 +623,7 @@ async fn test_h1_response_http_error_handling() {
#[actix_rt::test]
async fn test_h1_service_error() {
let mut srv = TestServer::start(|| {
let mut srv = test_server(|| {
HttpService::build()
.h1(|_| future::err::<Response, Error>(error::ErrorBadRequest("error")))
.tcp()
@@ -639,7 +639,7 @@ async fn test_h1_service_error() {
#[actix_rt::test]
async fn test_h1_on_connect() {
let srv = TestServer::start(|| {
let srv = test_server(|| {
HttpService::build()
.on_connect(|_| 10usize)
.h1(|req: Request| {

View File

@@ -1,33 +1,80 @@
use std::cell::Cell;
use std::marker::PhantomData;
use std::pin::Pin;
use std::sync::{Arc, Mutex};
use actix_codec::{AsyncRead, AsyncWrite, Framed};
use actix_http::{body, h1, ws, Error, HttpService, Request, Response};
use actix_http_test::TestServer;
use actix_utils::framed::FramedTransport;
use bytes::BytesMut;
use actix_http_test::test_server;
use actix_service::{fn_factory, Service};
use actix_utils::framed::Dispatcher;
use bytes::Bytes;
use futures::future;
use futures::{SinkExt, StreamExt};
use futures::task::{Context, Poll};
use futures::{Future, SinkExt, StreamExt};
async fn ws_service<T: AsyncRead + AsyncWrite + Unpin>(
(req, mut framed): (Request, Framed<T, h1::Codec>),
) -> Result<(), Error> {
let res = ws::handshake(req.head()).unwrap().message_body(());
struct WsService<T>(Arc<Mutex<(PhantomData<T>, Cell<bool>)>>);
framed
.send((res, body::BodySize::None).into())
.await
.unwrap();
impl<T> WsService<T> {
fn new() -> Self {
WsService(Arc::new(Mutex::new((PhantomData, Cell::new(false)))))
}
FramedTransport::new(framed.into_framed(ws::Codec::new()), service)
.await
.map_err(|_| panic!())
fn set_polled(&mut self) {
*self.0.lock().unwrap().1.get_mut() = true;
}
fn was_polled(&self) -> bool {
self.0.lock().unwrap().1.get()
}
}
impl<T> Clone for WsService<T> {
fn clone(&self) -> Self {
WsService(self.0.clone())
}
}
impl<T> Service for WsService<T>
where
T: AsyncRead + AsyncWrite + Unpin + 'static,
{
type Request = (Request, Framed<T, h1::Codec>);
type Response = ();
type Error = Error;
type Future = Pin<Box<dyn Future<Output = Result<(), Error>>>>;
fn poll_ready(&mut self, _ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.set_polled();
Poll::Ready(Ok(()))
}
fn call(&mut self, (req, mut framed): Self::Request) -> Self::Future {
let fut = async move {
let res = ws::handshake(req.head()).unwrap().message_body(());
framed
.send((res, body::BodySize::None).into())
.await
.unwrap();
Dispatcher::new(framed.into_framed(ws::Codec::new()), service)
.await
.map_err(|_| panic!())
};
Box::pin(fut)
}
}
async fn service(msg: ws::Frame) -> Result<ws::Message, Error> {
let msg = match msg {
ws::Frame::Ping(msg) => ws::Message::Pong(msg),
ws::Frame::Text(text) => {
ws::Message::Text(String::from_utf8_lossy(&text.unwrap()).to_string())
ws::Message::Text(String::from_utf8_lossy(&text).to_string())
}
ws::Frame::Binary(bin) => ws::Message::Binary(bin.unwrap().freeze()),
ws::Frame::Binary(bin) => ws::Message::Binary(bin),
ws::Frame::Continuation(item) => ws::Message::Continuation(item),
ws::Frame::Close(reason) => ws::Message::Close(reason),
_ => panic!(),
};
@@ -36,11 +83,16 @@ async fn service(msg: ws::Frame) -> Result<ws::Message, Error> {
#[actix_rt::test]
async fn test_simple() {
let mut srv = TestServer::start(|| {
HttpService::build()
.upgrade(actix_service::service_fn(ws_service))
.finish(|_| future::ok::<_, ()>(Response::NotFound()))
.tcp()
let ws_service = WsService::new();
let mut srv = test_server({
let ws_service = ws_service.clone();
move || {
let ws_service = ws_service.clone();
HttpService::build()
.upgrade(fn_factory(move || future::ok::<_, ()>(ws_service.clone())))
.finish(|_| future::ok::<_, ()>(Response::NotFound()))
.tcp()
}
});
// client service
@@ -52,7 +104,7 @@ async fn test_simple() {
let (item, mut framed) = framed.into_future().await;
assert_eq!(
item.unwrap().unwrap(),
ws::Frame::Text(Some(BytesMut::from("text")))
ws::Frame::Text(Bytes::from_static(b"text"))
);
framed
@@ -62,7 +114,7 @@ async fn test_simple() {
let (item, mut framed) = framed.into_future().await;
assert_eq!(
item.unwrap().unwrap(),
ws::Frame::Binary(Some(BytesMut::from(&b"text"[..]).into()))
ws::Frame::Binary(Bytes::from_static(&b"text"[..]))
);
framed.send(ws::Message::Ping("text".into())).await.unwrap();
@@ -72,6 +124,61 @@ async fn test_simple() {
ws::Frame::Pong("text".to_string().into())
);
framed
.send(ws::Message::Continuation(ws::Item::FirstText(
"text".into(),
)))
.await
.unwrap();
let (item, mut framed) = framed.into_future().await;
assert_eq!(
item.unwrap().unwrap(),
ws::Frame::Continuation(ws::Item::FirstText(Bytes::from_static(b"text")))
);
assert!(framed
.send(ws::Message::Continuation(ws::Item::FirstText(
"text".into()
)))
.await
.is_err());
assert!(framed
.send(ws::Message::Continuation(ws::Item::FirstBinary(
"text".into()
)))
.await
.is_err());
framed
.send(ws::Message::Continuation(ws::Item::Continue("text".into())))
.await
.unwrap();
let (item, mut framed) = framed.into_future().await;
assert_eq!(
item.unwrap().unwrap(),
ws::Frame::Continuation(ws::Item::Continue(Bytes::from_static(b"text")))
);
framed
.send(ws::Message::Continuation(ws::Item::Last("text".into())))
.await
.unwrap();
let (item, mut framed) = framed.into_future().await;
assert_eq!(
item.unwrap().unwrap(),
ws::Frame::Continuation(ws::Item::Last(Bytes::from_static(b"text")))
);
assert!(framed
.send(ws::Message::Continuation(ws::Item::Continue("text".into())))
.await
.is_err());
assert!(framed
.send(ws::Message::Continuation(ws::Item::Last("text".into())))
.await
.is_err());
framed
.send(ws::Message::Close(Some(ws::CloseCode::Normal.into())))
.await
@@ -82,4 +189,6 @@ async fn test_simple() {
item.unwrap().unwrap(),
ws::Frame::Close(Some(ws::CloseCode::Normal.into()))
);
assert!(ws_service.was_polled());
}

View File

@@ -1,5 +1,9 @@
# Changes
## [0.2.0] - 2019-12-20
* Use actix-web 2.0
## [0.1.0] - 2019-06-xx
* Move identity middleware to separate crate

View File

@@ -1,6 +1,6 @@
[package]
name = "actix-identity"
version = "0.2.0-alpha.3"
version = "0.2.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Identity service for actix web framework."
readme = "README.md"
@@ -17,14 +17,14 @@ name = "actix_identity"
path = "src/lib.rs"
[dependencies]
actix-web = { version = "2.0.0-alpha.3", default-features = false, features = ["secure-cookies"] }
actix-service = "1.0.0-alpha.3"
actix-web = { version = "2.0.0-rc", default-features = false, features = ["secure-cookies"] }
actix-service = "1.0.0"
futures = "0.3.1"
serde = "1.0"
serde_json = "1.0"
time = "0.1.42"
[dev-dependencies]
actix-rt = "1.0.0-alpha.3"
actix-http = "1.0.0-alpha.3"
bytes = "0.5.2"
actix-rt = "1.0.0"
actix-http = "1.0.1"
bytes = "0.5.3"

View File

@@ -1,5 +1,13 @@
# Changes
## [0.2.0] - 2019-12-20
* Release
## [0.2.0-alpha.4] - 2019-12-xx
* Multipart handling now handles Pending during read of boundary #1205
## [0.2.0-alpha.2] - 2019-12-03
* Migrate to `std::future`

View File

@@ -1,6 +1,6 @@
[package]
name = "actix-multipart"
version = "0.2.0-alpha.3"
version = "0.2.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Multipart support for actix web framework."
readme = "README.md"
@@ -9,8 +9,6 @@ homepage = "https://actix.rs"
repository = "https://github.com/actix/actix-web.git"
documentation = "https://docs.rs/actix-multipart/"
license = "MIT/Apache-2.0"
exclude = [".gitignore", ".travis.yml", ".cargo/config", "appveyor.yml"]
workspace = ".."
edition = "2018"
[lib]
@@ -18,10 +16,10 @@ name = "actix_multipart"
path = "src/lib.rs"
[dependencies]
actix-web = { version = "2.0.0-alpha.3", default-features = false }
actix-service = "1.0.0-alpha.3"
actix-utils = "1.0.0-alpha.3"
bytes = "0.5.2"
actix-web = { version = "2.0.0-rc", default-features = false }
actix-service = "1.0.0"
actix-utils = "1.0.3"
bytes = "0.5.3"
derive_more = "0.99.2"
httparse = "1.3"
futures = "0.3.1"
@@ -31,5 +29,5 @@ time = "0.1"
twoway = "0.2"
[dev-dependencies]
actix-rt = "1.0.0-alpha.3"
actix-http = "1.0.0-alpha.3"
actix-rt = "1.0.0"
actix-http = "1.0.0"

View File

@@ -610,7 +610,7 @@ impl InnerField {
}
match payload.readline() {
Ok(None) => Poll::Ready(None),
Ok(None) => Poll::Pending,
Ok(Some(line)) => {
if line.as_ref() != b"\r\n" {
log::warn!("multipart field did not read all the data or it is malformed");
@@ -867,6 +867,45 @@ mod tests {
(tx, rx.map(|res| res.map_err(|_| panic!())))
}
// Stream that returns from a Bytes, one char at a time and Pending every other poll()
struct SlowStream {
bytes: Bytes,
pos: usize,
ready: bool,
}
impl SlowStream {
fn new(bytes: Bytes) -> SlowStream {
return SlowStream {
bytes: bytes,
pos: 0,
ready: false,
};
}
}
impl Stream for SlowStream {
type Item = Result<Bytes, PayloadError>;
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context,
) -> Poll<Option<Self::Item>> {
let this = self.get_mut();
if !this.ready {
this.ready = true;
cx.waker().wake_by_ref();
return Poll::Pending;
}
if this.pos == this.bytes.len() {
return Poll::Ready(None);
}
let res = Poll::Ready(Some(Ok(this.bytes.slice(this.pos..(this.pos + 1)))));
this.pos += 1;
this.ready = false;
res
}
}
fn create_simple_request_with_header() -> (Bytes, HeaderMap) {
let bytes = Bytes::from(
@@ -969,12 +1008,22 @@ mod tests {
}
}
// Loops, collecting all bytes until end-of-field
async fn get_whole_field(field: &mut Field) -> BytesMut {
let mut b = BytesMut::new();
loop {
match field.next().await {
Some(Ok(chunk)) => b.extend_from_slice(&chunk),
None => return b,
_ => unreachable!(),
}
}
}
#[actix_rt::test]
async fn test_stream() {
let (sender, payload) = create_stream();
let (bytes, headers) = create_simple_request_with_header();
sender.send(Ok(bytes)).unwrap();
let payload = SlowStream::new(bytes);
let mut multipart = Multipart::new(&headers, payload);
match multipart.next().await.unwrap() {
@@ -986,14 +1035,7 @@ mod tests {
assert_eq!(field.content_type().type_(), mime::TEXT);
assert_eq!(field.content_type().subtype(), mime::PLAIN);
match field.next().await.unwrap() {
Ok(chunk) => assert_eq!(chunk, "test"),
_ => unreachable!(),
}
match field.next().await {
None => (),
_ => unreachable!(),
}
assert_eq!(get_whole_field(&mut field).await, "test");
}
_ => unreachable!(),
}
@@ -1003,14 +1045,7 @@ mod tests {
assert_eq!(field.content_type().type_(), mime::TEXT);
assert_eq!(field.content_type().subtype(), mime::PLAIN);
match field.next().await {
Some(Ok(chunk)) => assert_eq!(chunk, "data"),
_ => unreachable!(),
}
match field.next().await {
None => (),
_ => unreachable!(),
}
assert_eq!(get_whole_field(&mut field).await, "data");
}
_ => unreachable!(),
}

View File

@@ -1,5 +1,13 @@
# Changes
## [0.3.0] - 2019-12-20
* Release
## [0.3.0-alpha.4] - 2019-12-xx
* Allow access to sessions also from not mutable references to the request
## [0.3.0-alpha.3] - 2019-12-xx
* Add access to the session from RequestHead for use of session from guard methods

View File

@@ -1,6 +1,6 @@
[package]
name = "actix-session"
version = "0.3.0-alpha.3"
version = "0.3.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Session for actix web framework."
readme = "README.md"
@@ -9,8 +9,6 @@ homepage = "https://actix.rs"
repository = "https://github.com/actix/actix-web.git"
documentation = "https://docs.rs/actix-session/"
license = "MIT/Apache-2.0"
exclude = [".gitignore", ".travis.yml", ".cargo/config", "appveyor.yml"]
workspace = ".."
edition = "2018"
[lib]
@@ -24,9 +22,9 @@ default = ["cookie-session"]
cookie-session = ["actix-web/secure-cookies"]
[dependencies]
actix-web = "2.0.0-alpha.3"
actix-service = "1.0.0-alpha.3"
bytes = "0.5.2"
actix-web = "2.0.0-rc"
actix-service = "1.0.0"
bytes = "0.5.3"
derive_more = "0.99.2"
futures = "0.3.1"
serde = "1.0"
@@ -34,4 +32,4 @@ serde_json = "1.0"
time = "0.1.42"
[dev-dependencies]
actix-rt = "1.0.0-alpha.3"
actix-rt = "1.0.0"

View File

@@ -12,7 +12,7 @@
//! [*Session*](struct.Session.html) extractor must be used. Session
//! extractor allows us to get or set session data.
//!
//! ```rust
//! ```rust,no_run
//! use actix_web::{web, App, HttpServer, HttpResponse, Error};
//! use actix_session::{Session, CookieSession};
//!
@@ -28,8 +28,8 @@
//! Ok("Welcome!")
//! }
//!
//! fn main() -> std::io::Result<()> {
//! # std::thread::spawn(||
//! #[actix_rt::main]
//! async fn main() -> std::io::Result<()> {
//! HttpServer::new(
//! || App::new().wrap(
//! CookieSession::signed(&[0; 32]) // <- create cookie based session middleware
@@ -37,9 +37,8 @@
//! )
//! .service(web::resource("/").to(|| HttpResponse::Ok())))
//! .bind("127.0.0.1:59880")?
//! .run()
//! # );
//! # Ok(())
//! .start()
//! .await
//! }
//! ```
use std::cell::RefCell;
@@ -86,23 +85,23 @@ pub struct Session(Rc<RefCell<SessionInner>>);
/// Helper trait that allows to get session
pub trait UserSession {
fn get_session(&mut self) -> Session;
fn get_session(&self) -> Session;
}
impl UserSession for HttpRequest {
fn get_session(&mut self) -> Session {
fn get_session(&self) -> Session {
Session::get_session(&mut *self.extensions_mut())
}
}
impl UserSession for ServiceRequest {
fn get_session(&mut self) -> Session {
fn get_session(&self) -> Session {
Session::get_session(&mut *self.extensions_mut())
}
}
impl UserSession for RequestHead {
fn get_session(&mut self) -> Session {
fn get_session(&self) -> Session {
Session::get_session(&mut *self.extensions_mut())
}
}

View File

@@ -1,5 +1,17 @@
# Changes
## [2.0.0] - 2019-12-20
* Release
## [2.0.0-alpha.1] - 2019-12-15
* Migrate to actix-web 2.0.0
## [1.0.4] - 2019-12-07
* Allow comma-separated websocket subprotocols without spaces (#1172)
## [1.0.3] - 2019-11-14
* Update actix-web and actix-http dependencies

View File

@@ -1,6 +1,6 @@
[package]
name = "actix-web-actors"
version = "1.0.3"
version = "2.0.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix actors support for actix web framework."
readme = "README.md"
@@ -9,8 +9,6 @@ homepage = "https://actix.rs"
repository = "https://github.com/actix/actix-web.git"
documentation = "https://docs.rs/actix-web-actors/"
license = "MIT/Apache-2.0"
exclude = [".gitignore", ".travis.yml", ".cargo/config", "appveyor.yml"]
workspace = ".."
edition = "2018"
[lib]
@@ -18,13 +16,14 @@ name = "actix_web_actors"
path = "src/lib.rs"
[dependencies]
actix = "0.8.3"
actix-web = "1.0.9"
actix-http = "0.2.11"
actix-codec = "0.1.2"
bytes = "0.4"
futures = "0.1.25"
actix = "0.9.0"
actix-web = "2.0.0-rc"
actix-http = "1.0.1"
actix-codec = "0.2.0"
bytes = "0.5.2"
futures = "0.3.1"
pin-project = "0.4.6"
[dev-dependencies]
actix-rt = "1.0.0"
env_logger = "0.6"
actix-http-test = { version = "0.2.4", features=["ssl"] }

View File

@@ -1,4 +1,6 @@
use std::collections::VecDeque;
use std::pin::Pin;
use std::task::{Context, Poll};
use actix::dev::{
AsyncContextParts, ContextFut, ContextParts, Envelope, Mailbox, ToEnvelope,
@@ -7,10 +9,10 @@ use actix::fut::ActorFuture;
use actix::{
Actor, ActorContext, ActorState, Addr, AsyncContext, Handler, Message, SpawnHandle,
};
use actix_web::error::{Error, ErrorInternalServerError};
use actix_web::error::Error;
use bytes::Bytes;
use futures::sync::oneshot::Sender;
use futures::{Async, Future, Poll, Stream};
use futures::channel::oneshot::Sender;
use futures::{Future, Stream};
/// Execution context for http actors
pub struct HttpContext<A>
@@ -43,7 +45,7 @@ where
#[inline]
fn spawn<F>(&mut self, fut: F) -> SpawnHandle
where
F: ActorFuture<Item = (), Error = (), Actor = A> + 'static,
F: ActorFuture<Output = (), Actor = A> + 'static,
{
self.inner.spawn(fut)
}
@@ -51,7 +53,7 @@ where
#[inline]
fn wait<F>(&mut self, fut: F)
where
F: ActorFuture<Item = (), Error = (), Actor = A> + 'static,
F: ActorFuture<Output = (), Actor = A> + 'static,
{
self.inner.wait(fut)
}
@@ -81,7 +83,7 @@ where
{
#[inline]
/// Create a new HTTP Context from a request and an actor
pub fn create(actor: A) -> impl Stream<Item = Bytes, Error = Error> {
pub fn create(actor: A) -> impl Stream<Item = Result<Bytes, Error>> {
let mb = Mailbox::default();
let ctx = HttpContext {
inner: ContextParts::new(mb.sender_producer()),
@@ -91,7 +93,7 @@ where
}
/// Create a new HTTP Context
pub fn with_factory<F>(f: F) -> impl Stream<Item = Bytes, Error = Error>
pub fn with_factory<F>(f: F) -> impl Stream<Item = Result<Bytes, Error>>
where
F: FnOnce(&mut Self) -> A + 'static,
{
@@ -160,24 +162,23 @@ impl<A> Stream for HttpContextFut<A>
where
A: Actor<Context = HttpContext<A>>,
{
type Item = Bytes;
type Error = Error;
type Item = Result<Bytes, Error>;
fn poll(&mut self) -> Poll<Option<Bytes>, Error> {
fn poll_next(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Self::Item>> {
if self.fut.alive() {
match self.fut.poll() {
Ok(Async::NotReady) | Ok(Async::Ready(())) => (),
Err(_) => return Err(ErrorInternalServerError("error")),
}
let _ = Pin::new(&mut self.fut).poll(cx);
}
// frames
if let Some(data) = self.fut.ctx().stream.pop_front() {
Ok(Async::Ready(data))
Poll::Ready(data.map(|b| Ok(b)))
} else if self.fut.alive() {
Ok(Async::NotReady)
Poll::Pending
} else {
Ok(Async::Ready(None))
Poll::Ready(None)
}
}
}
@@ -199,9 +200,9 @@ mod tests {
use actix::Actor;
use actix_web::http::StatusCode;
use actix_web::test::{block_on, call_service, init_service, TestRequest};
use actix_web::test::{call_service, init_service, read_body, TestRequest};
use actix_web::{web, App, HttpResponse};
use bytes::{Bytes, BytesMut};
use bytes::Bytes;
use super::*;
@@ -223,31 +224,25 @@ mod tests {
if self.count > 3 {
ctx.write_eof()
} else {
ctx.write(Bytes::from(format!("LINE-{}", self.count).as_bytes()));
ctx.write(Bytes::from(format!("LINE-{}", self.count)));
ctx.run_later(Duration::from_millis(100), |slf, ctx| slf.write(ctx));
}
}
}
#[test]
fn test_default_resource() {
#[actix_rt::test]
async fn test_default_resource() {
let mut srv =
init_service(App::new().service(web::resource("/test").to(|| {
HttpResponse::Ok().streaming(HttpContext::create(MyActor { count: 0 }))
})));
})))
.await;
let req = TestRequest::with_uri("/test").to_request();
let mut resp = call_service(&mut srv, req);
let resp = call_service(&mut srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
let body = block_on(resp.take_body().fold(
BytesMut::new(),
move |mut body, chunk| {
body.extend_from_slice(&chunk);
Ok::<_, Error>(body)
},
))
.unwrap();
assert_eq!(body.freeze(), Bytes::from_static(b"LINE-1LINE-2LINE-3"));
let body = read_body(resp).await;
assert_eq!(body, Bytes::from_static(b"LINE-1LINE-2LINE-3"));
}
}

View File

@@ -1,6 +1,8 @@
//! Websocket integration
use std::collections::VecDeque;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use actix::dev::{
AsyncContextParts, ContextFut, ContextParts, Envelope, Mailbox, StreamHandler,
@@ -16,20 +18,20 @@ use actix_http::ws::{hash_key, Codec};
pub use actix_http::ws::{
CloseCode, CloseReason, Frame, HandshakeError, Message, ProtocolError,
};
use actix_web::dev::HttpResponseBuilder;
use actix_web::error::{Error, ErrorInternalServerError, PayloadError};
use actix_web::error::{Error, PayloadError};
use actix_web::http::{header, Method, StatusCode};
use actix_web::{HttpRequest, HttpResponse};
use bytes::{Bytes, BytesMut};
use futures::sync::oneshot::Sender;
use futures::{Async, Future, Poll, Stream};
use futures::channel::oneshot::Sender;
use futures::{Future, Stream};
/// Do websocket handshake and start ws actor.
pub fn start<A, T>(actor: A, req: &HttpRequest, stream: T) -> Result<HttpResponse, Error>
where
A: Actor<Context = WebsocketContext<A>> + StreamHandler<Message, ProtocolError>,
T: Stream<Item = Bytes, Error = PayloadError> + 'static,
A: Actor<Context = WebsocketContext<A>>
+ StreamHandler<Result<Message, ProtocolError>>,
T: Stream<Item = Result<Bytes, PayloadError>> + 'static,
{
let mut res = handshake(req)?;
Ok(res.streaming(WebsocketContext::create(actor, stream)))
@@ -52,8 +54,9 @@ pub fn start_with_addr<A, T>(
stream: T,
) -> Result<(Addr<A>, HttpResponse), Error>
where
A: Actor<Context = WebsocketContext<A>> + StreamHandler<Message, ProtocolError>,
T: Stream<Item = Bytes, Error = PayloadError> + 'static,
A: Actor<Context = WebsocketContext<A>>
+ StreamHandler<Result<Message, ProtocolError>>,
T: Stream<Item = Result<Bytes, PayloadError>> + 'static,
{
let mut res = handshake(req)?;
let (addr, out_stream) = WebsocketContext::create_with_addr(actor, stream);
@@ -70,8 +73,9 @@ pub fn start_with_protocols<A, T>(
stream: T,
) -> Result<HttpResponse, Error>
where
A: Actor<Context = WebsocketContext<A>> + StreamHandler<Message, ProtocolError>,
T: Stream<Item = Bytes, Error = PayloadError> + 'static,
A: Actor<Context = WebsocketContext<A>>
+ StreamHandler<Result<Message, ProtocolError>>,
T: Stream<Item = Result<Bytes, PayloadError>> + 'static,
{
let mut res = handshake_with_protocols(req, protocols)?;
Ok(res.streaming(WebsocketContext::create(actor, stream)))
@@ -152,7 +156,8 @@ pub fn handshake_with_protocols(
.and_then(|req_protocols| {
let req_protocols = req_protocols.to_str().ok()?;
req_protocols
.split(", ")
.split(',')
.map(|req_p| req_p.trim())
.find(|req_p| protocols.iter().any(|p| p == req_p))
});
@@ -201,14 +206,14 @@ where
{
fn spawn<F>(&mut self, fut: F) -> SpawnHandle
where
F: ActorFuture<Item = (), Error = (), Actor = A> + 'static,
F: ActorFuture<Output = (), Actor = A> + 'static,
{
self.inner.spawn(fut)
}
fn wait<F>(&mut self, fut: F)
where
F: ActorFuture<Item = (), Error = (), Actor = A> + 'static,
F: ActorFuture<Output = (), Actor = A> + 'static,
{
self.inner.wait(fut)
}
@@ -237,10 +242,10 @@ where
{
#[inline]
/// Create a new Websocket context from a request and an actor
pub fn create<S>(actor: A, stream: S) -> impl Stream<Item = Bytes, Error = Error>
pub fn create<S>(actor: A, stream: S) -> impl Stream<Item = Result<Bytes, Error>>
where
A: StreamHandler<Message, ProtocolError>,
S: Stream<Item = Bytes, Error = PayloadError> + 'static,
A: StreamHandler<Result<Message, ProtocolError>>,
S: Stream<Item = Result<Bytes, PayloadError>> + 'static,
{
let (_, stream) = WebsocketContext::create_with_addr(actor, stream);
stream
@@ -255,10 +260,10 @@ where
pub fn create_with_addr<S>(
actor: A,
stream: S,
) -> (Addr<A>, impl Stream<Item = Bytes, Error = Error>)
) -> (Addr<A>, impl Stream<Item = Result<Bytes, Error>>)
where
A: StreamHandler<Message, ProtocolError>,
S: Stream<Item = Bytes, Error = PayloadError> + 'static,
A: StreamHandler<Result<Message, ProtocolError>>,
S: Stream<Item = Result<Bytes, PayloadError>> + 'static,
{
let mb = Mailbox::default();
let mut ctx = WebsocketContext {
@@ -278,10 +283,10 @@ where
actor: A,
stream: S,
codec: Codec,
) -> impl Stream<Item = Bytes, Error = Error>
) -> impl Stream<Item = Result<Bytes, Error>>
where
A: StreamHandler<Message, ProtocolError>,
S: Stream<Item = Bytes, Error = PayloadError> + 'static,
A: StreamHandler<Result<Message, ProtocolError>>,
S: Stream<Item = Result<Bytes, PayloadError>> + 'static,
{
let mb = Mailbox::default();
let mut ctx = WebsocketContext {
@@ -297,11 +302,11 @@ where
pub fn with_factory<S, F>(
stream: S,
f: F,
) -> impl Stream<Item = Bytes, Error = Error>
) -> impl Stream<Item = Result<Bytes, Error>>
where
F: FnOnce(&mut Self) -> A + 'static,
A: StreamHandler<Message, ProtocolError>,
S: Stream<Item = Bytes, Error = PayloadError> + 'static,
A: StreamHandler<Result<Message, ProtocolError>>,
S: Stream<Item = Result<Bytes, PayloadError>> + 'static,
{
let mb = Mailbox::default();
let mut ctx = WebsocketContext {
@@ -345,14 +350,14 @@ where
/// Send ping frame
#[inline]
pub fn ping(&mut self, message: &str) {
self.write_raw(Message::Ping(message.to_string()));
pub fn ping(&mut self, message: &[u8]) {
self.write_raw(Message::Ping(Bytes::copy_from_slice(message)));
}
/// Send pong frame
#[inline]
pub fn pong(&mut self, message: &str) {
self.write_raw(Message::Pong(message.to_string()));
pub fn pong(&mut self, message: &[u8]) {
self.write_raw(Message::Pong(Bytes::copy_from_slice(message)));
}
/// Send close frame
@@ -414,30 +419,34 @@ impl<A> Stream for WebsocketContextFut<A>
where
A: Actor<Context = WebsocketContext<A>>,
{
type Item = Bytes;
type Error = Error;
type Item = Result<Bytes, Error>;
fn poll(&mut self) -> Poll<Option<Bytes>, Error> {
if self.fut.alive() && self.fut.poll().is_err() {
return Err(ErrorInternalServerError("error"));
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Self::Item>> {
let this = self.get_mut();
if this.fut.alive() {
let _ = Pin::new(&mut this.fut).poll(cx);
}
// encode messages
while let Some(item) = self.fut.ctx().messages.pop_front() {
while let Some(item) = this.fut.ctx().messages.pop_front() {
if let Some(msg) = item {
self.encoder.encode(msg, &mut self.buf)?;
this.encoder.encode(msg, &mut this.buf)?;
} else {
self.closed = true;
this.closed = true;
break;
}
}
if !self.buf.is_empty() {
Ok(Async::Ready(Some(self.buf.take().freeze())))
} else if self.fut.alive() && !self.closed {
Ok(Async::NotReady)
if !this.buf.is_empty() {
Poll::Ready(Some(Ok(this.buf.split().freeze())))
} else if this.fut.alive() && !this.closed {
Poll::Pending
} else {
Ok(Async::Ready(None))
Poll::Ready(None)
}
}
}
@@ -453,7 +462,9 @@ where
}
}
#[pin_project::pin_project]
struct WsStream<S> {
#[pin]
stream: S,
decoder: Codec,
buf: BytesMut,
@@ -462,7 +473,7 @@ struct WsStream<S> {
impl<S> WsStream<S>
where
S: Stream<Item = Bytes, Error = PayloadError>,
S: Stream<Item = Result<Bytes, PayloadError>>,
{
fn new(stream: S, codec: Codec) -> Self {
Self {
@@ -476,62 +487,64 @@ where
impl<S> Stream for WsStream<S>
where
S: Stream<Item = Bytes, Error = PayloadError>,
S: Stream<Item = Result<Bytes, PayloadError>>,
{
type Item = Message;
type Error = ProtocolError;
type Item = Result<Message, ProtocolError>;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
if !self.closed {
fn poll_next(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Self::Item>> {
let mut this = self.as_mut().project();
if !*this.closed {
loop {
match self.stream.poll() {
Ok(Async::Ready(Some(chunk))) => {
self.buf.extend_from_slice(&chunk[..]);
this = self.as_mut().project();
match Pin::new(&mut this.stream).poll_next(cx) {
Poll::Ready(Some(Ok(chunk))) => {
this.buf.extend_from_slice(&chunk[..]);
}
Ok(Async::Ready(None)) => {
self.closed = true;
Poll::Ready(None) => {
*this.closed = true;
break;
}
Ok(Async::NotReady) => break,
Err(e) => {
return Err(ProtocolError::Io(io::Error::new(
io::ErrorKind::Other,
format!("{}", e),
)));
Poll::Pending => break,
Poll::Ready(Some(Err(e))) => {
return Poll::Ready(Some(Err(ProtocolError::Io(
io::Error::new(io::ErrorKind::Other, format!("{}", e)),
))));
}
}
}
}
match self.decoder.decode(&mut self.buf)? {
match this.decoder.decode(this.buf)? {
None => {
if self.closed {
Ok(Async::Ready(None))
if *this.closed {
Poll::Ready(None)
} else {
Ok(Async::NotReady)
Poll::Pending
}
}
Some(frm) => {
let msg = match frm {
Frame::Text(data) => {
if let Some(data) = data {
Message::Text(
std::str::from_utf8(&data)
.map_err(|_| ProtocolError::BadEncoding)?
.to_string(),
)
} else {
Message::Text(String::new())
}
}
Frame::Binary(data) => Message::Binary(
data.map(|b| b.freeze()).unwrap_or_else(Bytes::new),
Frame::Text(data) => Message::Text(
std::str::from_utf8(&data)
.map_err(|e| {
ProtocolError::Io(io::Error::new(
io::ErrorKind::Other,
format!("{}", e),
))
})?
.to_string(),
),
Frame::Binary(data) => Message::Binary(data),
Frame::Ping(s) => Message::Ping(s),
Frame::Pong(s) => Message::Pong(s),
Frame::Close(reason) => Message::Close(reason),
Frame::Continuation(item) => Message::Continuation(item),
};
Ok(Async::Ready(Some(msg)))
Poll::Ready(Some(Ok(msg)))
}
}
}
@@ -736,5 +749,46 @@ mod tests {
.headers()
.get(&header::SEC_WEBSOCKET_PROTOCOL)
);
let req = TestRequest::default()
.header(
header::UPGRADE,
header::HeaderValue::from_static("websocket"),
)
.header(
header::CONNECTION,
header::HeaderValue::from_static("upgrade"),
)
.header(
header::SEC_WEBSOCKET_VERSION,
header::HeaderValue::from_static("13"),
)
.header(
header::SEC_WEBSOCKET_KEY,
header::HeaderValue::from_static("13"),
)
.header(
header::SEC_WEBSOCKET_PROTOCOL,
header::HeaderValue::from_static("p1,p2,p3"),
)
.to_http_request();
let protocols = vec!["p3", "p2"];
assert_eq!(
StatusCode::SWITCHING_PROTOCOLS,
handshake_with_protocols(&req, &protocols)
.unwrap()
.finish()
.status()
);
assert_eq!(
Some(&header::HeaderValue::from_static("p2")),
handshake_with_protocols(&req, &protocols)
.unwrap()
.finish()
.headers()
.get(&header::SEC_WEBSOCKET_PROTOCOL)
);
}
}

View File

@@ -1,10 +1,8 @@
use actix::prelude::*;
use actix_http::HttpService;
use actix_http_test::TestServer;
use actix_web::{web, App, HttpRequest};
use actix_web::{test, web, App, HttpRequest};
use actix_web_actors::*;
use bytes::{Bytes, BytesMut};
use futures::{Sink, Stream};
use bytes::Bytes;
use futures::{SinkExt, StreamExt};
struct Ws;
@@ -12,9 +10,13 @@ impl Actor for Ws {
type Context = ws::WebsocketContext<Self>;
}
impl StreamHandler<ws::Message, ws::ProtocolError> for Ws {
fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
match msg {
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for Ws {
fn handle(
&mut self,
msg: Result<ws::Message, ws::ProtocolError>,
ctx: &mut Self::Context,
) {
match msg.unwrap() {
ws::Message::Ping(msg) => ctx.pong(&msg),
ws::Message::Text(text) => ctx.text(text),
ws::Message::Binary(bin) => ctx.binary(bin),
@@ -24,45 +26,42 @@ impl StreamHandler<ws::Message, ws::ProtocolError> for Ws {
}
}
#[test]
fn test_simple() {
let mut srv =
TestServer::new(|| {
HttpService::new(App::new().service(web::resource("/").to(
|req: HttpRequest, stream: web::Payload| ws::start(Ws, &req, stream),
)))
});
#[actix_rt::test]
async fn test_simple() {
let mut srv = test::start(|| {
App::new().service(web::resource("/").to(
|req: HttpRequest, stream: web::Payload| {
async move { ws::start(Ws, &req, stream) }
},
))
});
// client service
let framed = srv.ws().unwrap();
let framed = srv
.block_on(framed.send(ws::Message::Text("text".to_string())))
.unwrap();
let (item, framed) = srv.block_on(framed.into_future()).map_err(|_| ()).unwrap();
assert_eq!(item, Some(ws::Frame::Text(Some(BytesMut::from("text")))));
let framed = srv
.block_on(framed.send(ws::Message::Binary("text".into())))
.unwrap();
let (item, framed) = srv.block_on(framed.into_future()).map_err(|_| ()).unwrap();
assert_eq!(
item,
Some(ws::Frame::Binary(Some(Bytes::from_static(b"text").into())))
);
let framed = srv
.block_on(framed.send(ws::Message::Ping("text".into())))
.unwrap();
let (item, framed) = srv.block_on(framed.into_future()).map_err(|_| ()).unwrap();
assert_eq!(item, Some(ws::Frame::Pong("text".to_string().into())));
let framed = srv
.block_on(framed.send(ws::Message::Close(Some(ws::CloseCode::Normal.into()))))
let mut framed = srv.ws().await.unwrap();
framed
.send(ws::Message::Text("text".to_string()))
.await
.unwrap();
let (item, _framed) = srv.block_on(framed.into_future()).map_err(|_| ()).unwrap();
assert_eq!(
item,
Some(ws::Frame::Close(Some(ws::CloseCode::Normal.into())))
);
let item = framed.next().await.unwrap().unwrap();
assert_eq!(item, ws::Frame::Text(Bytes::from_static(b"text")));
framed
.send(ws::Message::Binary("text".into()))
.await
.unwrap();
let item = framed.next().await.unwrap().unwrap();
assert_eq!(item, ws::Frame::Binary(Bytes::from_static(b"text").into()));
framed.send(ws::Message::Ping("text".into())).await.unwrap();
let item = framed.next().await.unwrap().unwrap();
assert_eq!(item, ws::Frame::Pong(Bytes::copy_from_slice(b"text")));
framed
.send(ws::Message::Close(Some(ws::CloseCode::Normal.into())))
.await
.unwrap();
let item = framed.next().await.unwrap().unwrap();
assert_eq!(item, ws::Frame::Close(Some(ws::CloseCode::Normal.into())));
}

View File

@@ -1,5 +1,9 @@
# Changes
## [0.2.0] - 2019-12-13
* Generate code for actix-web 2.0
## [0.1.3] - 2019-10-14
* Bump up `syn` & `quote` to 1.0

View File

@@ -1,6 +1,6 @@
[package]
name = "actix-web-codegen"
version = "0.2.0-alpha.2"
version = "0.2.0"
description = "Actix web proc macros"
readme = "README.md"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
@@ -17,8 +17,6 @@ syn = { version = "^1", features = ["full", "parsing"] }
proc-macro2 = "^1"
[dev-dependencies]
actix-rt = { version = "1.0.0-alpha.2" }
actix-web = { version = "2.0.0-alpha.2" }
actix-http = { version = "0.3.0-alpha.2", features=["openssl"] }
actix-http-test = { version = "0.3.0-alpha.2", features=["openssl"] }
actix-rt = { version = "1.0.0" }
actix-web = { version = "2.0.0-rc" }
futures = { version = "0.3.1" }

View File

@@ -1,11 +1,9 @@
use actix_http::HttpService;
use actix_http_test::TestServer;
use actix_web::{http, web::Path, App, HttpResponse, Responder};
use actix_web::{http, test, web::Path, App, HttpResponse, Responder};
use actix_web_codegen::{connect, delete, get, head, options, patch, post, put, trace};
use futures::{future, Future};
#[get("/test")]
async fn test() -> impl Responder {
async fn test_handler() -> impl Responder {
HttpResponse::Ok()
}
@@ -71,14 +69,11 @@ async fn get_param_test(_: Path<String>) -> impl Responder {
#[actix_rt::test]
async fn test_params() {
let srv = TestServer::start(|| {
HttpService::new(
App::new()
.service(get_param_test)
.service(put_param_test)
.service(delete_param_test),
)
.tcp()
let srv = test::start(|| {
App::new()
.service(get_param_test)
.service(put_param_test)
.service(delete_param_test)
});
let request = srv.request(http::Method::GET, srv.url("/test/it"));
@@ -96,19 +91,16 @@ async fn test_params() {
#[actix_rt::test]
async fn test_body() {
let srv = TestServer::start(|| {
HttpService::new(
App::new()
.service(post_test)
.service(put_test)
.service(head_test)
.service(connect_test)
.service(options_test)
.service(trace_test)
.service(patch_test)
.service(test),
)
.tcp()
let srv = test::start(|| {
App::new()
.service(post_test)
.service(put_test)
.service(head_test)
.service(connect_test)
.service(options_test)
.service(trace_test)
.service(patch_test)
.service(test_handler)
});
let request = srv.request(http::Method::GET, srv.url("/test"));
let response = request.send().await.unwrap();
@@ -151,8 +143,7 @@ async fn test_body() {
#[actix_rt::test]
async fn test_auto_async() {
let srv =
TestServer::start(|| HttpService::new(App::new().service(auto_async)).tcp());
let srv = test::start(|| App::new().service(auto_async));
let request = srv.request(http::Method::GET, srv.url("/test"));
let response = request.send().await.unwrap();

View File

@@ -1,5 +1,14 @@
# Changes
## [1.0.1] - 2019-12-15
* Fix compilation with default features off
## [1.0.0] - 2019-12-13
* Release
## [1.0.0-alpha.3]
* Migrate to `std::future`

View File

@@ -1,6 +1,6 @@
[package]
name = "awc"
version = "1.0.0-alpha.3"
version = "1.0.1"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix http client."
readme = "README.md"
@@ -12,19 +12,17 @@ categories = ["network-programming", "asynchronous",
"web-programming::http-client",
"web-programming::websocket"]
license = "MIT/Apache-2.0"
exclude = [".gitignore", ".travis.yml", ".cargo/config", "appveyor.yml"]
edition = "2018"
workspace = ".."
[lib]
name = "awc"
path = "src/lib.rs"
[package.metadata.docs.rs]
features = ["openssl", "rustls", "brotli", "flate2-zlib"]
features = ["openssl", "rustls", "compress"]
[features]
default = ["brotli", "flate2-zlib"]
default = ["compress"]
# openssl
openssl = ["open-ssl", "actix-http/openssl"]
@@ -32,25 +30,19 @@ openssl = ["open-ssl", "actix-http/openssl"]
# rustls
rustls = ["rust-tls", "actix-http/rustls"]
# brotli encoding, requires c compiler
brotli = ["actix-http/brotli"]
# miniz-sys backend for flate2 crate
flate2-zlib = ["actix-http/flate2-zlib"]
# rust backend for flate2 crate
flate2-rust = ["actix-http/flate2-rust"]
# content-encoding support
compress = ["actix-http/compress"]
[dependencies]
actix-codec = "0.2.0-alpha.3"
actix-service = "1.0.0-alpha.3"
actix-http = "1.0.0-alpha.3"
actix-rt = "1.0.0-alpha.3"
actix-codec = "0.2.0"
actix-service = "1.0.0"
actix-http = "1.0.0"
actix-rt = "1.0.0"
base64 = "0.11"
bytes = "0.5.2"
bytes = "0.5.3"
derive_more = "0.99.2"
futures = "0.3.1"
futures-core = "0.3.1"
log =" 0.4"
mime = "0.3"
percent-encoding = "2.1"
@@ -62,14 +54,15 @@ open-ssl = { version="0.10", package="openssl", optional = true }
rust-tls = { version = "0.16.0", package="rustls", optional = true, features = ["dangerous_configuration"] }
[dev-dependencies]
actix-connect = { version = "1.0.0-alpha.3", features=["openssl"] }
actix-web = { version = "2.0.0-alpha.3", features=["openssl"] }
actix-http = { version = "1.0.0-alpha.3", features=["openssl"] }
actix-http-test = { version = "1.0.0-alpha.3", features=["openssl"] }
actix-utils = "1.0.0-alpha.3"
actix-server = { version = "1.0.0-alpha.3" }
actix-tls = { version = "1.0.0-alpha.3", features=["openssl", "rustls"] }
brotli2 = { version="0.3.2" }
flate2 = { version="1.0.2" }
actix-connect = { version = "1.0.1", features=["openssl"] }
actix-web = { version = "2.0.0-rc", features=["openssl"] }
actix-http = { version = "1.0.1", features=["openssl"] }
actix-http-test = { version = "1.0.0", features=["openssl"] }
actix-utils = "1.0.3"
actix-server = "1.0.0"
actix-tls = { version = "1.0.0", features=["openssl", "rustls"] }
brotli2 = "0.3.2"
flate2 = "1.0.13"
futures = "0.3.1"
env_logger = "0.6"
webpki = { version = "0.21" }
webpki = "0.21"

View File

@@ -1,3 +1,4 @@
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll};
@@ -12,7 +13,6 @@ use actix_http::h1::ClientCodec;
use actix_http::http::HeaderMap;
use actix_http::{RequestHead, RequestHeadType, ResponseHead};
use actix_service::Service;
use futures::future::{FutureExt, LocalBoxFuture};
use crate::response::ClientResponse;
@@ -24,7 +24,7 @@ pub(crate) trait Connect {
head: RequestHead,
body: Body,
addr: Option<net::SocketAddr>,
) -> LocalBoxFuture<'static, Result<ClientResponse, SendRequestError>>;
) -> Pin<Box<dyn Future<Output = Result<ClientResponse, SendRequestError>>>>;
fn send_request_extra(
&mut self,
@@ -32,16 +32,22 @@ pub(crate) trait Connect {
extra_headers: Option<HeaderMap>,
body: Body,
addr: Option<net::SocketAddr>,
) -> LocalBoxFuture<'static, Result<ClientResponse, SendRequestError>>;
) -> Pin<Box<dyn Future<Output = Result<ClientResponse, SendRequestError>>>>;
/// Send request, returns Response and Framed
fn open_tunnel(
&mut self,
head: RequestHead,
addr: Option<net::SocketAddr>,
) -> LocalBoxFuture<
'static,
Result<(ResponseHead, Framed<BoxedSocket, ClientCodec>), SendRequestError>,
) -> Pin<
Box<
dyn Future<
Output = Result<
(ResponseHead, Framed<BoxedSocket, ClientCodec>),
SendRequestError,
>,
>,
>,
>;
/// Send request and extra headers, returns Response and Framed
@@ -50,9 +56,15 @@ pub(crate) trait Connect {
head: Rc<RequestHead>,
extra_headers: Option<HeaderMap>,
addr: Option<net::SocketAddr>,
) -> LocalBoxFuture<
'static,
Result<(ResponseHead, Framed<BoxedSocket, ClientCodec>), SendRequestError>,
) -> Pin<
Box<
dyn Future<
Output = Result<
(ResponseHead, Framed<BoxedSocket, ClientCodec>),
SendRequestError,
>,
>,
>,
>;
}
@@ -70,14 +82,14 @@ where
head: RequestHead,
body: Body,
addr: Option<net::SocketAddr>,
) -> LocalBoxFuture<'static, Result<ClientResponse, SendRequestError>> {
) -> Pin<Box<dyn Future<Output = Result<ClientResponse, SendRequestError>>>> {
// connect to the host
let fut = self.0.call(ClientConnect {
uri: head.uri.clone(),
addr,
});
async move {
Box::pin(async move {
let connection = fut.await?;
// send request
@@ -85,8 +97,7 @@ where
.send_request(RequestHeadType::from(head), body)
.await
.map(|(head, payload)| ClientResponse::new(head, payload))
}
.boxed_local()
})
}
fn send_request_extra(
@@ -95,14 +106,14 @@ where
extra_headers: Option<HeaderMap>,
body: Body,
addr: Option<net::SocketAddr>,
) -> LocalBoxFuture<'static, Result<ClientResponse, SendRequestError>> {
) -> Pin<Box<dyn Future<Output = Result<ClientResponse, SendRequestError>>>> {
// connect to the host
let fut = self.0.call(ClientConnect {
uri: head.uri.clone(),
addr,
});
async move {
Box::pin(async move {
let connection = fut.await?;
// send request
@@ -111,17 +122,22 @@ where
.await?;
Ok(ClientResponse::new(head, payload))
}
.boxed_local()
})
}
fn open_tunnel(
&mut self,
head: RequestHead,
addr: Option<net::SocketAddr>,
) -> LocalBoxFuture<
'static,
Result<(ResponseHead, Framed<BoxedSocket, ClientCodec>), SendRequestError>,
) -> Pin<
Box<
dyn Future<
Output = Result<
(ResponseHead, Framed<BoxedSocket, ClientCodec>),
SendRequestError,
>,
>,
>,
> {
// connect to the host
let fut = self.0.call(ClientConnect {
@@ -129,7 +145,7 @@ where
addr,
});
async move {
Box::pin(async move {
let connection = fut.await?;
// send request
@@ -138,8 +154,7 @@ where
let framed = framed.map_io(|io| BoxedSocket(Box::new(Socket(io))));
Ok((head, framed))
}
.boxed_local()
})
}
fn open_tunnel_extra(
@@ -147,9 +162,15 @@ where
head: Rc<RequestHead>,
extra_headers: Option<HeaderMap>,
addr: Option<net::SocketAddr>,
) -> LocalBoxFuture<
'static,
Result<(ResponseHead, Framed<BoxedSocket, ClientCodec>), SendRequestError>,
) -> Pin<
Box<
dyn Future<
Output = Result<
(ResponseHead, Framed<BoxedSocket, ClientCodec>),
SendRequestError,
>,
>,
>,
> {
// connect to the host
let fut = self.0.call(ClientConnect {
@@ -157,7 +178,7 @@ where
addr,
});
async move {
Box::pin(async move {
let connection = fut.await?;
// send request
@@ -167,8 +188,7 @@ where
let framed = framed.map_io(|io| BoxedSocket(Box::new(Socket(io))));
Ok((head, framed))
}
.boxed_local()
})
}
}
@@ -195,7 +215,7 @@ impl<T: AsyncRead + AsyncWrite + Unpin> AsyncSocket for Socket<T> {
pub struct BoxedSocket(Box<dyn AsyncSocket>);
impl fmt::Debug for BoxedSocket {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "BoxedSocket")
}
}

View File

@@ -4,7 +4,7 @@ use std::rc::Rc;
use std::time::Duration;
use bytes::Bytes;
use futures::Stream;
use futures_core::Stream;
use serde::Serialize;
use actix_http::body::Body;

View File

@@ -1,4 +1,9 @@
#![allow(clippy::borrow_interior_mutable_const)]
#![deny(rust_2018_idioms, warnings)]
#![allow(
clippy::type_complexity,
clippy::borrow_interior_mutable_const,
clippy::needless_doctest_main
)]
//! An HTTP Client
//!
//! ```rust
@@ -11,9 +16,9 @@
//! let mut client = Client::default();
//!
//! let response = client.get("http://www.rust-lang.org") // <- Create request builder
//! .header("User-Agent", "Actix-web")
//! .send() // <- Send http request
//! .await;
//! .header("User-Agent", "Actix-web")
//! .send() // <- Send http request
//! .await;
//!
//! println!("Response: {:?}", response);
//! }
@@ -50,22 +55,18 @@ use self::connect::{Connect, ConnectorWrapper};
/// An HTTP Client
///
/// ```rust
/// use actix_rt::System;
/// use awc::Client;
///
/// fn main() {
/// System::new("test").block_on(async {
/// let mut client = Client::default();
/// #[actix_rt::main]
/// async fn main() {
/// let mut client = Client::default();
///
/// client.get("http://www.rust-lang.org") // <- Create request builder
/// .header("User-Agent", "Actix-web")
/// .send() // <- Send http request
/// .await
/// .and_then(|response| { // <- server http response
/// println!("Response: {:?}", response);
/// Ok(())
/// })
/// });
/// let res = client.get("http://www.rust-lang.org") // <- Create request builder
/// .header("User-Agent", "Actix-web")
/// .send() // <- Send http request
/// .await; // <- send request and wait for response
///
/// println!("Response: {:?}", res);
/// }
/// ```
#[derive(Clone)]

Some files were not shown because too many files have changed in this diff Show More