diff --git a/CHANGES.md b/CHANGES.md index a7569862d..600dc8e15 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,12 @@ # Changes +## [2.0.0-alpha.3] - 2019-12-xx + +### Changed + +* Migrate to tokio 0.2 + + ## [2.0.0-alpha.1] - 2019-11-22 ### Changed diff --git a/Cargo.toml b/Cargo.toml index d5b16844d..ee3158a15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-web" -version = "2.0.0-alpha.2" +version = "2.0.0-alpha.3" authors = ["Nikolay Kim "] description = "Actix web is a simple, pragmatic and extremely fast web framework for Rust." readme = "README.md" @@ -66,24 +66,24 @@ fail = ["actix-http/fail"] openssl = ["open-ssl", "actix-tls/openssl", "awc/openssl"] # rustls -# rustls = ["rust-tls", "actix-server/rustls", "awc/rustls"] +rustls = ["rust-tls", "actix-tls/rustls", "awc/rustls"] [dependencies] -actix-codec = "0.2.0-alpha.2" -actix-service = "1.0.0-alpha.2" -actix-utils = "1.0.0-alpha.2" -actix-router = "0.1.5" -actix-rt = "1.0.0-alpha.2" -actix-server = "1.0.0-alpha.2" -actix-testing = "1.0.0-alpha.2" +actix-codec = "0.2.0-alpha.3" +actix-service = "1.0.0-alpha.3" +actix-utils = "1.0.0-alpha.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-threadpool = "0.3.0" -actix-tls = { version = "1.0.0-alpha.1" } +actix-tls = { version = "1.0.0-alpha.3" } actix-web-codegen = "0.2.0-alpha.2" actix-http = "0.3.0-alpha.2" awc = { version = "0.3.0-alpha.2", optional = true } -bytes = "0.4" +bytes = "0.5.2" derive_more = "0.99.2" encoding_rs = "0.8" futures = "0.3.1" @@ -102,7 +102,7 @@ url = "2.1" # ssl support open-ssl = { version="0.10", package="openssl", optional = true } -# rust-tls = { version = "0.16", package="rustls", optional = true } +rust-tls = { version = "0.16", package="rustls", optional = true } [dev-dependencies] # actix = "0.8.3" @@ -130,3 +130,13 @@ actix-session = { path = "actix-session" } actix-files = { path = "actix-files" } actix-multipart = { path = "actix-multipart" } awc = { path = "awc" } + +actix-codec = { git = "https://github.com/actix/actix-net.git" } +actix-connect = { git = "https://github.com/actix/actix-net.git" } +actix-rt = { git = "https://github.com/actix/actix-net.git" } +actix-server = { git = "https://github.com/actix/actix-net.git" } +actix-service = { git = "https://github.com/actix/actix-net.git" } +actix-testing = { git = "https://github.com/actix/actix-net.git" } +actix-tls = { git = "https://github.com/actix/actix-net.git" } +actix-utils = { git = "https://github.com/actix/actix-net.git" } +actix-router = { git = "https://github.com/actix/actix-net.git" } diff --git a/actix-cors/CHANGES.md b/actix-cors/CHANGES.md index 10e408ede..92e3b697b 100644 --- a/actix-cors/CHANGES.md +++ b/actix-cors/CHANGES.md @@ -1,8 +1,10 @@ # Changes -## [0.1.1] - unreleased +## [0.2.0-alpha.3] - unreleased -* Bump `derive_more` crate version to 0.15.0 +* Migrate to actix-web 2.0.0 + +* Bump `derive_more` crate version to 0.99.0 ## [0.1.0] - 2019-06-15 diff --git a/actix-cors/Cargo.toml b/actix-cors/Cargo.toml index bc8c7d805..976d0be7f 100644 --- a/actix-cors/Cargo.toml +++ b/actix-cors/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-cors" -version = "0.2.0-alpha.1" +version = "0.2.0-alpha.3" authors = ["Nikolay Kim "] description = "Cross-origin resource sharing (CORS) for Actix applications." readme = "README.md" diff --git a/actix-cors/src/lib.rs b/actix-cors/src/lib.rs index d3607aa8e..71d98f896 100644 --- a/actix-cors/src/lib.rs +++ b/actix-cors/src/lib.rs @@ -40,6 +40,7 @@ //! //! Cors middleware automatically handle *OPTIONS* preflight request. use std::collections::HashSet; +use std::convert::TryFrom; use std::iter::FromIterator; use std::rc::Rc; use std::task::{Context, Poll}; @@ -48,7 +49,7 @@ use actix_service::{Service, Transform}; use actix_web::dev::{RequestHead, ServiceRequest, ServiceResponse}; use actix_web::error::{Error, ResponseError, Result}; use actix_web::http::header::{self, HeaderName, HeaderValue}; -use actix_web::http::{self, HttpTryFrom, Method, StatusCode, Uri}; +use actix_web::http::{self, Error as HttpError, Method, StatusCode, Uri}; use actix_web::HttpResponse; use derive_more::Display; use futures::future::{ok, Either, FutureExt, LocalBoxFuture, Ready}; @@ -274,7 +275,8 @@ impl Cors { pub fn allowed_methods(mut self, methods: U) -> Cors where U: IntoIterator, - Method: HttpTryFrom, + Method: TryFrom, + >::Error: Into, { self.methods = true; if let Some(cors) = cors(&mut self.cors, &self.error) { @@ -296,7 +298,8 @@ impl Cors { /// Set an allowed header pub fn allowed_header(mut self, header: H) -> Cors where - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, { if let Some(cors) = cors(&mut self.cors, &self.error) { match HeaderName::try_from(header) { @@ -328,7 +331,8 @@ impl Cors { pub fn allowed_headers(mut self, headers: U) -> Cors where U: IntoIterator, - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, { if let Some(cors) = cors(&mut self.cors, &self.error) { for h in headers { @@ -362,7 +366,8 @@ impl Cors { pub fn expose_headers(mut self, headers: U) -> Cors where U: IntoIterator, - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, { for h in headers { match HeaderName::try_from(h) { diff --git a/actix-files/Cargo.toml b/actix-files/Cargo.toml index 55078adb7..261bf14e3 100644 --- a/actix-files/Cargo.toml +++ b/actix-files/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-files" -version = "0.2.0-alpha.2" +version = "0.2.0-alpha.3" authors = ["Nikolay Kim "] description = "Static files support for actix web." readme = "README.md" @@ -20,9 +20,9 @@ path = "src/lib.rs" [dependencies] actix-web = { version = "2.0.0-alpha.2", default-features = false } actix-http = "0.3.0-alpha.2" -actix-service = "1.0.0-alpha.2" +actix-service = "1.0.0-alpha.3" bitflags = "1" -bytes = "0.4" +bytes = "0.5.2" futures = "0.3.1" derive_more = "0.99.2" log = "0.4" diff --git a/actix-framed/Cargo.toml b/actix-framed/Cargo.toml index 55bc1a24c..0b80266aa 100644 --- a/actix-framed/Cargo.toml +++ b/actix-framed/Cargo.toml @@ -20,19 +20,19 @@ name = "actix_framed" path = "src/lib.rs" [dependencies] -actix-codec = "0.2.0-alpha.2" -actix-service = "1.0.0-alpha.2" -actix-router = "0.1.2" -actix-rt = "1.0.0-alpha.2" -actix-http = "0.3.0-alpha.2" +actix-codec = "0.2.0-alpha.3" +actix-service = "1.0.0-alpha.3" +actix-router = "0.2.0" +actix-rt = "1.0.0-alpha.3" +actix-http = "0.3.0-alpha.3" -bytes = "0.4" +bytes = "0.5.2" futures = "0.3.1" pin-project = "0.4.6" log = "0.4" [dev-dependencies] -actix-server = { version = "1.0.0-alpha.2" } -actix-connect = { version = "1.0.0-alpha.2", features=["openssl"] } -actix-http-test = { version = "0.3.0-alpha.2", features=["openssl"] } -actix-utils = "1.0.0-alpha.2" +actix-server = { version = "1.0.0-alpha.3" } +actix-connect = { version = "1.0.0-alpha.3", features=["openssl"] } +actix-http-test = { version = "0.3.0-alpha.3", features=["openssl"] } +actix-utils = "1.0.0-alpha.3" diff --git a/actix-framed/src/request.rs b/actix-framed/src/request.rs index bdcdd7026..1872dcc25 100644 --- a/actix-framed/src/request.rs +++ b/actix-framed/src/request.rs @@ -123,7 +123,9 @@ impl FramedRequest { #[cfg(test)] mod tests { - use actix_http::http::{HeaderName, HeaderValue, HttpTryFrom}; + use std::convert::TryFrom; + + use actix_http::http::{HeaderName, HeaderValue}; use actix_http::test::{TestBuffer, TestRequest}; use super::*; diff --git a/actix-framed/src/test.rs b/actix-framed/src/test.rs index 7969d51ff..b8029531e 100644 --- a/actix-framed/src/test.rs +++ b/actix-framed/src/test.rs @@ -1,10 +1,11 @@ //! Various helpers for Actix applications to use during testing. +use std::convert::TryFrom; use std::future::Future; use actix_codec::Framed; use actix_http::h1::Codec; use actix_http::http::header::{Header, HeaderName, IntoHeaderValue}; -use actix_http::http::{HttpTryFrom, Method, Uri, Version}; +use actix_http::http::{Error as HttpError, Method, Uri, Version}; use actix_http::test::{TestBuffer, TestRequest as HttpTestRequest}; use actix_router::{Path, Url}; @@ -41,7 +42,8 @@ impl TestRequest<()> { /// Create TestRequest and set header pub fn with_header(key: K, value: V) -> Self where - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, V: IntoHeaderValue, { Self::default().header(key, value) @@ -96,7 +98,8 @@ impl TestRequest { /// Set a header pub fn header(mut self, key: K, value: V) -> Self where - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, V: IntoHeaderValue, { self.req.header(key, value); diff --git a/actix-framed/tests/test_server.rs b/actix-framed/tests/test_server.rs index c272f0f93..40e698c70 100644 --- a/actix-framed/tests/test_server.rs +++ b/actix-framed/tests/test_server.rs @@ -3,7 +3,7 @@ use actix_http::{body, http::StatusCode, ws, Error, HttpService, Response}; use actix_http_test::TestServer; use actix_service::{pipeline_factory, IntoServiceFactory, ServiceFactory}; use actix_utils::framed::FramedTransport; -use bytes::{Bytes, BytesMut}; +use bytes::BytesMut; use futures::{future, SinkExt, StreamExt}; use actix_framed::{FramedApp, FramedRequest, FramedRoute, SendError, VerifyWebSockets}; @@ -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(Bytes::from_static(b"text").into())) + ws::Frame::Binary(Some(BytesMut::from(&b"text"[..]))) ); framed.send(ws::Message::Ping("text".into())).await.unwrap(); @@ -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(Bytes::from_static(b"text").into())) + ws::Frame::Binary(Some(BytesMut::from(&b"text"[..]))) ); framed.send(ws::Message::Ping("text".into())).await.unwrap(); diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml index d81c46119..aadef9e3c 100644 --- a/actix-http/Cargo.toml +++ b/actix-http/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-http" -version = "0.3.0-alpha.2" +version = "0.3.0-alpha.3" authors = ["Nikolay Kim "] description = "Actix http primitives" readme = "README.md" @@ -16,7 +16,7 @@ edition = "2018" workspace = ".." [package.metadata.docs.rs] -features = ["openssl", "fail", "brotli", "flate2-zlib", "secure-cookies"] +features = ["openssl", "rustls", "fail", "brotli", "flate2-zlib", "secure-cookies"] [lib] name = "actix_http" @@ -26,10 +26,10 @@ path = "src/lib.rs" default = [] # openssl -openssl = ["open-ssl", "actix-tls/openssl", "actix-connect/openssl", "tokio-openssl"] +openssl = ["actix-tls/openssl", "actix-connect/openssl"] # rustls support -# rustls = ["rust-tls", "webpki-roots", "actix-connect/rustls"] +rustls = ["actix-tls/rustls", "actix-connect/rustls"] # brotli encoding, requires c compiler brotli = ["brotli2"] @@ -47,17 +47,17 @@ fail = ["failure"] secure-cookies = ["ring"] [dependencies] -actix-service = "1.0.0-alpha.2" -actix-codec = "0.2.0-alpha.2" -actix-connect = "1.0.0-alpha.2" -actix-utils = "1.0.0-alpha.2" -actix-rt = "1.0.0-alpha.2" +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.1", optional = true } +actix-tls = { version = "1.0.0-alpha.3", optional = true } base64 = "0.11" bitflags = "1.0" -bytes = "0.4" +bytes = "0.5.2" copyless = "0.1.4" chrono = "0.4.6" derive_more = "0.99.2" @@ -65,8 +65,8 @@ either = "1.5.2" encoding_rs = "0.8" futures = "0.3.1" fxhash = "0.2.1" -h2 = "0.2.0-alpha.3" -http = "0.1.17" +h2 = "0.2.0" +http = "0.2.0" httparse = "1.3" indexmap = "1.2" lazy_static = "1.0" @@ -76,14 +76,13 @@ mime = "0.3" percent-encoding = "2.1" pin-project = "0.4.6" rand = "0.7" -regex = "1.0" +regex = "1.3" serde = "1.0" serde_json = "1.0" sha1 = "0.6" slab = "0.4" serde_urlencoded = "0.6.1" time = "0.1.42" -trust-dns-resolver = { version="0.18.0-alpha.1", default-features = false } # for secure cookie ring = { version = "0.16.9", optional = true } @@ -94,17 +93,13 @@ flate2 = { version="1.0.7", optional = true, default-features = false } # optional deps failure = { version = "0.1.5", optional = true } -open-ssl = { version="0.10", package="openssl", optional = true } -tokio-openssl = { version = "0.4.0-alpha.6", optional = true } - -# rust-tls = { version = "0.16.0", package="rustls", optional = true } -# webpki-roots = { version = "0.18", optional = true } [dev-dependencies] -actix-server = { version = "1.0.0-alpha.2" } -actix-connect = { version = "1.0.0-alpha.2", features=["openssl"] } -actix-http-test = { version = "0.3.0-alpha.2", features=["openssl"] } -actix-tls = { version = "1.0.0-alpha.1", features=["openssl"] } +actix-server = { version = "1.0.0-alpha.3" } +actix-connect = { version = "1.0.0-alpha.3", features=["openssl"] } +actix-http-test = { version = "0.3.0-alpha.3", features=["openssl"] } +actix-tls = { version = "1.0.0-alpha.3", features=["openssl"] } env_logger = "0.6" serde_derive = "1.0" -open-ssl = { version="0.10", package="openssl" } +open-ssl = { version="0.10", package = "openssl" } +rust-tls = { version="0.16", package = "rustls" } diff --git a/actix-http/src/body.rs b/actix-http/src/body.rs index b69c21eaa..ff7235626 100644 --- a/actix-http/src/body.rs +++ b/actix-http/src/body.rs @@ -133,7 +133,7 @@ pub enum Body { impl Body { /// Create body from slice (copy) pub fn from_slice(s: &[u8]) -> Body { - Body::Bytes(Bytes::from(s)) + Body::Bytes(Bytes::copy_from_slice(s)) } /// Create body from generic message body. @@ -226,7 +226,7 @@ impl From for Body { impl<'a> From<&'a String> for Body { fn from(s: &'a String) -> Body { - Body::Bytes(Bytes::from(AsRef::<[u8]>::as_ref(&s))) + Body::Bytes(Bytes::copy_from_slice(AsRef::<[u8]>::as_ref(&s))) } } diff --git a/actix-http/src/client/connection.rs b/actix-http/src/client/connection.rs index 75d393b1b..9b590690f 100644 --- a/actix-http/src/client/connection.rs +++ b/actix-http/src/client/connection.rs @@ -1,6 +1,6 @@ use std::pin::Pin; use std::task::{Context, Poll}; -use std::{fmt, io, time}; +use std::{fmt, io, mem, time}; use actix_codec::{AsyncRead, AsyncWrite, Framed}; use bytes::{Buf, Bytes}; @@ -228,7 +228,10 @@ where } } - unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { + unsafe fn prepare_uninitialized_buffer( + &self, + buf: &mut [mem::MaybeUninit], + ) -> bool { match self { EitherIo::A(ref val) => val.prepare_uninitialized_buffer(buf), EitherIo::B(ref val) => val.prepare_uninitialized_buffer(buf), diff --git a/actix-http/src/client/connector.rs b/actix-http/src/client/connector.rs index fb43733cf..2710252e3 100644 --- a/actix-http/src/client/connector.rs +++ b/actix-http/src/client/connector.rs @@ -17,10 +17,10 @@ use super::pool::{ConnectionPool, Protocol}; use super::Connect; #[cfg(feature = "openssl")] -use open_ssl::ssl::SslConnector as OpensslConnector; +use actix_connect::ssl::openssl::SslConnector as OpensslConnector; #[cfg(feature = "rustls")] -use rust_tls::ClientConfig; +use actix_connect::ssl::rustls::ClientConfig; #[cfg(feature = "rustls")] use std::sync::Arc; @@ -74,7 +74,7 @@ impl Connector<(), ()> { let ssl = { #[cfg(feature = "openssl")] { - use open_ssl::ssl::SslMethod; + use actix_connect::ssl::openssl::SslMethod; let mut ssl = OpensslConnector::builder(SslMethod::tls()).unwrap(); let _ = ssl @@ -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(&webpki_roots::TLS_SERVER_ROOTS); + config.root_store.add_server_trust_anchors( + &actix_connect::ssl::rustls::TLS_SERVER_ROOTS, + ); SslConnector::Rustls(Arc::new(config)) } #[cfg(not(any(feature = "openssl", feature = "rustls")))] @@ -242,12 +242,10 @@ where { const H2: &[u8] = b"h2"; #[cfg(feature = "openssl")] - use actix_connect::ssl::OpensslConnector; + use actix_connect::ssl::openssl::OpensslConnector; #[cfg(feature = "rustls")] - use actix_connect::ssl::RustlsConnector; + use actix_connect::ssl::rustls::{RustlsConnector, Session}; use actix_service::{boxed::service, pipeline}; - #[cfg(feature = "rustls")] - use rust_tls::Session; let ssl_service = TimeoutService::new( self.timeout, diff --git a/actix-http/src/client/error.rs b/actix-http/src/client/error.rs index ee568e8be..42ea47ee8 100644 --- a/actix-http/src/client/error.rs +++ b/actix-http/src/client/error.rs @@ -1,10 +1,10 @@ use std::io; +use actix_connect::resolver::ResolveError; use derive_more::{Display, From}; -use trust_dns_resolver::error::ResolveError; #[cfg(feature = "openssl")] -use open_ssl::ssl::{Error as SslError, HandshakeError}; +use actix_connect::ssl::openssl::{HandshakeError, SslError}; use crate::error::{Error, ParseError, ResponseError}; use crate::http::{Error as HttpError, StatusCode}; @@ -21,6 +21,11 @@ pub enum ConnectError { #[display(fmt = "{}", _0)] SslError(SslError), + /// SSL Handshake error + #[cfg(feature = "openssl")] + #[display(fmt = "{}", _0)] + SslHandshakeError(String), + /// Failed to resolve the hostname #[display(fmt = "Failed resolving hostname: {}", _0)] Resolver(ResolveError), @@ -63,13 +68,9 @@ impl From for ConnectError { } #[cfg(feature = "openssl")] -impl From> for ConnectError { +impl From> for ConnectError { fn from(err: HandshakeError) -> ConnectError { - match err { - HandshakeError::SetupFailure(stack) => SslError::from(stack).into(), - HandshakeError::Failure(stream) => stream.into_error().into(), - HandshakeError::WouldBlock(stream) => stream.into_error().into(), - } + ConnectError::SslHandshakeError(format!("{:?}", err)) } } diff --git a/actix-http/src/client/h1proto.rs b/actix-http/src/client/h1proto.rs index ddfc7a314..048d3795c 100644 --- a/actix-http/src/client/h1proto.rs +++ b/actix-http/src/client/h1proto.rs @@ -1,10 +1,11 @@ use std::io::Write; use std::pin::Pin; use std::task::{Context, Poll}; -use std::{io, time}; +use std::{io, mem, time}; use actix_codec::{AsyncRead, AsyncWrite, Framed}; -use bytes::{BufMut, Bytes, BytesMut}; +use bytes::buf::BufMutExt; +use bytes::{Bytes, BytesMut}; use futures::future::poll_fn; use futures::{SinkExt, Stream, StreamExt}; @@ -43,7 +44,7 @@ where Some(port) => write!(wrt, "{}:{}", host, port), }; - match wrt.get_mut().take().freeze().try_into() { + match wrt.get_mut().split().freeze().try_into() { Ok(value) => match head { RequestHeadType::Owned(ref mut head) => { head.headers.insert(HOST, value) @@ -199,7 +200,10 @@ where } impl AsyncRead for H1Connection { - unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { + unsafe fn prepare_uninitialized_buffer( + &self, + buf: &mut [mem::MaybeUninit], + ) -> bool { self.io.as_ref().unwrap().prepare_uninitialized_buffer(buf) } diff --git a/actix-http/src/client/h2proto.rs b/actix-http/src/client/h2proto.rs index a94562f2d..ff8f21d00 100644 --- a/actix-http/src/client/h2proto.rs +++ b/actix-http/src/client/h2proto.rs @@ -1,3 +1,4 @@ +use std::convert::TryFrom; use std::time; use actix_codec::{AsyncRead, AsyncWrite}; @@ -5,7 +6,7 @@ use bytes::Bytes; use futures::future::poll_fn; use h2::{client::SendRequest, SendStream}; use http::header::{HeaderValue, CONNECTION, CONTENT_LENGTH, TRANSFER_ENCODING}; -use http::{request::Request, HttpTryFrom, Method, Version}; +use http::{request::Request, Method, Version}; use crate::body::{BodySize, MessageBody}; use crate::header::HeaderMap; diff --git a/actix-http/src/client/pool.rs b/actix-http/src/client/pool.rs index 938ccb5d0..ef5bd5965 100644 --- a/actix-http/src/client/pool.rs +++ b/actix-http/src/client/pool.rs @@ -108,7 +108,7 @@ where let inner = self.1.clone(); let fut = async move { - let key = if let Some(authority) = req.uri.authority_part() { + let key = if let Some(authority) = req.uri.authority() { authority.clone().into() } else { return Err(ConnectError::Unresolverd); @@ -299,7 +299,7 @@ where ) { let (tx, rx) = oneshot::channel(); - let key: Key = connect.uri.authority_part().unwrap().clone().into(); + let key: Key = connect.uri.authority().unwrap().clone().into(); let entry = self.waiters.vacant_entry(); let token = entry.key(); entry.insert(Some((connect, tx))); diff --git a/actix-http/src/config.rs b/actix-http/src/config.rs index 6ea75e565..77633bdc2 100644 --- a/actix-http/src/config.rs +++ b/actix-http/src/config.rs @@ -1,10 +1,10 @@ use std::cell::UnsafeCell; use std::fmt::Write; use std::rc::Rc; -use std::time::{Duration, Instant}; +use std::time::Duration; use std::{fmt, net}; -use actix_rt::time::{delay, delay_for, Delay}; +use actix_rt::time::{delay_for, delay_until, Delay, Instant}; use bytes::BytesMut; use futures::{future, FutureExt}; use time; @@ -124,7 +124,7 @@ impl ServiceConfig { pub fn client_timer(&self) -> Option { let delay_time = self.0.client_timeout; if delay_time != 0 { - Some(delay( + Some(delay_until( self.0.timer.now() + Duration::from_millis(delay_time), )) } else { @@ -156,7 +156,7 @@ impl ServiceConfig { /// Return keep-alive timer delay is configured. pub fn keep_alive_timer(&self) -> Option { if let Some(ka) = self.0.keep_alive { - Some(delay(self.0.timer.now() + ka)) + Some(delay_until(self.0.timer.now() + ka)) } else { None } diff --git a/actix-http/src/encoding/encoder.rs b/actix-http/src/encoding/encoder.rs index f561ab0c4..d1b64bfb8 100644 --- a/actix-http/src/encoding/encoder.rs +++ b/actix-http/src/encoding/encoder.rs @@ -13,7 +13,7 @@ use flate2::write::{GzEncoder, ZlibEncoder}; use crate::body::{Body, BodySize, MessageBody, ResponseBody}; use crate::http::header::{ContentEncoding, CONTENT_ENCODING}; -use crate::http::{HeaderValue, HttpTryFrom, StatusCode}; +use crate::http::{HeaderValue, StatusCode}; use crate::{Error, ResponseHead}; use super::Writer; @@ -168,7 +168,7 @@ impl MessageBody for Encoder { fn update_head(encoding: ContentEncoding, head: &mut ResponseHead) { head.headers_mut().insert( CONTENT_ENCODING, - HeaderValue::try_from(Bytes::from_static(encoding.as_str().as_bytes())).unwrap(), + HeaderValue::from_static(encoding.as_str()), ); } diff --git a/actix-http/src/encoding/mod.rs b/actix-http/src/encoding/mod.rs index b55a43a7c..9f65f800c 100644 --- a/actix-http/src/encoding/mod.rs +++ b/actix-http/src/encoding/mod.rs @@ -20,7 +20,7 @@ impl Writer { } } fn take(&mut self) -> Bytes { - self.buf.take().freeze() + self.buf.split().freeze() } } diff --git a/actix-http/src/error.rs b/actix-http/src/error.rs index 2c09142e0..c580f3846 100644 --- a/actix-http/src/error.rs +++ b/actix-http/src/error.rs @@ -113,12 +113,6 @@ impl fmt::Debug for Error { } } -impl From<()> for Error { - fn from(_: ()) -> Self { - Error::from(UnitError) - } -} - impl std::error::Error for Error { fn description(&self) -> &str { "actix-http::Error" @@ -133,6 +127,12 @@ impl std::error::Error for Error { } } +impl From<()> for Error { + fn from(_: ()) -> Self { + Error::from(UnitError) + } +} + impl From for Error { fn from(_: std::convert::Infallible) -> Self { // `std::convert::Infallible` indicates an error @@ -182,11 +182,11 @@ impl ResponseError for FormError {} #[cfg(feature = "openssl")] /// `InternalServerError` for `openssl::ssl::Error` -impl ResponseError for open_ssl::ssl::Error {} +impl ResponseError for actix_connect::ssl::openssl::SslError {} #[cfg(feature = "openssl")] /// `InternalServerError` for `openssl::ssl::HandshakeError` -impl ResponseError for open_ssl::ssl::HandshakeError {} +impl ResponseError for actix_tls::openssl::HandshakeError {} /// Return `BAD_REQUEST` for `de::value::Error` impl ResponseError for DeError { @@ -230,13 +230,6 @@ impl ResponseError for header::InvalidHeaderValue { } } -/// `BadRequest` for `InvalidHeaderValue` -impl ResponseError for header::InvalidHeaderValueBytes { - fn status_code(&self) -> StatusCode { - StatusCode::BAD_REQUEST - } -} - /// A set of errors that can occur during parsing HTTP streams #[derive(Debug, Display)] pub enum ParseError { diff --git a/actix-http/src/h1/decoder.rs b/actix-http/src/h1/decoder.rs index ffa00288f..32ec64ba3 100644 --- a/actix-http/src/h1/decoder.rs +++ b/actix-http/src/h1/decoder.rs @@ -1,3 +1,4 @@ +use std::convert::TryFrom; use std::io; use std::marker::PhantomData; use std::mem::MaybeUninit; @@ -6,7 +7,7 @@ use std::task::Poll; use actix_codec::Decoder; use bytes::{Bytes, BytesMut}; use http::header::{HeaderName, HeaderValue}; -use http::{header, HttpTryFrom, Method, StatusCode, Uri, Version}; +use http::{header, Method, StatusCode, Uri, Version}; use httparse; use log::{debug, error, trace}; @@ -79,8 +80,8 @@ pub(crate) trait MessageType: Sized { // Unsafe: httparse check header value for valid utf-8 let value = unsafe { - HeaderValue::from_shared_unchecked( - slice.slice(idx.value.0, idx.value.1), + HeaderValue::from_maybe_shared_unchecked( + slice.slice(idx.value.0..idx.value.1), ) }; match name { @@ -428,7 +429,7 @@ impl Decoder for PayloadDecoder { let len = src.len() as u64; let buf; if *remaining > len { - buf = src.take().freeze(); + buf = src.split().freeze(); *remaining -= len; } else { buf = src.split_to(*remaining as usize).freeze(); @@ -463,7 +464,7 @@ impl Decoder for PayloadDecoder { if src.is_empty() { Ok(None) } else { - Ok(Some(PayloadItem::Chunk(src.take().freeze()))) + Ok(Some(PayloadItem::Chunk(src.split().freeze()))) } } } @@ -581,7 +582,7 @@ impl ChunkedState { } else { let slice; if *rem > len { - slice = rdr.take().freeze(); + slice = rdr.split().freeze(); *rem -= len; } else { slice = rdr.split_to(*rem as usize).freeze(); diff --git a/actix-http/src/h1/dispatcher.rs b/actix-http/src/h1/dispatcher.rs index d5b3a8ed6..0e2a58346 100644 --- a/actix-http/src/h1/dispatcher.rs +++ b/actix-http/src/h1/dispatcher.rs @@ -2,11 +2,10 @@ use std::collections::VecDeque; use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; -use std::time::Instant; use std::{fmt, io, net}; use actix_codec::{AsyncRead, AsyncWrite, Decoder, Encoder, Framed, FramedParts}; -use actix_rt::time::{delay, Delay}; +use actix_rt::time::{delay_until, Delay, Instant}; use actix_service::Service; use bitflags::bitflags; use bytes::{BufMut, BytesMut}; @@ -610,7 +609,7 @@ where // shutdown timeout if self.flags.contains(Flags::SHUTDOWN) { if let Some(interval) = self.codec.config().client_disconnect_timer() { - self.ka_timer = Some(delay(interval)); + self.ka_timer = Some(delay_until(interval)); } else { self.flags.insert(Flags::READ_DISCONNECT); if let Some(mut payload) = self.payload.take() { diff --git a/actix-http/src/h1/encoder.rs b/actix-http/src/h1/encoder.rs index 6396f3b55..e83ce90cf 100644 --- a/actix-http/src/h1/encoder.rs +++ b/actix-http/src/h1/encoder.rs @@ -2,11 +2,13 @@ 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 bytes::{BufMut, Bytes, BytesMut}; +use bytes::{buf::BufMutExt, BufMut, Bytes, BytesMut}; use crate::body::BodySize; use crate::config::ServiceConfig; @@ -144,8 +146,8 @@ pub(crate) trait MessageType: Sized { // write headers let mut pos = 0; let mut has_date = false; - let mut remaining = dst.remaining_mut(); - let mut buf = unsafe { &mut *(dst.bytes_mut() as *mut [u8]) }; + let mut remaining = dst.capacity() - dst.len(); + let mut buf = dst.bytes_mut().as_mut_ptr() as *mut u8; for (key, value) in headers { match *key { CONNECTION => continue, @@ -159,61 +161,67 @@ pub(crate) trait MessageType: Sized { match value { map::Value::One(ref val) => { let v = val.as_ref(); - let len = k.len() + v.len() + 4; + let v_len = v.len(); + let k_len = k.len(); + let len = k_len + v_len + 4; if len > remaining { unsafe { dst.advance_mut(pos); } pos = 0; dst.reserve(len * 2); - remaining = dst.remaining_mut(); - unsafe { - buf = &mut *(dst.bytes_mut() as *mut _); - } + remaining = dst.capacity() - dst.len(); + buf = dst.bytes_mut().as_mut_ptr() as *mut u8; } // use upper Camel-Case - if camel_case { - write_camel_case(k, &mut buf[pos..pos + k.len()]); - } else { - buf[pos..pos + k.len()].copy_from_slice(k); + unsafe { + if camel_case { + write_camel_case(k, from_raw_parts_mut(buf, k_len)) + } else { + write_data(k, buf, k_len) + } + buf = buf.add(k_len); + write_data(b": ", buf, 2); + buf = buf.add(2); + write_data(v, buf, v_len); + buf = buf.add(v_len); + write_data(b"\r\n", buf, 2); + buf = buf.add(2); + pos += len; + remaining -= len; } - pos += k.len(); - buf[pos..pos + 2].copy_from_slice(b": "); - pos += 2; - buf[pos..pos + v.len()].copy_from_slice(v); - pos += v.len(); - buf[pos..pos + 2].copy_from_slice(b"\r\n"); - pos += 2; - remaining -= len; } map::Value::Multi(ref vec) => { for val in vec { let v = val.as_ref(); - let len = k.len() + v.len() + 4; + let v_len = v.len(); + let k_len = k.len(); + let len = k_len + v_len + 4; if len > remaining { unsafe { dst.advance_mut(pos); } pos = 0; dst.reserve(len * 2); - remaining = dst.remaining_mut(); - unsafe { - buf = &mut *(dst.bytes_mut() as *mut _); - } + remaining = dst.capacity() - dst.len(); + buf = dst.bytes_mut().as_mut_ptr() as *mut u8; } // use upper Camel-Case - if camel_case { - write_camel_case(k, &mut buf[pos..pos + k.len()]); - } else { - buf[pos..pos + k.len()].copy_from_slice(k); - } - pos += k.len(); - buf[pos..pos + 2].copy_from_slice(b": "); - pos += 2; - buf[pos..pos + v.len()].copy_from_slice(v); - pos += v.len(); - buf[pos..pos + 2].copy_from_slice(b"\r\n"); - pos += 2; + unsafe { + if camel_case { + write_camel_case(k, from_raw_parts_mut(buf, k_len)); + } else { + write_data(k, buf, k_len); + } + buf = buf.add(k_len); + write_data(b": ", buf, 2); + buf = buf.add(2); + write_data(v, buf, v_len); + buf = buf.add(v_len); + write_data(b"\r\n", buf, 2); + buf = buf.add(2); + }; + pos += len; remaining -= len; } } @@ -298,6 +306,12 @@ impl MessageType for RequestHeadType { Version::HTTP_10 => "HTTP/1.0", Version::HTTP_11 => "HTTP/1.1", Version::HTTP_2 => "HTTP/2.0", + Version::HTTP_3 => "HTTP/3.0", + _ => + return Err(io::Error::new( + io::ErrorKind::Other, + "unsupported version" + )), } ) .map_err(|e| io::Error::new(io::ErrorKind::Other, e)) @@ -479,6 +493,10 @@ impl<'a> io::Write for Writer<'a> { } } +unsafe fn write_data(value: &[u8], buf: *mut u8, len: usize) { + copy_nonoverlapping(value.as_ptr(), buf, len); +} + fn write_camel_case(value: &[u8], buffer: &mut [u8]) { let mut index = 0; let key = value; @@ -525,7 +543,7 @@ mod tests { assert!(enc.encode(b"", &mut bytes).ok().unwrap()); } assert_eq!( - bytes.take().freeze(), + bytes.split().freeze(), Bytes::from_static(b"4\r\ntest\r\n0\r\n\r\n") ); } @@ -548,7 +566,8 @@ mod tests { ConnectionType::Close, &ServiceConfig::default(), ); - let data = String::from_utf8(Vec::from(bytes.take().freeze().as_ref())).unwrap(); + let data = + String::from_utf8(Vec::from(bytes.split().freeze().as_ref())).unwrap(); assert!(data.contains("Content-Length: 0\r\n")); assert!(data.contains("Connection: close\r\n")); assert!(data.contains("Content-Type: plain/text\r\n")); @@ -561,7 +580,8 @@ mod tests { ConnectionType::KeepAlive, &ServiceConfig::default(), ); - let data = String::from_utf8(Vec::from(bytes.take().freeze().as_ref())).unwrap(); + let data = + String::from_utf8(Vec::from(bytes.split().freeze().as_ref())).unwrap(); assert!(data.contains("Transfer-Encoding: chunked\r\n")); assert!(data.contains("Content-Type: plain/text\r\n")); assert!(data.contains("Date: date\r\n")); @@ -573,7 +593,8 @@ mod tests { ConnectionType::KeepAlive, &ServiceConfig::default(), ); - let data = String::from_utf8(Vec::from(bytes.take().freeze().as_ref())).unwrap(); + let data = + String::from_utf8(Vec::from(bytes.split().freeze().as_ref())).unwrap(); assert!(data.contains("Content-Length: 100\r\n")); assert!(data.contains("Content-Type: plain/text\r\n")); assert!(data.contains("Date: date\r\n")); @@ -594,7 +615,8 @@ mod tests { ConnectionType::KeepAlive, &ServiceConfig::default(), ); - let data = String::from_utf8(Vec::from(bytes.take().freeze().as_ref())).unwrap(); + let data = + String::from_utf8(Vec::from(bytes.split().freeze().as_ref())).unwrap(); assert!(data.contains("transfer-encoding: chunked\r\n")); assert!(data.contains("content-type: xml\r\n")); assert!(data.contains("content-type: plain/text\r\n")); @@ -627,7 +649,8 @@ mod tests { ConnectionType::Close, &ServiceConfig::default(), ); - let data = String::from_utf8(Vec::from(bytes.take().freeze().as_ref())).unwrap(); + let data = + String::from_utf8(Vec::from(bytes.split().freeze().as_ref())).unwrap(); assert!(data.contains("content-length: 0\r\n")); assert!(data.contains("connection: close\r\n")); assert!(data.contains("authorization: another authorization\r\n")); diff --git a/actix-http/src/h1/service.rs b/actix-http/src/h1/service.rs index 354fed482..d6494b5cb 100644 --- a/actix-http/src/h1/service.rs +++ b/actix-http/src/h1/service.rs @@ -97,9 +97,8 @@ where mod openssl { use super::*; - use actix_tls::openssl::{Acceptor, SslStream}; + use actix_tls::openssl::{Acceptor, SslAcceptor, SslStream}; use actix_tls::{openssl::HandshakeError, SslError}; - use open_ssl::ssl::SslAcceptor; impl H1Service, S, B, X, U> where @@ -144,6 +143,56 @@ mod openssl { } } +#[cfg(feature = "rustls")] +mod rustls { + use super::*; + use actix_tls::rustls::{Acceptor, ServerConfig, TlsStream}; + use actix_tls::SslError; + use std::{fmt, io}; + + impl H1Service, S, B, X, U> + where + S: ServiceFactory, + S::Error: Into, + S::InitError: fmt::Debug, + S::Response: Into>, + B: MessageBody, + X: ServiceFactory, + X::Error: Into, + X::InitError: fmt::Debug, + U: ServiceFactory< + Config = (), + Request = (Request, Framed, Codec>), + Response = (), + >, + U::Error: fmt::Display, + U::InitError: fmt::Debug, + { + /// Create rustls based service + pub fn rustls( + self, + config: ServerConfig, + ) -> impl ServiceFactory< + Config = (), + Request = TcpStream, + Response = (), + Error = SslError, + InitError = (), + > { + pipeline_factory( + Acceptor::new(config) + .map_err(SslError::Ssl) + .map_init_err(|_| panic!()), + ) + .and_then(|io: TlsStream| { + let peer_addr = io.get_ref().0.peer_addr().ok(); + ok((io, peer_addr)) + }) + .and_then(self.map_err(SslError::Service)) + } + } +} + impl H1Service where S: ServiceFactory, diff --git a/actix-http/src/h2/dispatcher.rs b/actix-http/src/h2/dispatcher.rs index e6e8967df..707ac7b9d 100644 --- a/actix-http/src/h2/dispatcher.rs +++ b/actix-http/src/h2/dispatcher.rs @@ -1,13 +1,13 @@ use std::collections::VecDeque; +use std::convert::TryFrom; use std::future::Future; use std::marker::PhantomData; use std::pin::Pin; use std::task::{Context, Poll}; -use std::time::Instant; use std::{fmt, mem, net}; use actix_codec::{AsyncRead, AsyncWrite}; -use actix_rt::time::Delay; +use actix_rt::time::{Delay, Instant}; use actix_service::Service; use bitflags::bitflags; use bytes::{Bytes, BytesMut}; @@ -17,7 +17,6 @@ use h2::{RecvStream, SendStream}; use http::header::{ HeaderValue, ACCEPT_ENCODING, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING, }; -use http::HttpTryFrom; use log::{debug, error, trace}; use crate::body::{Body, BodySize, MessageBody, ResponseBody}; @@ -235,8 +234,9 @@ where if !has_date { let mut bytes = BytesMut::with_capacity(29); self.config.set_date_header(&mut bytes); - res.headers_mut() - .insert(DATE, HeaderValue::try_from(bytes.freeze()).unwrap()); + res.headers_mut().insert(DATE, unsafe { + HeaderValue::from_maybe_shared_unchecked(bytes.freeze()) + }); } res diff --git a/actix-http/src/h2/mod.rs b/actix-http/src/h2/mod.rs index 9c902f18c..28dd75383 100644 --- a/actix-http/src/h2/mod.rs +++ b/actix-http/src/h2/mod.rs @@ -35,7 +35,7 @@ impl Stream for Payload { match Pin::new(&mut this.pl).poll_data(cx) { Poll::Ready(Some(Ok(chunk))) => { let len = chunk.len(); - if let Err(err) = this.pl.release_capacity().release_capacity(len) { + if let Err(err) = this.pl.flow_control().release_capacity(len) { Poll::Ready(Some(Err(err.into()))) } else { Poll::Ready(Some(Ok(chunk))) diff --git a/actix-http/src/h2/service.rs b/actix-http/src/h2/service.rs index 864070eb3..1bacc5c95 100644 --- a/actix-http/src/h2/service.rs +++ b/actix-http/src/h2/service.rs @@ -102,9 +102,8 @@ where #[cfg(feature = "openssl")] mod openssl { use actix_service::{factory_fn, service_fn2}; - use actix_tls::openssl::{Acceptor, SslStream}; + use actix_tls::openssl::{Acceptor, SslAcceptor, SslStream}; use actix_tls::{openssl::HandshakeError, SslError}; - use open_ssl::ssl::SslAcceptor; use super::*; @@ -143,6 +142,51 @@ mod openssl { } } +#[cfg(feature = "rustls")] +mod rustls { + use super::*; + use actix_tls::rustls::{Acceptor, ServerConfig, Session, TlsStream}; + use actix_tls::SslError; + use std::{fmt, io}; + + impl H2Service, S, B> + where + S: ServiceFactory, + S::Error: Into + 'static, + S::Response: Into> + 'static, + ::Future: 'static, + B: MessageBody + 'static, + { + /// Create openssl based service + pub fn rustls( + self, + mut config: ServerConfig, + ) -> impl ServiceFactory< + Config = (), + Request = TcpStream, + Response = (), + Error = SslError, + InitError = S::InitError, + > { + let protos = vec!["h2".to_string().into()]; + config.set_protocols(&protos); + + pipeline_factory( + Acceptor::new(config) + .map_err(SslError::Ssl) + .map_init_err(|_| panic!()), + ) + .and_then(factory_fn(|| { + ok::<_, S::InitError>(service_fn2(|io: TlsStream| { + let peer_addr = io.get_ref().0.peer_addr().ok(); + ok((io, peer_addr)) + })) + })) + .and_then(self.map_err(SslError::Service)) + } + } +} + impl ServiceFactory for H2Service where T: AsyncRead + AsyncWrite + Unpin, diff --git a/actix-http/src/header/common/cache_control.rs b/actix-http/src/header/common/cache_control.rs index 55774619b..a3253b85b 100644 --- a/actix-http/src/header/common/cache_control.rs +++ b/actix-http/src/header/common/cache_control.rs @@ -80,12 +80,12 @@ impl fmt::Display for CacheControl { } impl IntoHeaderValue for CacheControl { - type Error = header::InvalidHeaderValueBytes; + type Error = header::InvalidHeaderValue; fn try_into(self) -> Result { let mut writer = Writer::new(); let _ = write!(&mut writer, "{}", self); - header::HeaderValue::from_shared(writer.take()) + header::HeaderValue::from_maybe_shared(writer.take()) } } diff --git a/actix-http/src/header/common/content_disposition.rs b/actix-http/src/header/common/content_disposition.rs index b2b6f34d7..d09024f3f 100644 --- a/actix-http/src/header/common/content_disposition.rs +++ b/actix-http/src/header/common/content_disposition.rs @@ -462,12 +462,12 @@ impl ContentDisposition { } impl IntoHeaderValue for ContentDisposition { - type Error = header::InvalidHeaderValueBytes; + type Error = header::InvalidHeaderValue; fn try_into(self) -> Result { let mut writer = Writer::new(); let _ = write!(&mut writer, "{}", self); - header::HeaderValue::from_shared(writer.take()) + header::HeaderValue::from_maybe_shared(writer.take()) } } @@ -768,9 +768,8 @@ mod tests { Mainstream browsers like Firefox (gecko) and Chrome use UTF-8 directly as above. (And now, only UTF-8 is handled by this implementation.) */ - let a = - HeaderValue::from_str("form-data; name=upload; filename=\"文件.webp\"") - .unwrap(); + let a = HeaderValue::from_str("form-data; name=upload; filename=\"文件.webp\"") + .unwrap(); let a: ContentDisposition = ContentDisposition::from_raw(&a).unwrap(); let b = ContentDisposition { disposition: DispositionType::FormData, @@ -884,7 +883,11 @@ mod tests { assert!(ContentDisposition::from_raw(&a).is_err()); let a = HeaderValue::from_static("inline; filename=\"\""); - assert!(ContentDisposition::from_raw(&a).expect("parse cd").get_filename().expect("filename").is_empty()); + assert!(ContentDisposition::from_raw(&a) + .expect("parse cd") + .get_filename() + .expect("filename") + .is_empty()); } #[test] diff --git a/actix-http/src/header/common/content_range.rs b/actix-http/src/header/common/content_range.rs index cc7f27548..a3e4d49ba 100644 --- a/actix-http/src/header/common/content_range.rs +++ b/actix-http/src/header/common/content_range.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use crate::error::ParseError; use crate::header::{ - HeaderValue, IntoHeaderValue, InvalidHeaderValueBytes, Writer, CONTENT_RANGE, + HeaderValue, IntoHeaderValue, InvalidHeaderValue, Writer, CONTENT_RANGE, }; header! { @@ -198,11 +198,11 @@ impl Display for ContentRangeSpec { } impl IntoHeaderValue for ContentRangeSpec { - type Error = InvalidHeaderValueBytes; + type Error = InvalidHeaderValue; fn try_into(self) -> Result { let mut writer = Writer::new(); let _ = write!(&mut writer, "{}", self); - HeaderValue::from_shared(writer.take()) + HeaderValue::from_maybe_shared(writer.take()) } } diff --git a/actix-http/src/header/common/if_range.rs b/actix-http/src/header/common/if_range.rs index e910ebd96..ea5d69a13 100644 --- a/actix-http/src/header/common/if_range.rs +++ b/actix-http/src/header/common/if_range.rs @@ -3,7 +3,7 @@ use std::fmt::{self, Display, Write}; use crate::error::ParseError; use crate::header::{ self, from_one_raw_str, EntityTag, Header, HeaderName, HeaderValue, HttpDate, - IntoHeaderValue, InvalidHeaderValueBytes, Writer, + IntoHeaderValue, InvalidHeaderValue, Writer, }; use crate::httpmessage::HttpMessage; @@ -96,12 +96,12 @@ impl Display for IfRange { } impl IntoHeaderValue for IfRange { - type Error = InvalidHeaderValueBytes; + type Error = InvalidHeaderValue; fn try_into(self) -> Result { let mut writer = Writer::new(); let _ = write!(&mut writer, "{}", self); - HeaderValue::from_shared(writer.take()) + HeaderValue::from_maybe_shared(writer.take()) } } diff --git a/actix-http/src/header/common/mod.rs b/actix-http/src/header/common/mod.rs index 30dfcaa6d..814050b13 100644 --- a/actix-http/src/header/common/mod.rs +++ b/actix-http/src/header/common/mod.rs @@ -164,13 +164,13 @@ macro_rules! header { } } impl $crate::http::header::IntoHeaderValue for $id { - type Error = $crate::http::header::InvalidHeaderValueBytes; + type Error = $crate::http::header::InvalidHeaderValue; fn try_into(self) -> Result<$crate::http::header::HeaderValue, Self::Error> { use std::fmt::Write; let mut writer = $crate::http::header::Writer::new(); let _ = write!(&mut writer, "{}", self); - $crate::http::header::HeaderValue::from_shared(writer.take()) + $crate::http::header::HeaderValue::from_maybe_shared(writer.take()) } } }; @@ -200,13 +200,13 @@ macro_rules! header { } } impl $crate::http::header::IntoHeaderValue for $id { - type Error = $crate::http::header::InvalidHeaderValueBytes; + type Error = $crate::http::header::InvalidHeaderValue; fn try_into(self) -> Result<$crate::http::header::HeaderValue, Self::Error> { use std::fmt::Write; let mut writer = $crate::http::header::Writer::new(); let _ = write!(&mut writer, "{}", self); - $crate::http::header::HeaderValue::from_shared(writer.take()) + $crate::http::header::HeaderValue::from_maybe_shared(writer.take()) } } }; @@ -236,7 +236,7 @@ macro_rules! header { } } impl $crate::http::header::IntoHeaderValue for $id { - type Error = $crate::http::header::InvalidHeaderValueBytes; + type Error = $crate::http::header::InvalidHeaderValue; fn try_into(self) -> Result<$crate::http::header::HeaderValue, Self::Error> { self.0.try_into() @@ -285,13 +285,13 @@ macro_rules! header { } } impl $crate::http::header::IntoHeaderValue for $id { - type Error = $crate::http::header::InvalidHeaderValueBytes; + type Error = $crate::http::header::InvalidHeaderValue; fn try_into(self) -> Result<$crate::http::header::HeaderValue, Self::Error> { use std::fmt::Write; let mut writer = $crate::http::header::Writer::new(); let _ = write!(&mut writer, "{}", self); - $crate::http::header::HeaderValue::from_shared(writer.take()) + $crate::http::header::HeaderValue::from_maybe_shared(writer.take()) } } }; diff --git a/actix-http/src/header/map.rs b/actix-http/src/header/map.rs index 5fcf79f75..dc49d53f3 100644 --- a/actix-http/src/header/map.rs +++ b/actix-http/src/header/map.rs @@ -1,9 +1,9 @@ use std::collections::hash_map::{self, Entry}; +use std::convert::TryFrom; use either::Either; use fxhash::FxHashMap; use http::header::{HeaderName, HeaderValue}; -use http::HttpTryFrom; /// A set of HTTP headers /// diff --git a/actix-http/src/header/mod.rs b/actix-http/src/header/mod.rs index 59cbb11c4..6fd3c1b96 100644 --- a/actix-http/src/header/mod.rs +++ b/actix-http/src/header/mod.rs @@ -1,6 +1,7 @@ //! Various http headers // This is mostly copy of [hyper](https://github.com/hyperium/hyper/tree/master/src/header) +use std::convert::TryFrom; use std::{fmt, str::FromStr}; use bytes::{Bytes, BytesMut}; @@ -73,58 +74,58 @@ impl<'a> IntoHeaderValue for &'a [u8] { } impl IntoHeaderValue for Bytes { - type Error = InvalidHeaderValueBytes; + type Error = InvalidHeaderValue; #[inline] fn try_into(self) -> Result { - HeaderValue::from_shared(self) + HeaderValue::from_maybe_shared(self) } } impl IntoHeaderValue for Vec { - type Error = InvalidHeaderValueBytes; + type Error = InvalidHeaderValue; #[inline] fn try_into(self) -> Result { - HeaderValue::from_shared(Bytes::from(self)) + HeaderValue::try_from(self) } } impl IntoHeaderValue for String { - type Error = InvalidHeaderValueBytes; + type Error = InvalidHeaderValue; #[inline] fn try_into(self) -> Result { - HeaderValue::from_shared(Bytes::from(self)) + HeaderValue::try_from(self) } } impl IntoHeaderValue for usize { - type Error = InvalidHeaderValueBytes; + type Error = InvalidHeaderValue; #[inline] fn try_into(self) -> Result { let s = format!("{}", self); - HeaderValue::from_shared(Bytes::from(s)) + HeaderValue::try_from(s) } } impl IntoHeaderValue for u64 { - type Error = InvalidHeaderValueBytes; + type Error = InvalidHeaderValue; #[inline] fn try_into(self) -> Result { let s = format!("{}", self); - HeaderValue::from_shared(Bytes::from(s)) + HeaderValue::try_from(s) } } impl IntoHeaderValue for Mime { - type Error = InvalidHeaderValueBytes; + type Error = InvalidHeaderValue; #[inline] fn try_into(self) -> Result { - HeaderValue::from_shared(Bytes::from(format!("{}", self))) + HeaderValue::try_from(format!("{}", self)) } } @@ -204,7 +205,7 @@ impl Writer { } } fn take(&mut self) -> Bytes { - self.buf.take().freeze() + self.buf.split().freeze() } } diff --git a/actix-http/src/header/shared/entity.rs b/actix-http/src/header/shared/entity.rs index da02dc193..7ef51a7d6 100644 --- a/actix-http/src/header/shared/entity.rs +++ b/actix-http/src/header/shared/entity.rs @@ -1,7 +1,7 @@ use std::fmt::{self, Display, Write}; use std::str::FromStr; -use crate::header::{HeaderValue, IntoHeaderValue, InvalidHeaderValueBytes, Writer}; +use crate::header::{HeaderValue, IntoHeaderValue, InvalidHeaderValue, Writer}; /// check that each char in the slice is either: /// 1. `%x21`, or @@ -157,12 +157,12 @@ impl FromStr for EntityTag { } impl IntoHeaderValue for EntityTag { - type Error = InvalidHeaderValueBytes; + type Error = InvalidHeaderValue; fn try_into(self) -> Result { let mut wrt = Writer::new(); write!(wrt, "{}", self).unwrap(); - HeaderValue::from_shared(wrt.take()) + HeaderValue::from_maybe_shared(wrt.take()) } } diff --git a/actix-http/src/header/shared/httpdate.rs b/actix-http/src/header/shared/httpdate.rs index 350f77bbe..c8d26ef54 100644 --- a/actix-http/src/header/shared/httpdate.rs +++ b/actix-http/src/header/shared/httpdate.rs @@ -3,8 +3,8 @@ use std::io::Write; use std::str::FromStr; use std::time::{Duration, SystemTime, UNIX_EPOCH}; -use bytes::{BufMut, BytesMut}; -use http::header::{HeaderValue, InvalidHeaderValueBytes}; +use bytes::{buf::BufMutExt, BytesMut}; +use http::header::{HeaderValue, InvalidHeaderValue}; use crate::error::ParseError; use crate::header::IntoHeaderValue; @@ -58,12 +58,12 @@ impl From for HttpDate { } impl IntoHeaderValue for HttpDate { - type Error = InvalidHeaderValueBytes; + type Error = InvalidHeaderValue; fn try_into(self) -> Result { let mut wrt = BytesMut::with_capacity(29).writer(); write!(wrt, "{}", self.0.rfc822()).unwrap(); - HeaderValue::from_shared(wrt.get_mut().take().freeze()) + HeaderValue::from_maybe_shared(wrt.get_mut().split().freeze()) } } diff --git a/actix-http/src/helpers.rs b/actix-http/src/helpers.rs index 84403d8fd..58ebff61f 100644 --- a/actix-http/src/helpers.rs +++ b/actix-http/src/helpers.rs @@ -60,7 +60,7 @@ pub(crate) fn write_status_line(version: Version, mut n: u16, bytes: &mut BytesM bytes.put_slice(&buf); if four { - bytes.put(b' '); + bytes.put_u8(b' '); } } @@ -203,33 +203,33 @@ mod tests { let mut bytes = BytesMut::new(); bytes.reserve(50); write_content_length(0, &mut bytes); - assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 0\r\n"[..]); + assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 0\r\n"[..]); bytes.reserve(50); write_content_length(9, &mut bytes); - assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 9\r\n"[..]); + assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 9\r\n"[..]); bytes.reserve(50); write_content_length(10, &mut bytes); - assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 10\r\n"[..]); + assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 10\r\n"[..]); bytes.reserve(50); write_content_length(99, &mut bytes); - assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 99\r\n"[..]); + assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 99\r\n"[..]); bytes.reserve(50); write_content_length(100, &mut bytes); - assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 100\r\n"[..]); + assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 100\r\n"[..]); bytes.reserve(50); write_content_length(101, &mut bytes); - assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 101\r\n"[..]); + assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 101\r\n"[..]); bytes.reserve(50); write_content_length(998, &mut bytes); - assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 998\r\n"[..]); + assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 998\r\n"[..]); bytes.reserve(50); write_content_length(1000, &mut bytes); - assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 1000\r\n"[..]); + assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 1000\r\n"[..]); bytes.reserve(50); write_content_length(1001, &mut bytes); - assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 1001\r\n"[..]); + assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 1001\r\n"[..]); bytes.reserve(50); write_content_length(5909, &mut bytes); - assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 5909\r\n"[..]); + assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 5909\r\n"[..]); } } diff --git a/actix-http/src/lib.rs b/actix-http/src/lib.rs index e476623d1..190d5fbdc 100644 --- a/actix-http/src/lib.rs +++ b/actix-http/src/lib.rs @@ -51,7 +51,7 @@ pub mod http { // re-exports pub use http::header::{HeaderName, HeaderValue}; pub use http::uri::PathAndQuery; - pub use http::{uri, Error, HttpTryFrom, Uri}; + pub use http::{uri, Error, Uri}; pub use http::{Method, StatusCode, Version}; pub use crate::cookie::{Cookie, CookieBuilder}; diff --git a/actix-http/src/request.rs b/actix-http/src/request.rs index 77ece01c5..371e2ccd8 100644 --- a/actix-http/src/request.rs +++ b/actix-http/src/request.rs @@ -187,7 +187,7 @@ impl

fmt::Debug for Request

{ #[cfg(test)] mod tests { use super::*; - use http::HttpTryFrom; + use std::convert::TryFrom; #[test] fn test_basics() { diff --git a/actix-http/src/response.rs b/actix-http/src/response.rs index e9147aa4b..e7f145d39 100644 --- a/actix-http/src/response.rs +++ b/actix-http/src/response.rs @@ -1,12 +1,12 @@ //! Http response use std::cell::{Ref, RefMut}; +use std::convert::TryFrom; use std::future::Future; -use std::io::Write; use std::pin::Pin; use std::task::{Context, Poll}; use std::{fmt, str}; -use bytes::{BufMut, Bytes, BytesMut}; +use bytes::{Bytes, BytesMut}; use futures::stream::Stream; use serde::Serialize; use serde_json; @@ -17,7 +17,7 @@ use crate::error::Error; use crate::extensions::Extensions; use crate::header::{Header, IntoHeaderValue}; use crate::http::header::{self, HeaderName, HeaderValue}; -use crate::http::{Error as HttpError, HeaderMap, HttpTryFrom, StatusCode}; +use crate::http::{Error as HttpError, HeaderMap, StatusCode}; use crate::message::{BoxedResponseHead, ConnectionType, ResponseHead}; /// An HTTP Response @@ -384,7 +384,8 @@ impl ResponseBuilder { /// ``` pub fn header(&mut self, key: K, value: V) -> &mut Self where - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, V: IntoHeaderValue, { if let Some(parts) = parts(&mut self.head, &self.err) { @@ -416,7 +417,8 @@ impl ResponseBuilder { /// ``` pub fn set_header(&mut self, key: K, value: V) -> &mut Self where - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, V: IntoHeaderValue, { if let Some(parts) = parts(&mut self.head, &self.err) { @@ -485,7 +487,8 @@ impl ResponseBuilder { #[inline] pub fn content_type(&mut self, value: V) -> &mut Self where - HeaderValue: HttpTryFrom, + HeaderValue: TryFrom, + >::Error: Into, { if let Some(parts) = parts(&mut self.head, &self.err) { match HeaderValue::try_from(value) { @@ -501,9 +504,7 @@ impl ResponseBuilder { /// Set content length #[inline] pub fn content_length(&mut self, len: u64) -> &mut Self { - let mut wrt = BytesMut::new().writer(); - let _ = write!(wrt, "{}", len); - self.header(header::CONTENT_LENGTH, wrt.get_mut().take().freeze()) + self.header(header::CONTENT_LENGTH, len) } /// Set a cookie diff --git a/actix-http/src/service.rs b/actix-http/src/service.rs index de5fd0c55..3624060bf 100644 --- a/actix-http/src/service.rs +++ b/actix-http/src/service.rs @@ -193,9 +193,8 @@ where #[cfg(feature = "openssl")] mod openssl { use super::*; - use actix_tls::openssl::{Acceptor, SslStream}; + use actix_tls::openssl::{Acceptor, SslAcceptor, SslStream}; use actix_tls::{openssl::HandshakeError, SslError}; - use open_ssl::ssl::SslAcceptor; impl HttpService, S, B, X, U> where @@ -252,6 +251,71 @@ mod openssl { } } +#[cfg(feature = "rustls")] +mod rustls { + use super::*; + use actix_tls::rustls::{Acceptor, ServerConfig, Session, TlsStream}; + use actix_tls::SslError; + use std::io; + + impl HttpService, S, B, X, U> + where + S: ServiceFactory, + S::Error: Into + 'static, + S::InitError: fmt::Debug, + S::Response: Into> + 'static, + ::Future: 'static, + B: MessageBody + 'static, + X: ServiceFactory, + X::Error: Into, + X::InitError: fmt::Debug, + ::Future: 'static, + U: ServiceFactory< + Config = (), + Request = (Request, Framed, h1::Codec>), + Response = (), + >, + U::Error: fmt::Display, + U::InitError: fmt::Debug, + ::Future: 'static, + { + /// Create openssl based service + pub fn rustls( + self, + mut config: ServerConfig, + ) -> impl ServiceFactory< + Config = (), + Request = TcpStream, + Response = (), + Error = SslError, + InitError = (), + > { + let protos = vec!["h2".to_string().into(), "http/1.1".to_string().into()]; + config.set_protocols(&protos); + + pipeline_factory( + Acceptor::new(config) + .map_err(SslError::Ssl) + .map_init_err(|_| panic!()), + ) + .and_then(|io: TlsStream| { + let proto = if let Some(protos) = io.get_ref().1.get_alpn_protocol() { + if protos.windows(2).any(|window| window == b"h2") { + Protocol::Http2 + } else { + Protocol::Http1 + } + } else { + Protocol::Http1 + }; + let peer_addr = io.get_ref().0.peer_addr().ok(); + ok((io, proto, peer_addr)) + }) + .and_then(self.map_err(SslError::Service)) + } + } +} + impl ServiceFactory for HttpService where T: AsyncRead + AsyncWrite + Unpin, diff --git a/actix-http/src/test.rs b/actix-http/src/test.rs index ebb7bda37..b629ad784 100644 --- a/actix-http/src/test.rs +++ b/actix-http/src/test.rs @@ -1,4 +1,5 @@ //! Test Various helpers for Actix applications to use during testing. +use std::convert::TryFrom; use std::fmt::Write as FmtWrite; use std::io::{self, Read, Write}; use std::pin::Pin; @@ -8,7 +9,7 @@ use std::task::{Context, Poll}; use actix_codec::{AsyncRead, AsyncWrite}; use bytes::{Bytes, BytesMut}; use http::header::{self, HeaderName, HeaderValue}; -use http::{HttpTryFrom, Method, Uri, Version}; +use http::{Error as HttpError, Method, Uri, Version}; use percent_encoding::percent_encode; use crate::cookie::{Cookie, CookieJar, USERINFO}; @@ -82,7 +83,8 @@ impl TestRequest { /// Create TestRequest and set header pub fn with_header(key: K, value: V) -> TestRequest where - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, V: IntoHeaderValue, { TestRequest::default().header(key, value).take() @@ -118,7 +120,8 @@ impl TestRequest { /// Set a header pub fn header(&mut self, key: K, value: V) -> &mut Self where - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, V: IntoHeaderValue, { if let Ok(key) = HeaderName::try_from(key) { diff --git a/actix-http/src/ws/frame.rs b/actix-http/src/ws/frame.rs index 46e9f36db..0949b711f 100644 --- a/actix-http/src/ws/frame.rs +++ b/actix-http/src/ws/frame.rs @@ -180,11 +180,11 @@ impl Parser { } else if payload_len <= 65_535 { dst.reserve(p_len + 4 + if mask { 4 } else { 0 }); dst.put_slice(&[one, two | 126]); - dst.put_u16_be(payload_len as u16); + dst.put_u16(payload_len as u16); } else { dst.reserve(p_len + 10 + if mask { 4 } else { 0 }); dst.put_slice(&[one, two | 127]); - dst.put_u64_be(payload_len as u64); + dst.put_u64(payload_len as u64); }; if mask { diff --git a/actix-http/tests/test_rustls.rs b/actix-http/tests/test_rustls.rs index 4a649ca37..89719221d 100644 --- a/actix-http/tests/test_rustls.rs +++ b/actix-http/tests/test_rustls.rs @@ -1,13 +1,10 @@ #![cfg(feature = "rustls")] -use actix_codec::{AsyncRead, AsyncWrite}; 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_server::ssl::RustlsAcceptor; -use actix_server_config::ServerConfig; -use actix_service::{factory_fn_cfg, pipeline_factory, service_fn2, ServiceFactory}; +use actix_service::{factory_fn_cfg, service_fn2}; use bytes::{Bytes, BytesMut}; use futures::future::{self, err, ok}; @@ -31,7 +28,7 @@ where Ok(body) } -fn ssl_acceptor() -> io::Result> { +fn ssl_acceptor() -> RustlsServerConfig { // load ssl keys let mut config = RustlsServerConfig::new(NoClientAuth::new()); let cert_file = &mut BufReader::new(File::open("../tests/cert.pem").unwrap()); @@ -39,22 +36,45 @@ fn ssl_acceptor() -> io::Result let cert_chain = certs(cert_file).unwrap(); let mut keys = pkcs8_private_keys(key_file).unwrap(); config.set_single_cert(cert_chain, keys.remove(0)).unwrap(); + config +} - let protos = vec![b"h2".to_vec()]; - config.set_protocols(&protos); - Ok(RustlsAcceptor::new(config)) +#[actix_rt::test] +async fn test_h1() -> io::Result<()> { + let srv = TestServer::start(move || { + HttpService::build() + .h1(|_| future::ok::<_, Error>(Response::Ok().finish())) + .rustls(ssl_acceptor()) + }); + + let response = srv.sget("/").send().await.unwrap(); + assert!(response.status().is_success()); + Ok(()) } #[actix_rt::test] async fn test_h2() -> io::Result<()> { - let rustls = ssl_acceptor()?; let srv = TestServer::start(move || { - pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e))) - .and_then( - HttpService::build() - .h2(|_| future::ok::<_, Error>(Response::Ok().finish())) - .map_err(|_| ()), - ) + HttpService::build() + .h2(|_| future::ok::<_, Error>(Response::Ok().finish())) + .rustls(ssl_acceptor()) + }); + + let response = srv.sget("/").send().await.unwrap(); + assert!(response.status().is_success()); + Ok(()) +} + +#[actix_rt::test] +async fn test_h1_1() -> io::Result<()> { + let srv = TestServer::start(move || { + HttpService::build() + .h1(|req: Request| { + assert!(req.peer_addr().is_some()); + assert_eq!(req.version(), Version::HTTP_11); + future::ok::<_, Error>(Response::Ok().finish()) + }) + .rustls(ssl_acceptor()) }); let response = srv.sget("/").send().await.unwrap(); @@ -64,18 +84,14 @@ async fn test_h2() -> io::Result<()> { #[actix_rt::test] async fn test_h2_1() -> io::Result<()> { - let rustls = ssl_acceptor()?; let srv = TestServer::start(move || { - pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e))) - .and_then( - HttpService::build() - .finish(|req: Request| { - assert!(req.peer_addr().is_some()); - assert_eq!(req.version(), Version::HTTP_2); - future::ok::<_, Error>(Response::Ok().finish()) - }) - .map_err(|_| ()), - ) + HttpService::build() + .finish(|req: Request| { + assert!(req.peer_addr().is_some()); + assert_eq!(req.version(), Version::HTTP_2); + future::ok::<_, Error>(Response::Ok().finish()) + }) + .rustls(ssl_acceptor()) }); let response = srv.sget("/").send().await.unwrap(); @@ -86,19 +102,15 @@ 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 rustls = ssl_acceptor()?; let mut srv = TestServer::start(move || { - pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e))) - .and_then( - HttpService::build() - .h2(|mut req: Request<_>| { - async move { - let body = load_body(req.take_payload()).await?; - Ok::<_, Error>(Response::Ok().body(body)) - } - }) - .map_err(|_| ()), - ) + HttpService::build() + .h2(|mut req: Request<_>| { + async move { + let body = load_body(req.take_payload()).await?; + Ok::<_, Error>(Response::Ok().body(body)) + } + }) + .rustls(ssl_acceptor()) }); let response = srv.sget("/").send_body(data.clone()).await.unwrap(); @@ -111,31 +123,25 @@ async fn test_h2_body1() -> io::Result<()> { #[actix_rt::test] async fn test_h2_content_length() { - let rustls = ssl_acceptor().unwrap(); - let srv = TestServer::start(move || { - pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e))) - .and_then( - HttpService::build() - .h2(|req: Request| { - let indx: usize = req.uri().path()[1..].parse().unwrap(); - let statuses = [ - StatusCode::NO_CONTENT, - StatusCode::CONTINUE, - StatusCode::SWITCHING_PROTOCOLS, - StatusCode::PROCESSING, - StatusCode::OK, - StatusCode::NOT_FOUND, - ]; - future::ok::<_, ()>(Response::new(statuses[indx])) - }) - .map_err(|_| ()), - ) + HttpService::build() + .h2(|req: Request| { + let indx: usize = req.uri().path()[1..].parse().unwrap(); + let statuses = [ + StatusCode::NO_CONTENT, + StatusCode::CONTINUE, + StatusCode::SWITCHING_PROTOCOLS, + StatusCode::PROCESSING, + StatusCode::OK, + StatusCode::NOT_FOUND, + ]; + future::ok::<_, ()>(Response::new(statuses[indx])) + }) + .rustls(ssl_acceptor()) }); let header = HeaderName::from_static("content-length"); let value = HeaderValue::from_static("0"); - { for i in 0..4 { let req = srv @@ -165,14 +171,9 @@ async fn test_h2_content_length() { async fn test_h2_headers() { let data = STR.repeat(10); let data2 = data.clone(); - let rustls = ssl_acceptor().unwrap(); let mut srv = TestServer::start(move || { let data = data.clone(); - pipeline_factory(rustls - .clone() - .map_err(|e| println!("Rustls error: {}", e))) - .and_then( HttpService::build().h2(move |_| { let mut config = Response::Ok(); for idx in 0..90 { @@ -194,7 +195,8 @@ async fn test_h2_headers() { ); } future::ok::<_, ()>(config.body(data.clone())) - }).map_err(|_| ())) + }) + .rustls(ssl_acceptor()) }); let response = srv.sget("/").send().await.unwrap(); @@ -229,14 +231,10 @@ const STR: &str = "Hello World Hello World Hello World Hello World Hello World \ #[actix_rt::test] async fn test_h2_body2() { - let rustls = ssl_acceptor().unwrap(); let mut srv = TestServer::start(move || { - pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e))) - .and_then( - HttpService::build() - .h2(|_| future::ok::<_, ()>(Response::Ok().body(STR))) - .map_err(|_| ()), - ) + HttpService::build() + .h2(|_| future::ok::<_, ()>(Response::Ok().body(STR))) + .rustls(ssl_acceptor()) }); let response = srv.sget("/").send().await.unwrap(); @@ -249,14 +247,10 @@ async fn test_h2_body2() { #[actix_rt::test] async fn test_h2_head_empty() { - let rustls = ssl_acceptor().unwrap(); let mut srv = TestServer::start(move || { - pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e))) - .and_then( - HttpService::build() - .finish(|_| ok::<_, ()>(Response::Ok().body(STR))) - .map_err(|_| ()), - ) + HttpService::build() + .finish(|_| ok::<_, ()>(Response::Ok().body(STR))) + .rustls(ssl_acceptor()) }); let response = srv.shead("/").send().await.unwrap(); @@ -278,18 +272,12 @@ async fn test_h2_head_empty() { #[actix_rt::test] async fn test_h2_head_binary() { - let rustls = ssl_acceptor().unwrap(); let mut srv = TestServer::start(move || { - pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e))) - .and_then( - HttpService::build() - .h2(|_| { - ok::<_, ()>( - Response::Ok().content_length(STR.len() as u64).body(STR), - ) - }) - .map_err(|_| ()), - ) + HttpService::build() + .h2(|_| { + ok::<_, ()>(Response::Ok().content_length(STR.len() as u64).body(STR)) + }) + .rustls(ssl_acceptor()) }); let response = srv.shead("/").send().await.unwrap(); @@ -310,14 +298,10 @@ async fn test_h2_head_binary() { #[actix_rt::test] async fn test_h2_head_binary2() { - let rustls = ssl_acceptor().unwrap(); let srv = TestServer::start(move || { - pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e))) - .and_then( - HttpService::build() - .h2(|_| ok::<_, ()>(Response::Ok().body(STR))) - .map_err(|_| ()), - ) + HttpService::build() + .h2(|_| ok::<_, ()>(Response::Ok().body(STR))) + .rustls(ssl_acceptor()) }); let response = srv.shead("/").send().await.unwrap(); @@ -334,20 +318,15 @@ async fn test_h2_head_binary2() { #[actix_rt::test] async fn test_h2_body_length() { - let rustls = ssl_acceptor().unwrap(); let mut srv = TestServer::start(move || { - pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e))) - .and_then( - HttpService::build() - .h2(|_| { - let body = once(ok(Bytes::from_static(STR.as_ref()))); - ok::<_, ()>( - Response::Ok() - .body(body::SizedStream::new(STR.len() as u64, body)), - ) - }) - .map_err(|_| ()), - ) + HttpService::build() + .h2(|_| { + let body = once(ok(Bytes::from_static(STR.as_ref()))); + ok::<_, ()>( + Response::Ok().body(body::SizedStream::new(STR.len() as u64, body)), + ) + }) + .rustls(ssl_acceptor()) }); let response = srv.sget("/").send().await.unwrap(); @@ -360,22 +339,17 @@ async fn test_h2_body_length() { #[actix_rt::test] async fn test_h2_body_chunked_explicit() { - let rustls = ssl_acceptor().unwrap(); let mut srv = TestServer::start(move || { - pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e))) - .and_then( - HttpService::build() - .h2(|_| { - let body = - once(ok::<_, Error>(Bytes::from_static(STR.as_ref()))); - ok::<_, ()>( - Response::Ok() - .header(header::TRANSFER_ENCODING, "chunked") - .streaming(body), - ) - }) - .map_err(|_| ()), - ) + HttpService::build() + .h2(|_| { + let body = once(ok::<_, Error>(Bytes::from_static(STR.as_ref()))); + ok::<_, ()>( + Response::Ok() + .header(header::TRANSFER_ENCODING, "chunked") + .streaming(body), + ) + }) + .rustls(ssl_acceptor()) }); let response = srv.sget("/").send().await.unwrap(); @@ -391,24 +365,19 @@ async fn test_h2_body_chunked_explicit() { #[actix_rt::test] async fn test_h2_response_http_error_handling() { - let rustls = ssl_acceptor().unwrap(); - let mut srv = TestServer::start(move || { - pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e))) - .and_then( - HttpService::build() - .h2(factory_fn_cfg(|_: &ServerConfig| { - ok::<_, ()>(service_fn2(|_| { - let broken_header = Bytes::from_static(b"\0\0\0"); - ok::<_, ()>( - Response::Ok() - .header(http::header::CONTENT_TYPE, broken_header) - .body(STR), - ) - })) - })) - .map_err(|_| ()), - ) + HttpService::build() + .h2(factory_fn_cfg(|_: ()| { + ok::<_, ()>(service_fn2(|_| { + let broken_header = Bytes::from_static(b"\0\0\0"); + ok::<_, ()>( + Response::Ok() + .header(http::header::CONTENT_TYPE, broken_header) + .body(STR), + ) + })) + })) + .rustls(ssl_acceptor()) }); let response = srv.sget("/").send().await.unwrap(); @@ -421,15 +390,26 @@ async fn test_h2_response_http_error_handling() { #[actix_rt::test] async fn test_h2_service_error() { - let rustls = ssl_acceptor().unwrap(); - let mut srv = TestServer::start(move || { - pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e))) - .and_then( - HttpService::build() - .h2(|_| err::(error::ErrorBadRequest("error"))) - .map_err(|_| ()), - ) + HttpService::build() + .h2(|_| err::(error::ErrorBadRequest("error"))) + .rustls(ssl_acceptor()) + }); + + let response = srv.sget("/").send().await.unwrap(); + assert_eq!(response.status(), http::StatusCode::BAD_REQUEST); + + // read response + let bytes = srv.load_body(response).await.unwrap(); + assert_eq!(bytes, Bytes::from_static(b"error")); +} + +#[actix_rt::test] +async fn test_h1_service_error() { + let mut srv = TestServer::start(move || { + HttpService::build() + .h1(|_| err::(error::ErrorBadRequest("error"))) + .rustls(ssl_acceptor()) }); let response = srv.sget("/").send().await.unwrap(); diff --git a/actix-http/tests/test_ws.rs b/actix-http/tests/test_ws.rs index 5ac5fcaaf..284a4218a 100644 --- a/actix-http/tests/test_ws.rs +++ b/actix-http/tests/test_ws.rs @@ -2,7 +2,7 @@ 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::{Bytes, BytesMut}; +use bytes::BytesMut; use futures::future; use futures::{SinkExt, StreamExt}; @@ -62,7 +62,7 @@ async fn test_simple() { let (item, mut framed) = framed.into_future().await; assert_eq!( item.unwrap().unwrap(), - ws::Frame::Binary(Some(Bytes::from_static(b"text").into())) + ws::Frame::Binary(Some(BytesMut::from(&b"text"[..]).into())) ); framed.send(ws::Message::Ping("text".into())).await.unwrap(); diff --git a/actix-identity/Cargo.toml b/actix-identity/Cargo.toml index f9c664672..eea854263 100644 --- a/actix-identity/Cargo.toml +++ b/actix-identity/Cargo.toml @@ -27,4 +27,4 @@ time = "0.1.42" [dev-dependencies] actix-rt = "1.0.0-alpha.2" actix-http = "0.3.0-alpha.2" -bytes = "0.4" \ No newline at end of file +bytes = "0.5.2" \ No newline at end of file diff --git a/actix-multipart/Cargo.toml b/actix-multipart/Cargo.toml index 2107af5a0..f1913c3f1 100644 --- a/actix-multipart/Cargo.toml +++ b/actix-multipart/Cargo.toml @@ -21,7 +21,7 @@ path = "src/lib.rs" actix-web = { version = "2.0.0-alpha.2", default-features = false } actix-service = "1.0.0-alpha.2" actix-utils = "1.0.0-alpha.2" -bytes = "0.4" +bytes = "0.5.2" derive_more = "0.99.2" httparse = "1.3" futures = "0.3.1" diff --git a/actix-multipart/src/server.rs b/actix-multipart/src/server.rs index c49896761..7d1bbca46 100644 --- a/actix-multipart/src/server.rs +++ b/actix-multipart/src/server.rs @@ -1,5 +1,6 @@ //! Multipart payload support use std::cell::{Cell, RefCell, RefMut}; +use std::convert::TryFrom; use std::marker::PhantomData; use std::pin::Pin; use std::rc::Rc; @@ -16,7 +17,6 @@ use actix_web::error::{ParseError, PayloadError}; use actix_web::http::header::{ self, ContentDisposition, HeaderMap, HeaderName, HeaderValue, }; -use actix_web::http::HttpTryFrom; use crate::error::MultipartError; @@ -582,7 +582,7 @@ impl InnerField { } } } else { - Poll::Ready(Some(Ok(payload.buf.take().freeze()))) + Poll::Ready(Some(Ok(payload.buf.split().freeze()))) }; } } @@ -792,7 +792,7 @@ impl PayloadBuffer { pub fn readline_or_eof(&mut self) -> Result, MultipartError> { match self.readline() { Err(MultipartError::Incomplete) if self.eof => { - Ok(Some(self.buf.take().freeze())) + Ok(Some(self.buf.split().freeze())) } line => line, } @@ -800,7 +800,7 @@ impl PayloadBuffer { /// Put unprocessed data back to the buffer pub fn unprocessed(&mut self, data: Bytes) { - let buf = BytesMut::from(data); + let buf = BytesMut::from(data.as_ref()); let buf = std::mem::replace(&mut self.buf, buf); self.buf.extend_from_slice(&buf); } @@ -893,8 +893,8 @@ mod tests { #[actix_rt::test] async fn test_multipart_no_end_crlf() { let (sender, payload) = create_stream(); - let (bytes, headers) = create_simple_request_with_header(); - let bytes_stripped = bytes.slice_to(bytes.len()); // strip crlf + let (mut bytes, headers) = create_simple_request_with_header(); + let bytes_stripped = bytes.split_to(bytes.len()); // strip crlf sender.send(Ok(bytes_stripped)).unwrap(); drop(sender); // eof diff --git a/actix-session/Cargo.toml b/actix-session/Cargo.toml index d396a787a..c33642d67 100644 --- a/actix-session/Cargo.toml +++ b/actix-session/Cargo.toml @@ -26,7 +26,7 @@ cookie-session = ["actix-web/secure-cookies"] [dependencies] actix-web = "2.0.0-alpha.2" actix-service = "1.0.0-alpha.2" -bytes = "0.4" +bytes = "0.5.2" derive_more = "0.99.2" futures = "0.3.1" serde = "1.0" diff --git a/awc/Cargo.toml b/awc/Cargo.toml index e884aaddd..99ccd4bbb 100644 --- a/awc/Cargo.toml +++ b/awc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "awc" -version = "0.3.0-alpha.2" +version = "0.3.0-alpha.3" authors = ["Nikolay Kim "] description = "Actix http client." readme = "README.md" @@ -21,7 +21,7 @@ name = "awc" path = "src/lib.rs" [package.metadata.docs.rs] -features = ["openssl", "brotli", "flate2-zlib"] +features = ["openssl", "rustls", "brotli", "flate2-zlib"] [features] default = ["brotli", "flate2-zlib"] @@ -30,7 +30,7 @@ default = ["brotli", "flate2-zlib"] openssl = ["open-ssl", "actix-http/openssl"] # rustls -# rustls = ["rust-tls", "actix-http/rustls"] +rustls = ["rust-tls", "actix-http/rustls"] # brotli encoding, requires c compiler brotli = ["actix-http/brotli"] @@ -42,13 +42,13 @@ flate2-zlib = ["actix-http/flate2-zlib"] flate2-rust = ["actix-http/flate2-rust"] [dependencies] -actix-codec = "0.2.0-alpha.2" -actix-service = "1.0.0-alpha.2" -actix-http = "0.3.0-alpha.2" -actix-rt = "1.0.0-alpha.2" +actix-codec = "0.2.0-alpha.3" +actix-service = "1.0.0-alpha.3" +actix-http = "0.3.0-alpha.3" +actix-rt = "1.0.0-alpha.3" -base64 = "0.10.1" -bytes = "0.4" +base64 = "0.11" +bytes = "0.5.2" derive_more = "0.99.2" futures = "0.3.1" log =" 0.4" @@ -59,16 +59,16 @@ serde = "1.0" serde_json = "1.0" serde_urlencoded = "0.6.1" open-ssl = { version="0.10", package="openssl", optional = true } -# rust-tls = { version = "0.16.0", package="rustls", optional = true, features = ["dangerous_configuration"] } +rust-tls = { version = "0.16.0", package="rustls", optional = true, features = ["dangerous_configuration"] } [dev-dependencies] -actix-connect = { version = "1.0.0-alpha.2", features=["openssl"] } -actix-web = { version = "2.0.0-alpha.2", features=["openssl"] } -actix-http = { version = "0.3.0-alpha.2", features=["openssl"] } -actix-http-test = { version = "0.3.0-alpha.2", features=["openssl"] } -actix-utils = "1.0.0-alpha.2" -actix-server = { version = "1.0.0-alpha.2" } -#actix-tls = { version = "0.1.0-alpha.1", features=["openssl"] } +actix-connect = { version = "1.0.0-alpha.3", features=["openssl"] } +actix-web = { version = "2.0.0-alpha.3", features=["openssl"] } +actix-http = { version = "0.3.0-alpha.3", features=["openssl"] } +actix-http-test = { version = "0.3.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" } env_logger = "0.6" diff --git a/awc/src/builder.rs b/awc/src/builder.rs index 463f40303..7bd0171ec 100644 --- a/awc/src/builder.rs +++ b/awc/src/builder.rs @@ -1,10 +1,11 @@ use std::cell::RefCell; +use std::convert::TryFrom; use std::fmt; use std::rc::Rc; use std::time::Duration; use actix_http::client::{Connect, ConnectError, Connection, Connector}; -use actix_http::http::{header, HeaderMap, HeaderName, HttpTryFrom}; +use actix_http::http::{header, Error as HttpError, HeaderMap, HeaderName}; use actix_service::Service; use crate::connect::ConnectorWrapper; @@ -97,8 +98,8 @@ impl ClientBuilder { /// get added to every request. pub fn header(mut self, key: K, value: V) -> Self where - HeaderName: HttpTryFrom, - >::Error: fmt::Debug, + HeaderName: TryFrom, + >::Error: fmt::Debug + Into, V: header::IntoHeaderValue, V::Error: fmt::Debug, { diff --git a/awc/src/connect.rs b/awc/src/connect.rs index cc92fdbb6..44dbcd60a 100644 --- a/awc/src/connect.rs +++ b/awc/src/connect.rs @@ -1,7 +1,7 @@ use std::pin::Pin; use std::rc::Rc; use std::task::{Context, Poll}; -use std::{fmt, io, net}; +use std::{fmt, io, mem, net}; use actix_codec::{AsyncRead, AsyncWrite, Framed}; use actix_http::body::Body; @@ -201,7 +201,10 @@ impl fmt::Debug for BoxedSocket { } impl AsyncRead for BoxedSocket { - unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { + unsafe fn prepare_uninitialized_buffer( + &self, + buf: &mut [mem::MaybeUninit], + ) -> bool { self.0.as_read().prepare_uninitialized_buffer(buf) } diff --git a/awc/src/error.rs b/awc/src/error.rs index 8816c4075..7fece74ee 100644 --- a/awc/src/error.rs +++ b/awc/src/error.rs @@ -3,13 +3,14 @@ pub use actix_http::client::{ ConnectError, FreezeRequestError, InvalidUrl, SendRequestError, }; pub use actix_http::error::PayloadError; +pub use actix_http::http::Error as HttpError; pub use actix_http::ws::HandshakeError as WsHandshakeError; pub use actix_http::ws::ProtocolError as WsProtocolError; use actix_http::ResponseError; use serde_json::error::Error as JsonError; -use actix_http::http::{header::HeaderValue, Error as HttpError, StatusCode}; +use actix_http::http::{header::HeaderValue, StatusCode}; use derive_more::{Display, From}; /// Websocket client error diff --git a/awc/src/frozen.rs b/awc/src/frozen.rs index 61ba87aad..748a15d3b 100644 --- a/awc/src/frozen.rs +++ b/awc/src/frozen.rs @@ -1,3 +1,4 @@ +use std::convert::TryFrom; use std::net; use std::rc::Rc; use std::time::Duration; @@ -8,9 +9,7 @@ use serde::Serialize; use actix_http::body::Body; use actix_http::http::header::IntoHeaderValue; -use actix_http::http::{ - Error as HttpError, HeaderMap, HeaderName, HttpTryFrom, Method, Uri, -}; +use actix_http::http::{Error as HttpError, HeaderMap, HeaderName, Method, Uri}; use actix_http::{Error, RequestHead}; use crate::sender::{RequestSender, SendClientRequest}; @@ -112,7 +111,8 @@ impl FrozenClientRequest { /// Create a `FrozenSendBuilder` with an extra header pub fn extra_header(&self, key: K, value: V) -> FrozenSendBuilder where - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, V: IntoHeaderValue, { self.extra_headers(HeaderMap::new()) @@ -139,7 +139,8 @@ impl FrozenSendBuilder { /// Insert a header, it overrides existing header in `FrozenClientRequest`. pub fn extra_header(mut self, key: K, value: V) -> Self where - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, V: IntoHeaderValue, { match HeaderName::try_from(key) { diff --git a/awc/src/lib.rs b/awc/src/lib.rs index e995519ea..64784ed95 100644 --- a/awc/src/lib.rs +++ b/awc/src/lib.rs @@ -19,12 +19,13 @@ //! } //! ``` use std::cell::RefCell; +use std::convert::TryFrom; use std::rc::Rc; use std::time::Duration; pub use actix_http::{client::Connector, cookie, http}; -use actix_http::http::{HeaderMap, HttpTryFrom, Method, Uri}; +use actix_http::http::{Error as HttpError, HeaderMap, Method, Uri}; use actix_http::RequestHead; mod builder; @@ -102,7 +103,8 @@ impl Client { /// Construct HTTP request. pub fn request(&self, method: Method, url: U) -> ClientRequest where - Uri: HttpTryFrom, + Uri: TryFrom, + >::Error: Into, { let mut req = ClientRequest::new(method, url, self.0.clone()); @@ -118,7 +120,8 @@ impl Client { /// copies all headers and the method. pub fn request_from(&self, url: U, head: &RequestHead) -> ClientRequest where - Uri: HttpTryFrom, + Uri: TryFrom, + >::Error: Into, { let mut req = self.request(head.method.clone(), url); for (key, value) in head.headers.iter() { @@ -130,7 +133,8 @@ impl Client { /// Construct HTTP *GET* request. pub fn get(&self, url: U) -> ClientRequest where - Uri: HttpTryFrom, + Uri: TryFrom, + >::Error: Into, { self.request(Method::GET, url) } @@ -138,7 +142,8 @@ impl Client { /// Construct HTTP *HEAD* request. pub fn head(&self, url: U) -> ClientRequest where - Uri: HttpTryFrom, + Uri: TryFrom, + >::Error: Into, { self.request(Method::HEAD, url) } @@ -146,7 +151,8 @@ impl Client { /// Construct HTTP *PUT* request. pub fn put(&self, url: U) -> ClientRequest where - Uri: HttpTryFrom, + Uri: TryFrom, + >::Error: Into, { self.request(Method::PUT, url) } @@ -154,7 +160,8 @@ impl Client { /// Construct HTTP *POST* request. pub fn post(&self, url: U) -> ClientRequest where - Uri: HttpTryFrom, + Uri: TryFrom, + >::Error: Into, { self.request(Method::POST, url) } @@ -162,7 +169,8 @@ impl Client { /// Construct HTTP *PATCH* request. pub fn patch(&self, url: U) -> ClientRequest where - Uri: HttpTryFrom, + Uri: TryFrom, + >::Error: Into, { self.request(Method::PATCH, url) } @@ -170,7 +178,8 @@ impl Client { /// Construct HTTP *DELETE* request. pub fn delete(&self, url: U) -> ClientRequest where - Uri: HttpTryFrom, + Uri: TryFrom, + >::Error: Into, { self.request(Method::DELETE, url) } @@ -178,7 +187,8 @@ impl Client { /// Construct HTTP *OPTIONS* request. pub fn options(&self, url: U) -> ClientRequest where - Uri: HttpTryFrom, + Uri: TryFrom, + >::Error: Into, { self.request(Method::OPTIONS, url) } @@ -186,7 +196,8 @@ impl Client { /// Construct WebSockets request. pub fn ws(&self, url: U) -> ws::WebsocketsRequest where - Uri: HttpTryFrom, + Uri: TryFrom, + >::Error: Into, { let mut req = ws::WebsocketsRequest::new(url, self.0.clone()); for (key, value) in self.0.headers.iter() { diff --git a/awc/src/request.rs b/awc/src/request.rs index 3660f8086..5ca4973cd 100644 --- a/awc/src/request.rs +++ b/awc/src/request.rs @@ -1,10 +1,10 @@ +use std::convert::TryFrom; use std::fmt::Write as FmtWrite; -use std::io::Write; use std::rc::Rc; use std::time::Duration; use std::{fmt, net}; -use bytes::{BufMut, Bytes, BytesMut}; +use bytes::Bytes; use futures::Stream; use percent_encoding::percent_encode; use serde::Serialize; @@ -13,8 +13,8 @@ use actix_http::body::Body; use actix_http::cookie::{Cookie, CookieJar, USERINFO}; use actix_http::http::header::{self, Header, IntoHeaderValue}; use actix_http::http::{ - uri, ConnectionType, Error as HttpError, HeaderMap, HeaderName, HeaderValue, - HttpTryFrom, Method, Uri, Version, + uri, ConnectionType, Error as HttpError, HeaderMap, HeaderName, HeaderValue, Method, + Uri, Version, }; use actix_http::{Error, RequestHead}; @@ -67,7 +67,8 @@ impl ClientRequest { /// Create new client request builder. pub(crate) fn new(method: Method, uri: U, config: Rc) -> Self where - Uri: HttpTryFrom, + Uri: TryFrom, + >::Error: Into, { ClientRequest { config, @@ -86,7 +87,8 @@ impl ClientRequest { #[inline] pub fn uri(mut self, uri: U) -> Self where - Uri: HttpTryFrom, + Uri: TryFrom, + >::Error: Into, { match Uri::try_from(uri) { Ok(uri) => self.head.uri = uri, @@ -196,7 +198,8 @@ impl ClientRequest { /// ``` pub fn header(mut self, key: K, value: V) -> Self where - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, V: IntoHeaderValue, { match HeaderName::try_from(key) { @@ -212,7 +215,8 @@ impl ClientRequest { /// Insert a header, replaces existing header. pub fn set_header(mut self, key: K, value: V) -> Self where - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, V: IntoHeaderValue, { match HeaderName::try_from(key) { @@ -228,7 +232,8 @@ impl ClientRequest { /// Insert a header only if it is not yet set. pub fn set_header_if_none(mut self, key: K, value: V) -> Self where - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, V: IntoHeaderValue, { match HeaderName::try_from(key) { @@ -264,7 +269,8 @@ impl ClientRequest { #[inline] pub fn content_type(mut self, value: V) -> Self where - HeaderValue: HttpTryFrom, + HeaderValue: TryFrom, + >::Error: Into, { match HeaderValue::try_from(value) { Ok(value) => self.head.headers.insert(header::CONTENT_TYPE, value), @@ -276,9 +282,7 @@ impl ClientRequest { /// Set content length #[inline] pub fn content_length(self, len: u64) -> Self { - let mut wrt = BytesMut::new().writer(); - let _ = write!(wrt, "{}", len); - self.header(header::CONTENT_LENGTH, wrt.get_mut().take().freeze()) + self.header(header::CONTENT_LENGTH, len) } /// Set HTTP basic authorization header @@ -513,9 +517,9 @@ impl ClientRequest { let uri = &self.head.uri; if uri.host().is_none() { return Err(InvalidUrl::MissingHost.into()); - } else if uri.scheme_part().is_none() { + } else if uri.scheme().is_none() { return Err(InvalidUrl::MissingScheme.into()); - } else if let Some(scheme) = uri.scheme_part() { + } else if let Some(scheme) = uri.scheme() { match scheme.as_str() { "http" | "ws" | "https" | "wss" => (), _ => return Err(InvalidUrl::UnknownScheme.into()), @@ -551,7 +555,7 @@ impl ClientRequest { let https = slf .head .uri - .scheme_part() + .scheme() .map(|s| s == &uri::Scheme::HTTPS) .unwrap_or(true); diff --git a/awc/src/response.rs b/awc/src/response.rs index 00ab4cee1..cb33e8a2b 100644 --- a/awc/src/response.rs +++ b/awc/src/response.rs @@ -348,7 +348,7 @@ where continue; } } - Poll::Ready(None) => Poll::Ready(Ok(this.buf.take().freeze())), + Poll::Ready(None) => Poll::Ready(Ok(this.buf.split().freeze())), Poll::Pending => Poll::Pending, }; } diff --git a/awc/src/test.rs b/awc/src/test.rs index 641ecaa88..a6cbd03e6 100644 --- a/awc/src/test.rs +++ b/awc/src/test.rs @@ -1,9 +1,10 @@ //! Test helpers for actix http client to use during testing. +use std::convert::TryFrom; use std::fmt::Write as FmtWrite; use actix_http::cookie::{Cookie, CookieJar, USERINFO}; use actix_http::http::header::{self, Header, HeaderValue, IntoHeaderValue}; -use actix_http::http::{HeaderName, HttpTryFrom, StatusCode, Version}; +use actix_http::http::{Error as HttpError, HeaderName, StatusCode, Version}; use actix_http::{h1, Payload, ResponseHead}; use bytes::Bytes; use percent_encoding::percent_encode; @@ -31,7 +32,8 @@ impl TestResponse { /// Create TestResponse and set header pub fn with_header(key: K, value: V) -> Self where - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, V: IntoHeaderValue, { Self::default().header(key, value) @@ -55,7 +57,8 @@ impl TestResponse { /// Append a header pub fn header(mut self, key: K, value: V) -> Self where - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, V: IntoHeaderValue, { if let Ok(key) = HeaderName::try_from(key) { diff --git a/awc/src/ws.rs b/awc/src/ws.rs index 075c83562..e6f8e6968 100644 --- a/awc/src/ws.rs +++ b/awc/src/ws.rs @@ -1,4 +1,5 @@ //! Websockets client +use std::convert::TryFrom; use std::fmt::Write as FmtWrite; use std::net::SocketAddr; use std::rc::Rc; @@ -7,7 +8,7 @@ use std::{fmt, str}; use actix_codec::Framed; use actix_http::cookie::{Cookie, CookieJar}; use actix_http::{ws, Payload, RequestHead}; -use actix_rt::time::Timeout; +use actix_rt::time::timeout; use percent_encoding::percent_encode; use actix_http::cookie::USERINFO; @@ -19,7 +20,7 @@ use crate::http::header::{ self, HeaderName, HeaderValue, IntoHeaderValue, AUTHORIZATION, }; use crate::http::{ - ConnectionType, Error as HttpError, HttpTryFrom, Method, StatusCode, Uri, Version, + ConnectionType, Error as HttpError, Method, StatusCode, Uri, Version, }; use crate::response::ClientResponse; use crate::ClientConfig; @@ -41,7 +42,8 @@ impl WebsocketsRequest { /// Create new websocket connection pub(crate) fn new(uri: U, config: Rc) -> Self where - Uri: HttpTryFrom, + Uri: TryFrom, + >::Error: Into, { let mut err = None; let mut head = RequestHead::default(); @@ -102,9 +104,10 @@ impl WebsocketsRequest { } /// Set request Origin - pub fn origin(mut self, origin: V) -> Self + pub fn origin(mut self, origin: V) -> Self where - HeaderValue: HttpTryFrom, + HeaderValue: TryFrom, + HttpError: From, { match HeaderValue::try_from(origin) { Ok(value) => self.origin = Some(value), @@ -133,7 +136,8 @@ impl WebsocketsRequest { /// To override header use `set_header()` method. pub fn header(mut self, key: K, value: V) -> Self where - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, V: IntoHeaderValue, { match HeaderName::try_from(key) { @@ -151,7 +155,8 @@ impl WebsocketsRequest { /// Insert a header, replaces existing header. pub fn set_header(mut self, key: K, value: V) -> Self where - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, V: IntoHeaderValue, { match HeaderName::try_from(key) { @@ -169,7 +174,8 @@ impl WebsocketsRequest { /// Insert a header only if it is not yet set. pub fn set_header_if_none(mut self, key: K, value: V) -> Self where - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, V: IntoHeaderValue, { match HeaderName::try_from(key) { @@ -220,9 +226,9 @@ impl WebsocketsRequest { let uri = &self.head.uri; if uri.host().is_none() { return Err(InvalidUrl::MissingHost.into()); - } else if uri.scheme_part().is_none() { + } else if uri.scheme().is_none() { return Err(InvalidUrl::MissingScheme.into()); - } else if let Some(scheme) = uri.scheme_part() { + } else if let Some(scheme) = uri.scheme() { match scheme.as_str() { "http" | "ws" | "https" | "wss" => (), _ => return Err(InvalidUrl::UnknownScheme.into()), @@ -295,8 +301,8 @@ impl WebsocketsRequest { .open_tunnel(head, self.addr); // set request timeout - let (head, framed) = if let Some(timeout) = self.config.timeout { - Timeout::new(fut, timeout) + let (head, framed) = if let Some(to) = self.config.timeout { + timeout(to, fut) .await .map_err(|_| SendRequestError::Timeout.into()) .and_then(|res| res)? diff --git a/awc/tests/test_rustls_client.rs b/awc/tests/test_rustls_client.rs index ac60d8e83..a6ced89d3 100644 --- a/awc/tests/test_rustls_client.rs +++ b/awc/tests/test_rustls_client.rs @@ -1,21 +1,17 @@ #![cfg(feature = "rustls")] -use rust_tls::ClientConfig; - -use std::io::Result; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; -use actix_codec::{AsyncRead, AsyncWrite}; use actix_http::HttpService; use actix_http_test::TestServer; -use actix_server::ssl::OpensslAcceptor; use actix_service::{pipeline_factory, ServiceFactory}; use actix_web::http::Version; use actix_web::{web, App, HttpResponse}; use futures::future::ok; use open_ssl::ssl::{SslAcceptor, SslFiletype, SslMethod, SslVerifyMode}; +use rust_tls::ClientConfig; -fn ssl_acceptor() -> Result> { +fn ssl_acceptor() -> SslAcceptor { // load ssl keys let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); builder.set_verify_callback(SslVerifyMode::NONE, |_, _| true); @@ -33,8 +29,8 @@ fn ssl_acceptor() -> Result> { Err(open_ssl::ssl::AlpnError::NOACK) } }); - builder.set_alpn_protos(b"\x02h2")?; - Ok(actix_server::ssl::OpensslAcceptor::new(builder.build())) + builder.set_alpn_protos(b"\x02h2").unwrap(); + builder.build() } mod danger { @@ -55,7 +51,6 @@ mod danger { // #[actix_rt::test] async fn _test_connection_reuse_h2() { - let openssl = ssl_acceptor().unwrap(); let num = Arc::new(AtomicUsize::new(0)); let num2 = num.clone(); @@ -65,15 +60,11 @@ async fn _test_connection_reuse_h2() { num2.fetch_add(1, Ordering::Relaxed); ok(io) }) - .and_then( - openssl - .clone() - .map_err(|e| println!("Openssl error: {}", e)), - ) .and_then( HttpService::build() .h2(App::new() .service(web::resource("/").route(web::to(|| HttpResponse::Ok())))) + .openssl(ssl_acceptor()) .map_err(|_| ()), ) }); diff --git a/awc/tests/test_ws.rs b/awc/tests/test_ws.rs index d90f55531..2f7ba2732 100644 --- a/awc/tests/test_ws.rs +++ b/awc/tests/test_ws.rs @@ -63,10 +63,7 @@ async fn test_simple() { .await .unwrap(); let item = framed.next().await.unwrap().unwrap(); - assert_eq!( - item, - ws::Frame::Binary(Some(Bytes::from_static(b"text").into())) - ); + assert_eq!(item, ws::Frame::Binary(Some(BytesMut::from(&b"text"[..])))); framed.send(ws::Message::Ping("text".into())).await.unwrap(); let item = framed.next().await.unwrap().unwrap(); diff --git a/src/guard.rs b/src/guard.rs index 3db525f9a..aaa99a9ec 100644 --- a/src/guard.rs +++ b/src/guard.rs @@ -24,9 +24,10 @@ //! ); //! } //! ``` - #![allow(non_snake_case)] -use actix_http::http::{self, header, uri::Uri, HttpTryFrom}; +use std::convert::TryFrom; + +use actix_http::http::{self, header, uri::Uri}; use actix_http::RequestHead; /// Trait defines resource guards. Guards are used for route selection. diff --git a/src/info.rs b/src/info.rs index a9c3e4eeb..c9a642b36 100644 --- a/src/info.rs +++ b/src/info.rs @@ -76,7 +76,7 @@ impl ConnectionInfo { } } if scheme.is_none() { - scheme = req.uri.scheme_part().map(|a| a.as_str()); + scheme = req.uri.scheme().map(|a| a.as_str()); if scheme.is_none() && cfg.secure() { scheme = Some("https") } @@ -98,7 +98,7 @@ impl ConnectionInfo { host = h.to_str().ok(); } if host.is_none() { - host = req.uri.authority_part().map(|a| a.as_str()); + host = req.uri.authority().map(|a| a.as_str()); if host.is_none() { host = Some(cfg.host()); } diff --git a/src/middleware/defaultheaders.rs b/src/middleware/defaultheaders.rs index 05a031065..14d035ab8 100644 --- a/src/middleware/defaultheaders.rs +++ b/src/middleware/defaultheaders.rs @@ -1,4 +1,5 @@ //! Middleware for setting default response headers +use std::convert::TryFrom; use std::rc::Rc; use std::task::{Context, Poll}; @@ -6,7 +7,7 @@ use actix_service::{Service, Transform}; use futures::future::{ok, FutureExt, LocalBoxFuture, Ready}; use crate::http::header::{HeaderName, HeaderValue, CONTENT_TYPE}; -use crate::http::{HeaderMap, HttpTryFrom}; +use crate::http::{Error as HttpError, HeaderMap}; use crate::service::{ServiceRequest, ServiceResponse}; use crate::Error; @@ -58,8 +59,10 @@ impl DefaultHeaders { #[inline] pub fn header(mut self, key: K, value: V) -> Self where - HeaderName: HttpTryFrom, - HeaderValue: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, + HeaderValue: TryFrom, + >::Error: Into, { #[allow(clippy::match_wild_err_arm)] match HeaderName::try_from(key) { diff --git a/src/middleware/logger.rs b/src/middleware/logger.rs index a57ea2961..60c10b207 100644 --- a/src/middleware/logger.rs +++ b/src/middleware/logger.rs @@ -1,5 +1,6 @@ //! Request logging middleware use std::collections::HashSet; +use std::convert::TryFrom; use std::env; use std::fmt::{self, Display, Formatter}; use std::future::Future; @@ -17,7 +18,7 @@ use time; use crate::dev::{BodySize, MessageBody, ResponseBody}; use crate::error::{Error, Result}; -use crate::http::{HeaderName, HttpTryFrom, StatusCode}; +use crate::http::{HeaderName, StatusCode}; use crate::service::{ServiceRequest, ServiceResponse}; use crate::HttpResponse; diff --git a/src/middleware/normalize.rs b/src/middleware/normalize.rs index 2926eacc9..6bff068bc 100644 --- a/src/middleware/normalize.rs +++ b/src/middleware/normalize.rs @@ -1,7 +1,7 @@ //! `Middleware` to normalize request's URI use std::task::{Context, Poll}; -use actix_http::http::{HttpTryFrom, PathAndQuery, Uri}; +use actix_http::http::{PathAndQuery, Uri}; use actix_service::{Service, Transform}; use bytes::Bytes; use futures::future::{ok, Ready}; @@ -74,7 +74,6 @@ where fn call(&mut self, mut req: ServiceRequest) -> Self::Future { let head = req.head_mut(); - let path = head.uri.path(); let original_len = path.len(); let path = self.merge_slash.replace_all(path, "/"); @@ -86,9 +85,10 @@ where let path = if let Some(q) = pq.query() { Bytes::from(format!("{}?{}", path, q)) } else { - Bytes::from(path.as_ref()) + Bytes::copy_from_slice(path.as_bytes()) }; - parts.path_and_query = Some(PathAndQuery::try_from(path).unwrap()); + parts.path_and_query = Some(PathAndQuery::from_maybe_shared(path).unwrap()); + drop(head); let uri = Uri::from_parts(parts).unwrap(); req.match_info_mut().get_mut().update(&uri); diff --git a/src/responder.rs b/src/responder.rs index 7b30315f5..48eae09b6 100644 --- a/src/responder.rs +++ b/src/responder.rs @@ -1,3 +1,4 @@ +use std::convert::TryFrom; use std::future::Future; use std::marker::PhantomData; use std::pin::Pin; @@ -5,8 +6,7 @@ use std::task::{Context, Poll}; use actix_http::error::InternalError; use actix_http::http::{ - header::IntoHeaderValue, Error as HttpError, HeaderMap, HeaderName, HttpTryFrom, - StatusCode, + header::IntoHeaderValue, Error as HttpError, HeaderMap, HeaderName, StatusCode, }; use actix_http::{Error, Response, ResponseBuilder}; use bytes::{Bytes, BytesMut}; @@ -68,7 +68,8 @@ pub trait Responder { fn with_header(self, key: K, value: V) -> CustomResponder where Self: Sized, - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, V: IntoHeaderValue, { CustomResponder::new(self).with_header(key, value) @@ -267,7 +268,8 @@ impl CustomResponder { /// ``` pub fn with_header(mut self, key: K, value: V) -> Self where - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, V: IntoHeaderValue, { if self.headers.is_none() { diff --git a/src/server.rs b/src/server.rs index f3ec550cf..f5883c0d0 100644 --- a/src/server.rs +++ b/src/server.rs @@ -14,9 +14,9 @@ use parking_lot::Mutex; use net2::TcpBuilder; #[cfg(feature = "openssl")] -use open_ssl::ssl::{SslAcceptor, SslAcceptorBuilder}; +use actix_tls::openssl::{SslAcceptor, SslAcceptorBuilder}; #[cfg(feature = "rustls")] -use rust_tls::ServerConfig as RustlsServerConfig; +use actix_tls::rustls::ServerConfig as RustlsServerConfig; struct Socket { scheme: &'static str, @@ -315,15 +315,8 @@ where fn listen_rustls_inner( mut self, lst: net::TcpListener, - mut config: RustlsServerConfig, + config: RustlsServerConfig, ) -> io::Result { - use actix_server::ssl::{RustlsAcceptor, SslError}; - use actix_service::pipeline_factory; - - let protos = vec!["h2".to_string().into(), "http/1.1".to_string().into()]; - config.set_protocols(&protos); - - let acceptor = RustlsAcceptor::new(config); let factory = self.factory.clone(); let cfg = self.config.clone(); let addr = lst.local_addr().unwrap(); @@ -337,15 +330,12 @@ where lst, move || { let c = cfg.lock(); - pipeline_factory(acceptor.clone().map_err(SslError::Ssl)).and_then( - HttpService::build() - .keep_alive(c.keep_alive) - .client_timeout(c.client_timeout) - .client_disconnect(c.client_shutdown) - .finish(factory()) - .map_err(SslError::Service) - .map_init_err(|_| ()), - ) + HttpService::build() + .keep_alive(c.keep_alive) + .client_timeout(c.client_timeout) + .client_disconnect(c.client_shutdown) + .finish(factory()) + .rustls(config.clone()) }, )?; Ok(self) @@ -530,14 +520,13 @@ where /// use std::io; /// use actix_web::{web, App, HttpResponse, HttpServer}; /// - /// fn main() -> io::Result<()> { - /// let sys = actix_rt::System::new("example"); // <- create Actix system - /// + /// #[actix_rt::main] + /// async fn main() -> io::Result<()> { + /// # actix_rt::System::current().stop(); /// HttpServer::new(|| App::new().service(web::resource("/").to(|| HttpResponse::Ok()))) /// .bind("127.0.0.1:0")? - /// .start(); - /// # actix_rt::System::current().stop(); - /// sys.run() // <- Run actix system, this method starts all async processes + /// .start() + /// .await /// } /// ``` pub fn start(self) -> Server { diff --git a/src/test.rs b/src/test.rs index 82ba97fec..5e50f24e1 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,8 +1,9 @@ //! Various helpers for Actix applications to use during testing. +use std::convert::TryFrom; use std::rc::Rc; use actix_http::http::header::{ContentType, Header, HeaderName, IntoHeaderValue}; -use actix_http::http::{HttpTryFrom, Method, StatusCode, Uri, Version}; +use actix_http::http::{Error as HttpError, Method, StatusCode, Uri, Version}; use actix_http::test::TestRequest as HttpTestRequest; use actix_http::{cookie::Cookie, Extensions, Request}; use actix_router::{Path, ResourceDef, Url}; @@ -319,7 +320,8 @@ impl TestRequest { /// Create TestRequest and set header pub fn with_header(key: K, value: V) -> TestRequest where - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, V: IntoHeaderValue, { TestRequest::default().header(key, value) @@ -377,7 +379,8 @@ impl TestRequest { /// Set a header pub fn header(mut self, key: K, value: V) -> Self where - HeaderName: HttpTryFrom, + HeaderName: TryFrom, + >::Error: Into, V: IntoHeaderValue, { self.req.header(key, value); diff --git a/test-server/Cargo.toml b/test-server/Cargo.toml index b3a225f3d..0f6af8ff2 100644 --- a/test-server/Cargo.toml +++ b/test-server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-http-test" -version = "0.3.0-alpha.2" +version = "0.3.0-alpha.3" authors = ["Nikolay Kim "] description = "Actix http test server" readme = "README.md" @@ -30,19 +30,19 @@ default = [] openssl = ["open-ssl", "awc/openssl", ] # "actix-tls/openssl"] [dependencies] -actix-service = "1.0.0-alpha.2" -actix-codec = "0.2.0-alpha.2" -actix-connect = "1.0.0-alpha.2" -actix-utils = "1.0.0-alpha.2" -actix-rt = "1.0.0-alpha.2" -actix-server = "1.0.0-alpha.2" -actix-testing = "1.0.0-alpha.2" -awc = "0.3.0-alpha.2" +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-server = "1.0.0-alpha.3" +actix-testing = "1.0.0-alpha.3" +awc = "0.3.0-alpha.3" base64 = "0.11" -bytes = "0.4" +bytes = "0.5.2" futures = "0.3.1" -http = "0.1.8" +http = "0.2.0" log = "0.4" env_logger = "0.6" net2 = "0.2" @@ -55,5 +55,5 @@ time = "0.1" open-ssl = { version="0.10", package="openssl", optional = true } [dev-dependencies] -actix-web = "2.0.0-alpha.2" -actix-http = "0.3.0-alpha.2" +actix-web = "2.0.0-alpha.3" +actix-http = "0.3.0-alpha.3"