mirror of
https://github.com/fafhrd91/actix-web
synced 2024-11-24 00:21:08 +01:00
upgrade to tokio 0.2
This commit is contained in:
parent
b45c6cd66b
commit
205a964d8f
@ -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
|
||||
|
34
Cargo.toml
34
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 <fafhrd91@gmail.com>"]
|
||||
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" }
|
||||
|
@ -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
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "actix-cors"
|
||||
version = "0.2.0-alpha.1"
|
||||
version = "0.2.0-alpha.3"
|
||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||
description = "Cross-origin resource sharing (CORS) for Actix applications."
|
||||
readme = "README.md"
|
||||
|
@ -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<U, M>(mut self, methods: U) -> Cors
|
||||
where
|
||||
U: IntoIterator<Item = M>,
|
||||
Method: HttpTryFrom<M>,
|
||||
Method: TryFrom<M>,
|
||||
<Method as TryFrom<M>>::Error: Into<HttpError>,
|
||||
{
|
||||
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<H>(mut self, header: H) -> Cors
|
||||
where
|
||||
HeaderName: HttpTryFrom<H>,
|
||||
HeaderName: TryFrom<H>,
|
||||
<HeaderName as TryFrom<H>>::Error: Into<HttpError>,
|
||||
{
|
||||
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<U, H>(mut self, headers: U) -> Cors
|
||||
where
|
||||
U: IntoIterator<Item = H>,
|
||||
HeaderName: HttpTryFrom<H>,
|
||||
HeaderName: TryFrom<H>,
|
||||
<HeaderName as TryFrom<H>>::Error: Into<HttpError>,
|
||||
{
|
||||
if let Some(cors) = cors(&mut self.cors, &self.error) {
|
||||
for h in headers {
|
||||
@ -362,7 +366,8 @@ impl Cors {
|
||||
pub fn expose_headers<U, H>(mut self, headers: U) -> Cors
|
||||
where
|
||||
U: IntoIterator<Item = H>,
|
||||
HeaderName: HttpTryFrom<H>,
|
||||
HeaderName: TryFrom<H>,
|
||||
<HeaderName as TryFrom<H>>::Error: Into<HttpError>,
|
||||
{
|
||||
for h in headers {
|
||||
match HeaderName::try_from(h) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "actix-files"
|
||||
version = "0.2.0-alpha.2"
|
||||
version = "0.2.0-alpha.3"
|
||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||
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"
|
||||
|
@ -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"
|
||||
|
@ -123,7 +123,9 @@ impl<Io, S> FramedRequest<Io, S> {
|
||||
|
||||
#[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::*;
|
||||
|
@ -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<K, V>(key: K, value: V) -> Self
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
{
|
||||
Self::default().header(key, value)
|
||||
@ -96,7 +98,8 @@ impl<S> TestRequest<S> {
|
||||
/// Set a header
|
||||
pub fn header<K, V>(mut self, key: K, value: V) -> Self
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
{
|
||||
self.req.header(key, value);
|
||||
|
@ -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();
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "actix-http"
|
||||
version = "0.3.0-alpha.2"
|
||||
version = "0.3.0-alpha.3"
|
||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||
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" }
|
||||
|
@ -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<String> 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)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<u8>],
|
||||
) -> bool {
|
||||
match self {
|
||||
EitherIo::A(ref val) => val.prepare_uninitialized_buffer(buf),
|
||||
EitherIo::B(ref val) => val.prepare_uninitialized_buffer(buf),
|
||||
|
@ -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,
|
||||
|
@ -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<actix_connect::ConnectError> for ConnectError {
|
||||
}
|
||||
|
||||
#[cfg(feature = "openssl")]
|
||||
impl<T> From<HandshakeError<T>> for ConnectError {
|
||||
impl<T: std::fmt::Debug> From<HandshakeError<T>> for ConnectError {
|
||||
fn from(err: HandshakeError<T>) -> 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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<T: AsyncRead + AsyncWrite + Unpin + 'static> AsyncRead for H1Connection<T> {
|
||||
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
|
||||
unsafe fn prepare_uninitialized_buffer(
|
||||
&self,
|
||||
buf: &mut [mem::MaybeUninit<u8>],
|
||||
) -> bool {
|
||||
self.io.as_ref().unwrap().prepare_uninitialized_buffer(buf)
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)));
|
||||
|
@ -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<Delay> {
|
||||
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<Delay> {
|
||||
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
|
||||
}
|
||||
|
@ -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<B: MessageBody> MessageBody for Encoder<B> {
|
||||
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()),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ impl Writer {
|
||||
}
|
||||
}
|
||||
fn take(&mut self) -> Bytes {
|
||||
self.buf.take().freeze()
|
||||
self.buf.split().freeze()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<std::convert::Infallible> 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<T: std::fmt::Debug> ResponseError for open_ssl::ssl::HandshakeError<T> {}
|
||||
impl<T: std::fmt::Debug> ResponseError for actix_tls::openssl::HandshakeError<T> {}
|
||||
|
||||
/// 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 {
|
||||
|
@ -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();
|
||||
|
@ -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() {
|
||||
|
@ -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"));
|
||||
|
@ -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<S, B, X, U> H1Service<SslStream<TcpStream>, 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<S, B, X, U> H1Service<TlsStream<TcpStream>, S, B, X, U>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S::Error: Into<Error>,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>>,
|
||||
B: MessageBody,
|
||||
X: ServiceFactory<Config = (), Request = Request, Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
X::InitError: fmt::Debug,
|
||||
U: ServiceFactory<
|
||||
Config = (),
|
||||
Request = (Request, Framed<TlsStream<TcpStream>, 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<io::Error, DispatchError>,
|
||||
InitError = (),
|
||||
> {
|
||||
pipeline_factory(
|
||||
Acceptor::new(config)
|
||||
.map_err(SslError::Ssl)
|
||||
.map_init_err(|_| panic!()),
|
||||
)
|
||||
.and_then(|io: TlsStream<TcpStream>| {
|
||||
let peer_addr = io.get_ref().0.peer_addr().ok();
|
||||
ok((io, peer_addr))
|
||||
})
|
||||
.and_then(self.map_err(SslError::Service))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, B, X, U> H1Service<T, S, B, X, U>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
|
@ -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
|
||||
|
@ -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)))
|
||||
|
@ -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<S, B> H2Service<TlsStream<TcpStream>, S, B>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
B: MessageBody + 'static,
|
||||
{
|
||||
/// Create openssl based service
|
||||
pub fn rustls(
|
||||
self,
|
||||
mut config: ServerConfig,
|
||||
) -> impl ServiceFactory<
|
||||
Config = (),
|
||||
Request = TcpStream,
|
||||
Response = (),
|
||||
Error = SslError<io::Error, DispatchError>,
|
||||
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<TcpStream>| {
|
||||
let peer_addr = io.get_ref().0.peer_addr().ok();
|
||||
ok((io, peer_addr))
|
||||
}))
|
||||
}))
|
||||
.and_then(self.map_err(SslError::Service))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, B> ServiceFactory for H2Service<T, S, B>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
|
@ -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<header::HeaderValue, Self::Error> {
|
||||
let mut writer = Writer::new();
|
||||
let _ = write!(&mut writer, "{}", self);
|
||||
header::HeaderValue::from_shared(writer.take())
|
||||
header::HeaderValue::from_maybe_shared(writer.take())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -462,12 +462,12 @@ impl ContentDisposition {
|
||||
}
|
||||
|
||||
impl IntoHeaderValue for ContentDisposition {
|
||||
type Error = header::InvalidHeaderValueBytes;
|
||||
type Error = header::InvalidHeaderValue;
|
||||
|
||||
fn try_into(self) -> Result<header::HeaderValue, Self::Error> {
|
||||
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]
|
||||
|
@ -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<HeaderValue, Self::Error> {
|
||||
let mut writer = Writer::new();
|
||||
let _ = write!(&mut writer, "{}", self);
|
||||
HeaderValue::from_shared(writer.take())
|
||||
HeaderValue::from_maybe_shared(writer.take())
|
||||
}
|
||||
}
|
||||
|
@ -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<HeaderValue, Self::Error> {
|
||||
let mut writer = Writer::new();
|
||||
let _ = write!(&mut writer, "{}", self);
|
||||
HeaderValue::from_shared(writer.take())
|
||||
HeaderValue::from_maybe_shared(writer.take())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -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
|
||||
///
|
||||
|
@ -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, Self::Error> {
|
||||
HeaderValue::from_shared(self)
|
||||
HeaderValue::from_maybe_shared(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoHeaderValue for Vec<u8> {
|
||||
type Error = InvalidHeaderValueBytes;
|
||||
type Error = InvalidHeaderValue;
|
||||
|
||||
#[inline]
|
||||
fn try_into(self) -> Result<HeaderValue, Self::Error> {
|
||||
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, Self::Error> {
|
||||
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<HeaderValue, Self::Error> {
|
||||
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<HeaderValue, Self::Error> {
|
||||
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, Self::Error> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<HeaderValue, Self::Error> {
|
||||
let mut wrt = Writer::new();
|
||||
write!(wrt, "{}", self).unwrap();
|
||||
HeaderValue::from_shared(wrt.take())
|
||||
HeaderValue::from_maybe_shared(wrt.take())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<SystemTime> for HttpDate {
|
||||
}
|
||||
|
||||
impl IntoHeaderValue for HttpDate {
|
||||
type Error = InvalidHeaderValueBytes;
|
||||
type Error = InvalidHeaderValue;
|
||||
|
||||
fn try_into(self) -> Result<HeaderValue, Self::Error> {
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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"[..]);
|
||||
}
|
||||
}
|
||||
|
@ -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};
|
||||
|
@ -187,7 +187,7 @@ impl<P> fmt::Debug for Request<P> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use http::HttpTryFrom;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
#[test]
|
||||
fn test_basics() {
|
||||
|
@ -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<K, V>(&mut self, key: K, value: V) -> &mut Self
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
{
|
||||
if let Some(parts) = parts(&mut self.head, &self.err) {
|
||||
@ -416,7 +417,8 @@ impl ResponseBuilder {
|
||||
/// ```
|
||||
pub fn set_header<K, V>(&mut self, key: K, value: V) -> &mut Self
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
{
|
||||
if let Some(parts) = parts(&mut self.head, &self.err) {
|
||||
@ -485,7 +487,8 @@ impl ResponseBuilder {
|
||||
#[inline]
|
||||
pub fn content_type<V>(&mut self, value: V) -> &mut Self
|
||||
where
|
||||
HeaderValue: HttpTryFrom<V>,
|
||||
HeaderValue: TryFrom<V>,
|
||||
<HeaderValue as TryFrom<V>>::Error: Into<HttpError>,
|
||||
{
|
||||
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
|
||||
|
@ -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<S, B, X, U> HttpService<SslStream<TcpStream>, 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<S, B, X, U> HttpService<TlsStream<TcpStream>, S, B, X, U>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
B: MessageBody + 'static,
|
||||
X: ServiceFactory<Config = (), Request = Request, Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
X::InitError: fmt::Debug,
|
||||
<X::Service as Service>::Future: 'static,
|
||||
U: ServiceFactory<
|
||||
Config = (),
|
||||
Request = (Request, Framed<TlsStream<TcpStream>, h1::Codec>),
|
||||
Response = (),
|
||||
>,
|
||||
U::Error: fmt::Display,
|
||||
U::InitError: fmt::Debug,
|
||||
<U::Service as Service>::Future: 'static,
|
||||
{
|
||||
/// Create openssl based service
|
||||
pub fn rustls(
|
||||
self,
|
||||
mut config: ServerConfig,
|
||||
) -> impl ServiceFactory<
|
||||
Config = (),
|
||||
Request = TcpStream,
|
||||
Response = (),
|
||||
Error = SslError<io::Error, DispatchError>,
|
||||
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<TcpStream>| {
|
||||
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<T, S, B, X, U> ServiceFactory for HttpService<T, S, B, X, U>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
|
@ -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<K, V>(key: K, value: V) -> TestRequest
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
{
|
||||
TestRequest::default().header(key, value).take()
|
||||
@ -118,7 +120,8 @@ impl TestRequest {
|
||||
/// Set a header
|
||||
pub fn header<K, V>(&mut self, key: K, value: V) -> &mut Self
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
{
|
||||
if let Ok(key) = HeaderName::try_from(key) {
|
||||
|
@ -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 {
|
||||
|
@ -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<T: AsyncRead + AsyncWrite>() -> io::Result<RustlsAcceptor<T, ()>> {
|
||||
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<T: AsyncRead + AsyncWrite>() -> io::Result<RustlsAcceptor<T, ()>
|
||||
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::<Response, Error>(error::ErrorBadRequest("error")))
|
||||
.map_err(|_| ()),
|
||||
)
|
||||
HttpService::build()
|
||||
.h2(|_| err::<Response, Error>(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::<Response, Error>(error::ErrorBadRequest("error")))
|
||||
.rustls(ssl_acceptor())
|
||||
});
|
||||
|
||||
let response = srv.sget("/").send().await.unwrap();
|
||||
|
@ -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();
|
||||
|
@ -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"
|
||||
bytes = "0.5.2"
|
@ -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"
|
||||
|
@ -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<Option<Bytes>, 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
|
||||
|
@ -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"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "awc"
|
||||
version = "0.3.0-alpha.2"
|
||||
version = "0.3.0-alpha.3"
|
||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||
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"
|
||||
|
@ -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<K, V>(mut self, key: K, value: V) -> Self
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
<HeaderName as HttpTryFrom<K>>::Error: fmt::Debug,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: fmt::Debug + Into<HttpError>,
|
||||
V: header::IntoHeaderValue,
|
||||
V::Error: fmt::Debug,
|
||||
{
|
||||
|
@ -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<u8>],
|
||||
) -> bool {
|
||||
self.0.as_read().prepare_uninitialized_buffer(buf)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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<K, V>(&self, key: K, value: V) -> FrozenSendBuilder
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
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<K, V>(mut self, key: K, value: V) -> Self
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
{
|
||||
match HeaderName::try_from(key) {
|
||||
|
@ -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<U>(&self, method: Method, url: U) -> ClientRequest
|
||||
where
|
||||
Uri: HttpTryFrom<U>,
|
||||
Uri: TryFrom<U>,
|
||||
<Uri as TryFrom<U>>::Error: Into<HttpError>,
|
||||
{
|
||||
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<U>(&self, url: U, head: &RequestHead) -> ClientRequest
|
||||
where
|
||||
Uri: HttpTryFrom<U>,
|
||||
Uri: TryFrom<U>,
|
||||
<Uri as TryFrom<U>>::Error: Into<HttpError>,
|
||||
{
|
||||
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<U>(&self, url: U) -> ClientRequest
|
||||
where
|
||||
Uri: HttpTryFrom<U>,
|
||||
Uri: TryFrom<U>,
|
||||
<Uri as TryFrom<U>>::Error: Into<HttpError>,
|
||||
{
|
||||
self.request(Method::GET, url)
|
||||
}
|
||||
@ -138,7 +142,8 @@ impl Client {
|
||||
/// Construct HTTP *HEAD* request.
|
||||
pub fn head<U>(&self, url: U) -> ClientRequest
|
||||
where
|
||||
Uri: HttpTryFrom<U>,
|
||||
Uri: TryFrom<U>,
|
||||
<Uri as TryFrom<U>>::Error: Into<HttpError>,
|
||||
{
|
||||
self.request(Method::HEAD, url)
|
||||
}
|
||||
@ -146,7 +151,8 @@ impl Client {
|
||||
/// Construct HTTP *PUT* request.
|
||||
pub fn put<U>(&self, url: U) -> ClientRequest
|
||||
where
|
||||
Uri: HttpTryFrom<U>,
|
||||
Uri: TryFrom<U>,
|
||||
<Uri as TryFrom<U>>::Error: Into<HttpError>,
|
||||
{
|
||||
self.request(Method::PUT, url)
|
||||
}
|
||||
@ -154,7 +160,8 @@ impl Client {
|
||||
/// Construct HTTP *POST* request.
|
||||
pub fn post<U>(&self, url: U) -> ClientRequest
|
||||
where
|
||||
Uri: HttpTryFrom<U>,
|
||||
Uri: TryFrom<U>,
|
||||
<Uri as TryFrom<U>>::Error: Into<HttpError>,
|
||||
{
|
||||
self.request(Method::POST, url)
|
||||
}
|
||||
@ -162,7 +169,8 @@ impl Client {
|
||||
/// Construct HTTP *PATCH* request.
|
||||
pub fn patch<U>(&self, url: U) -> ClientRequest
|
||||
where
|
||||
Uri: HttpTryFrom<U>,
|
||||
Uri: TryFrom<U>,
|
||||
<Uri as TryFrom<U>>::Error: Into<HttpError>,
|
||||
{
|
||||
self.request(Method::PATCH, url)
|
||||
}
|
||||
@ -170,7 +178,8 @@ impl Client {
|
||||
/// Construct HTTP *DELETE* request.
|
||||
pub fn delete<U>(&self, url: U) -> ClientRequest
|
||||
where
|
||||
Uri: HttpTryFrom<U>,
|
||||
Uri: TryFrom<U>,
|
||||
<Uri as TryFrom<U>>::Error: Into<HttpError>,
|
||||
{
|
||||
self.request(Method::DELETE, url)
|
||||
}
|
||||
@ -178,7 +187,8 @@ impl Client {
|
||||
/// Construct HTTP *OPTIONS* request.
|
||||
pub fn options<U>(&self, url: U) -> ClientRequest
|
||||
where
|
||||
Uri: HttpTryFrom<U>,
|
||||
Uri: TryFrom<U>,
|
||||
<Uri as TryFrom<U>>::Error: Into<HttpError>,
|
||||
{
|
||||
self.request(Method::OPTIONS, url)
|
||||
}
|
||||
@ -186,7 +196,8 @@ impl Client {
|
||||
/// Construct WebSockets request.
|
||||
pub fn ws<U>(&self, url: U) -> ws::WebsocketsRequest
|
||||
where
|
||||
Uri: HttpTryFrom<U>,
|
||||
Uri: TryFrom<U>,
|
||||
<Uri as TryFrom<U>>::Error: Into<HttpError>,
|
||||
{
|
||||
let mut req = ws::WebsocketsRequest::new(url, self.0.clone());
|
||||
for (key, value) in self.0.headers.iter() {
|
||||
|
@ -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<U>(method: Method, uri: U, config: Rc<ClientConfig>) -> Self
|
||||
where
|
||||
Uri: HttpTryFrom<U>,
|
||||
Uri: TryFrom<U>,
|
||||
<Uri as TryFrom<U>>::Error: Into<HttpError>,
|
||||
{
|
||||
ClientRequest {
|
||||
config,
|
||||
@ -86,7 +87,8 @@ impl ClientRequest {
|
||||
#[inline]
|
||||
pub fn uri<U>(mut self, uri: U) -> Self
|
||||
where
|
||||
Uri: HttpTryFrom<U>,
|
||||
Uri: TryFrom<U>,
|
||||
<Uri as TryFrom<U>>::Error: Into<HttpError>,
|
||||
{
|
||||
match Uri::try_from(uri) {
|
||||
Ok(uri) => self.head.uri = uri,
|
||||
@ -196,7 +198,8 @@ impl ClientRequest {
|
||||
/// ```
|
||||
pub fn header<K, V>(mut self, key: K, value: V) -> Self
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
{
|
||||
match HeaderName::try_from(key) {
|
||||
@ -212,7 +215,8 @@ impl ClientRequest {
|
||||
/// Insert a header, replaces existing header.
|
||||
pub fn set_header<K, V>(mut self, key: K, value: V) -> Self
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
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<K, V>(mut self, key: K, value: V) -> Self
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
{
|
||||
match HeaderName::try_from(key) {
|
||||
@ -264,7 +269,8 @@ impl ClientRequest {
|
||||
#[inline]
|
||||
pub fn content_type<V>(mut self, value: V) -> Self
|
||||
where
|
||||
HeaderValue: HttpTryFrom<V>,
|
||||
HeaderValue: TryFrom<V>,
|
||||
<HeaderValue as TryFrom<V>>::Error: Into<HttpError>,
|
||||
{
|
||||
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);
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
@ -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<K, V>(key: K, value: V) -> Self
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
{
|
||||
Self::default().header(key, value)
|
||||
@ -55,7 +57,8 @@ impl TestResponse {
|
||||
/// Append a header
|
||||
pub fn header<K, V>(mut self, key: K, value: V) -> Self
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
{
|
||||
if let Ok(key) = HeaderName::try_from(key) {
|
||||
|
@ -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<U>(uri: U, config: Rc<ClientConfig>) -> Self
|
||||
where
|
||||
Uri: HttpTryFrom<U>,
|
||||
Uri: TryFrom<U>,
|
||||
<Uri as TryFrom<U>>::Error: Into<HttpError>,
|
||||
{
|
||||
let mut err = None;
|
||||
let mut head = RequestHead::default();
|
||||
@ -102,9 +104,10 @@ impl WebsocketsRequest {
|
||||
}
|
||||
|
||||
/// Set request Origin
|
||||
pub fn origin<V>(mut self, origin: V) -> Self
|
||||
pub fn origin<V, E>(mut self, origin: V) -> Self
|
||||
where
|
||||
HeaderValue: HttpTryFrom<V>,
|
||||
HeaderValue: TryFrom<V, Error = E>,
|
||||
HttpError: From<E>,
|
||||
{
|
||||
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<K, V>(mut self, key: K, value: V) -> Self
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
{
|
||||
match HeaderName::try_from(key) {
|
||||
@ -151,7 +155,8 @@ impl WebsocketsRequest {
|
||||
/// Insert a header, replaces existing header.
|
||||
pub fn set_header<K, V>(mut self, key: K, value: V) -> Self
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
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<K, V>(mut self, key: K, value: V) -> Self
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
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)?
|
||||
|
@ -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<T: AsyncRead + AsyncWrite>() -> Result<OpensslAcceptor<T, ()>> {
|
||||
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<T: AsyncRead + AsyncWrite>() -> Result<OpensslAcceptor<T, ()>> {
|
||||
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(|_| ()),
|
||||
)
|
||||
});
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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<K, V>(mut self, key: K, value: V) -> Self
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderValue: HttpTryFrom<V>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
HeaderValue: TryFrom<V>,
|
||||
<HeaderValue as TryFrom<V>>::Error: Into<HttpError>,
|
||||
{
|
||||
#[allow(clippy::match_wild_err_arm)]
|
||||
match HeaderName::try_from(key) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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<K, V>(self, key: K, value: V) -> CustomResponder<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
{
|
||||
CustomResponder::new(self).with_header(key, value)
|
||||
@ -267,7 +268,8 @@ impl<T: Responder> CustomResponder<T> {
|
||||
/// ```
|
||||
pub fn with_header<K, V>(mut self, key: K, value: V) -> Self
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
{
|
||||
if self.headers.is_none() {
|
||||
|
@ -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<Self> {
|
||||
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 {
|
||||
|
@ -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<K, V>(key: K, value: V) -> TestRequest
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
{
|
||||
TestRequest::default().header(key, value)
|
||||
@ -377,7 +379,8 @@ impl TestRequest {
|
||||
/// Set a header
|
||||
pub fn header<K, V>(mut self, key: K, value: V) -> Self
|
||||
where
|
||||
HeaderName: HttpTryFrom<K>,
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
{
|
||||
self.req.header(key, value);
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "actix-http-test"
|
||||
version = "0.3.0-alpha.2"
|
||||
version = "0.3.0-alpha.3"
|
||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||
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"
|
||||
|
Loading…
Reference in New Issue
Block a user