mirror of
https://github.com/actix/actix-web.git
synced 2024-11-25 19:11:10 +00:00
add ws and http2 feature flags (#2618)
This commit is contained in:
parent
3200de3f34
commit
cd511affd5
18 changed files with 148 additions and 57 deletions
|
@ -80,7 +80,7 @@ actix-service = "2.0.0"
|
||||||
actix-utils = "3.0.0"
|
actix-utils = "3.0.0"
|
||||||
actix-tls = { version = "3.0.0", default-features = false, optional = true }
|
actix-tls = { version = "3.0.0", default-features = false, optional = true }
|
||||||
|
|
||||||
actix-http = "3.0.0-beta.19"
|
actix-http = { version = "3.0.0-beta.19", features = ["http2", "ws"] }
|
||||||
actix-router = "0.5.0-rc.2"
|
actix-router = "0.5.0-rc.2"
|
||||||
actix-web-codegen = "0.5.0-rc.1"
|
actix-web-codegen = "0.5.0-rc.1"
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
- Implement `From<Duration>` for `KeepAlive`. [#2611]
|
- Implement `From<Duration>` for `KeepAlive`. [#2611]
|
||||||
- Implement `From<Option<Duration>>` for `KeepAlive`. [#2611]
|
- Implement `From<Option<Duration>>` for `KeepAlive`. [#2611]
|
||||||
- Implement `Default` for `HttpServiceBuilder`. [#2611]
|
- Implement `Default` for `HttpServiceBuilder`. [#2611]
|
||||||
|
- Crate `ws` feature flag, disabled by default. [#2618]
|
||||||
|
- Crate `http2` feature flag, disabled by default. [#2618]
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Rename `ServiceConfig::{client_timer_expire => client_request_deadline}`. [#2611]
|
- Rename `ServiceConfig::{client_timer_expire => client_request_deadline}`. [#2611]
|
||||||
|
@ -27,6 +29,7 @@
|
||||||
- `HttpServiceBuilder::new`; use `default` instead. [#2611]
|
- `HttpServiceBuilder::new`; use `default` instead. [#2611]
|
||||||
|
|
||||||
[#2611]: https://github.com/actix/actix-web/pull/2611
|
[#2611]: https://github.com/actix/actix-web/pull/2611
|
||||||
|
[#2618]: https://github.com/actix/actix-web/pull/2618
|
||||||
|
|
||||||
|
|
||||||
## 3.0.0-beta.19 - 2022-01-21
|
## 3.0.0-beta.19 - 2022-01-21
|
||||||
|
|
|
@ -29,54 +29,69 @@ path = "src/lib.rs"
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
|
||||||
# openssl
|
# HTTP/2 protocol support
|
||||||
|
http2 = ["h2"]
|
||||||
|
|
||||||
|
# WebSocket protocol implementation
|
||||||
|
ws = [
|
||||||
|
"local-channel",
|
||||||
|
"base64",
|
||||||
|
"rand",
|
||||||
|
"sha-1",
|
||||||
|
]
|
||||||
|
|
||||||
|
# TLS via OpenSSL
|
||||||
openssl = ["actix-tls/accept", "actix-tls/openssl"]
|
openssl = ["actix-tls/accept", "actix-tls/openssl"]
|
||||||
|
|
||||||
# rustls support
|
# TLS via Rustls
|
||||||
rustls = ["actix-tls/accept", "actix-tls/rustls"]
|
rustls = ["actix-tls/accept", "actix-tls/rustls"]
|
||||||
|
|
||||||
# enable compression support
|
# Compression codecs
|
||||||
compress-brotli = ["brotli", "__compress"]
|
compress-brotli = ["__compress", "brotli"]
|
||||||
compress-gzip = ["flate2", "__compress"]
|
compress-gzip = ["__compress", "flate2"]
|
||||||
compress-zstd = ["zstd", "__compress"]
|
compress-zstd = ["__compress", "zstd"]
|
||||||
|
|
||||||
# Internal (PRIVATE!) features used to aid testing and cheking feature status.
|
# Internal (PRIVATE!) features used to aid testing and cheking feature status.
|
||||||
# Don't rely on these whatsoever. They may disappear at anytime.
|
# Don't rely on these whatsoever. They are semver-exempt and may disappear at anytime.
|
||||||
__compress = []
|
__compress = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-service = "2.0.0"
|
actix-service = "2"
|
||||||
actix-codec = "0.4.1"
|
actix-codec = "0.4.1"
|
||||||
actix-utils = "3.0.0"
|
actix-utils = "3"
|
||||||
actix-rt = { version = "2.2", default-features = false }
|
actix-rt = { version = "2.2", default-features = false }
|
||||||
|
|
||||||
ahash = "0.7"
|
ahash = "0.7"
|
||||||
base64 = "0.13"
|
|
||||||
bitflags = "1.2"
|
bitflags = "1.2"
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
bytestring = "1"
|
bytestring = "1"
|
||||||
derive_more = "0.99.5"
|
derive_more = "0.99.5"
|
||||||
encoding_rs = "0.8"
|
encoding_rs = "0.8"
|
||||||
futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] }
|
futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] }
|
||||||
h2 = "0.3.9"
|
|
||||||
http = "0.2.5"
|
http = "0.2.5"
|
||||||
httparse = "1.5.1"
|
httparse = "1.5.1"
|
||||||
httpdate = "1.0.1"
|
httpdate = "1.0.1"
|
||||||
itoa = "1"
|
itoa = "1"
|
||||||
language-tags = "0.3"
|
language-tags = "0.3"
|
||||||
local-channel = "0.1"
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
mime = "0.3"
|
mime = "0.3"
|
||||||
percent-encoding = "2.1"
|
percent-encoding = "2.1"
|
||||||
pin-project-lite = "0.2"
|
pin-project-lite = "0.2"
|
||||||
rand = "0.8"
|
|
||||||
sha-1 = "0.10"
|
|
||||||
smallvec = "1.6.1"
|
smallvec = "1.6.1"
|
||||||
|
|
||||||
# tls
|
# http2
|
||||||
|
h2 = { version = "0.3.9", optional = true }
|
||||||
|
|
||||||
|
# websockets
|
||||||
|
local-channel = { version = "0.1", optional = true }
|
||||||
|
base64 = { version = "0.13", optional = true }
|
||||||
|
rand = { version = "0.8", optional = true }
|
||||||
|
sha-1 = { version = "0.10", optional = true }
|
||||||
|
|
||||||
|
# openssl/rustls
|
||||||
actix-tls = { version = "3.0.0", default-features = false, optional = true }
|
actix-tls = { version = "3.0.0", default-features = false, optional = true }
|
||||||
|
|
||||||
# compression
|
# compress-*
|
||||||
brotli = { version = "3.3.3", optional = true }
|
brotli = { version = "3.3.3", optional = true }
|
||||||
flate2 = { version = "1.0.13", optional = true }
|
flate2 = { version = "1.0.13", optional = true }
|
||||||
zstd = { version = "0.9", optional = true }
|
zstd = { version = "0.9", optional = true }
|
||||||
|
|
|
@ -6,7 +6,6 @@ use actix_service::{IntoServiceFactory, Service, ServiceFactory};
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{BoxBody, MessageBody},
|
body::{BoxBody, MessageBody},
|
||||||
h1::{self, ExpectHandler, H1Service, UpgradeHandler},
|
h1::{self, ExpectHandler, H1Service, UpgradeHandler},
|
||||||
h2::H2Service,
|
|
||||||
service::HttpService,
|
service::HttpService,
|
||||||
ConnectCallback, Extensions, KeepAlive, Request, Response, ServiceConfig,
|
ConnectCallback, Extensions, KeepAlive, Request, Response, ServiceConfig,
|
||||||
};
|
};
|
||||||
|
@ -211,7 +210,8 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finish service configuration and create a HTTP service for HTTP/2 protocol.
|
/// Finish service configuration and create a HTTP service for HTTP/2 protocol.
|
||||||
pub fn h2<F, B>(self, service: F) -> H2Service<T, S, B>
|
#[cfg(feature = "http2")]
|
||||||
|
pub fn h2<F, B>(self, service: F) -> crate::h2::H2Service<T, S, B>
|
||||||
where
|
where
|
||||||
F: IntoServiceFactory<S, Request>,
|
F: IntoServiceFactory<S, Request>,
|
||||||
S::Error: Into<Response<BoxBody>> + 'static,
|
S::Error: Into<Response<BoxBody>> + 'static,
|
||||||
|
@ -228,7 +228,8 @@ where
|
||||||
self.local_addr,
|
self.local_addr,
|
||||||
);
|
);
|
||||||
|
|
||||||
H2Service::with_config(cfg, service.into_factory()).on_connect_ext(self.on_connect_ext)
|
crate::h2::H2Service::with_config(cfg, service.into_factory())
|
||||||
|
.on_connect_ext(self.on_connect_ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finish service configuration and create `HttpService` instance.
|
/// Finish service configuration and create `HttpService` instance.
|
||||||
|
|
|
@ -117,6 +117,7 @@ impl ServiceConfig {
|
||||||
dst.extend_from_slice(&buf);
|
dst.extend_from_slice(&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)] // used with `http2` feature flag
|
||||||
pub(crate) fn write_date_header_value(&self, dst: &mut BytesMut) {
|
pub(crate) fn write_date_header_value(&self, dst: &mut BytesMut) {
|
||||||
self.0
|
self.0
|
||||||
.date_service
|
.date_service
|
||||||
|
|
|
@ -352,7 +352,7 @@ impl ContentEncoder {
|
||||||
ContentEncoder::Brotli(ref mut encoder) => match encoder.write_all(data) {
|
ContentEncoder::Brotli(ref mut encoder) => match encoder.write_all(data) {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
trace!("Error decoding br encoding: {}", err);
|
log::trace!("Error decoding br encoding: {}", err);
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -361,7 +361,7 @@ impl ContentEncoder {
|
||||||
ContentEncoder::Gzip(ref mut encoder) => match encoder.write_all(data) {
|
ContentEncoder::Gzip(ref mut encoder) => match encoder.write_all(data) {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
trace!("Error decoding gzip encoding: {}", err);
|
log::trace!("Error decoding gzip encoding: {}", err);
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -370,7 +370,7 @@ impl ContentEncoder {
|
||||||
ContentEncoder::Deflate(ref mut encoder) => match encoder.write_all(data) {
|
ContentEncoder::Deflate(ref mut encoder) => match encoder.write_all(data) {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
trace!("Error decoding deflate encoding: {}", err);
|
log::trace!("Error decoding deflate encoding: {}", err);
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -379,7 +379,7 @@ impl ContentEncoder {
|
||||||
ContentEncoder::Zstd(ref mut encoder) => match encoder.write_all(data) {
|
ContentEncoder::Zstd(ref mut encoder) => match encoder.write_all(data) {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
trace!("Error decoding ztsd encoding: {}", err);
|
log::trace!("Error decoding ztsd encoding: {}", err);
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::{error::Error as StdError, fmt, io, str::Utf8Error, string::FromUtf8Err
|
||||||
use derive_more::{Display, Error, From};
|
use derive_more::{Display, Error, From};
|
||||||
use http::{uri::InvalidUri, StatusCode};
|
use http::{uri::InvalidUri, StatusCode};
|
||||||
|
|
||||||
use crate::{body::BoxBody, ws, Response};
|
use crate::{body::BoxBody, Response};
|
||||||
|
|
||||||
pub use http::Error as HttpError;
|
pub use http::Error as HttpError;
|
||||||
|
|
||||||
|
@ -61,6 +61,7 @@ impl Error {
|
||||||
Self::new(Kind::Encoder)
|
Self::new(Kind::Encoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)] // used with `ws` feature flag
|
||||||
pub(crate) fn new_ws() -> Self {
|
pub(crate) fn new_ws() -> Self {
|
||||||
Self::new(Kind::Ws)
|
Self::new(Kind::Ws)
|
||||||
}
|
}
|
||||||
|
@ -139,14 +140,16 @@ impl From<HttpError> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ws::HandshakeError> for Error {
|
#[cfg(feature = "ws")]
|
||||||
fn from(err: ws::HandshakeError) -> Self {
|
impl From<crate::ws::HandshakeError> for Error {
|
||||||
|
fn from(err: crate::ws::HandshakeError) -> Self {
|
||||||
Self::new_ws().with_cause(err)
|
Self::new_ws().with_cause(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ws::ProtocolError> for Error {
|
#[cfg(feature = "ws")]
|
||||||
fn from(err: ws::ProtocolError) -> Self {
|
impl From<crate::ws::ProtocolError> for Error {
|
||||||
|
fn from(err: crate::ws::ProtocolError) -> Self {
|
||||||
Self::new_ws().with_cause(err)
|
Self::new_ws().with_cause(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -277,8 +280,9 @@ pub enum PayloadError {
|
||||||
UnknownLength,
|
UnknownLength,
|
||||||
|
|
||||||
/// HTTP/2 payload error.
|
/// HTTP/2 payload error.
|
||||||
|
#[cfg(feature = "http2")]
|
||||||
#[display(fmt = "{}", _0)]
|
#[display(fmt = "{}", _0)]
|
||||||
Http2Payload(h2::Error),
|
Http2Payload(::h2::Error),
|
||||||
|
|
||||||
/// Generic I/O error.
|
/// Generic I/O error.
|
||||||
#[display(fmt = "{}", _0)]
|
#[display(fmt = "{}", _0)]
|
||||||
|
@ -293,14 +297,16 @@ impl std::error::Error for PayloadError {
|
||||||
PayloadError::EncodingCorrupted => None,
|
PayloadError::EncodingCorrupted => None,
|
||||||
PayloadError::Overflow => None,
|
PayloadError::Overflow => None,
|
||||||
PayloadError::UnknownLength => None,
|
PayloadError::UnknownLength => None,
|
||||||
|
#[cfg(feature = "http2")]
|
||||||
PayloadError::Http2Payload(err) => Some(err as &dyn std::error::Error),
|
PayloadError::Http2Payload(err) => Some(err as &dyn std::error::Error),
|
||||||
PayloadError::Io(err) => Some(err as &dyn std::error::Error),
|
PayloadError::Io(err) => Some(err as &dyn std::error::Error),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<h2::Error> for PayloadError {
|
#[cfg(feature = "http2")]
|
||||||
fn from(err: h2::Error) -> Self {
|
impl From<::h2::Error> for PayloadError {
|
||||||
|
fn from(err: ::h2::Error) -> Self {
|
||||||
PayloadError::Http2Payload(err)
|
PayloadError::Http2Payload(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -356,6 +362,7 @@ pub enum DispatchError {
|
||||||
|
|
||||||
/// HTTP/2 error.
|
/// HTTP/2 error.
|
||||||
#[display(fmt = "{}", _0)]
|
#[display(fmt = "{}", _0)]
|
||||||
|
#[cfg(feature = "http2")]
|
||||||
H2(h2::Error),
|
H2(h2::Error),
|
||||||
|
|
||||||
/// The first request did not complete within the specified timeout.
|
/// The first request did not complete within the specified timeout.
|
||||||
|
@ -379,7 +386,10 @@ impl StdError for DispatchError {
|
||||||
DispatchError::Body(err) => Some(&**err),
|
DispatchError::Body(err) => Some(&**err),
|
||||||
DispatchError::Io(err) => Some(err),
|
DispatchError::Io(err) => Some(err),
|
||||||
DispatchError::Parse(err) => Some(err),
|
DispatchError::Parse(err) => Some(err),
|
||||||
|
|
||||||
|
#[cfg(feature = "http2")]
|
||||||
DispatchError::H2(err) => Some(err),
|
DispatchError::H2(err) => Some(err),
|
||||||
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,7 +141,7 @@ where
|
||||||
DispatchError::SendResponse(err) => {
|
DispatchError::SendResponse(err) => {
|
||||||
trace!("Error sending HTTP/2 response: {:?}", err)
|
trace!("Error sending HTTP/2 response: {:?}", err)
|
||||||
}
|
}
|
||||||
DispatchError::SendData(err) => warn!("{:?}", err),
|
DispatchError::SendData(err) => log::warn!("{:?}", err),
|
||||||
DispatchError::ResponseBody(err) => {
|
DispatchError::ResponseBody(err) => {
|
||||||
error!("Response payload stream error: {:?}", err)
|
error!("Response payload stream error: {:?}", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -355,7 +355,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
trace!("H2 handshake error: {}", err);
|
log::trace!("H2 handshake error: {}", err);
|
||||||
Poll::Ready(Err(err))
|
Poll::Ready(Err(err))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -55,7 +55,7 @@ pub trait HttpMessage: Sized {
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get content type encoding
|
/// Get content type encoding.
|
||||||
///
|
///
|
||||||
/// UTF-8 is used by default, If request charset is not set.
|
/// UTF-8 is used by default, If request charset is not set.
|
||||||
fn encoding(&self) -> Result<&'static Encoding, ContentTypeError> {
|
fn encoding(&self) -> Result<&'static Encoding, ContentTypeError> {
|
||||||
|
|
|
@ -24,6 +24,7 @@ impl KeepAlive {
|
||||||
!matches!(self, Self::Disabled)
|
!matches!(self, Self::Disabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)] // used with `http2` feature flag
|
||||||
pub(crate) fn duration(&self) -> Option<Duration> {
|
pub(crate) fn duration(&self) -> Option<Duration> {
|
||||||
match self {
|
match self {
|
||||||
KeepAlive::Timeout(dur) => Some(*dur),
|
KeepAlive::Timeout(dur) => Some(*dur),
|
||||||
|
|
|
@ -24,9 +24,6 @@
|
||||||
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
|
||||||
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate log;
|
|
||||||
|
|
||||||
pub use ::http::{uri, uri::Uri};
|
pub use ::http::{uri, uri::Uri};
|
||||||
pub use ::http::{Method, StatusCode, Version};
|
pub use ::http::{Method, StatusCode, Version};
|
||||||
|
|
||||||
|
@ -39,6 +36,7 @@ pub mod encoding;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
mod extensions;
|
mod extensions;
|
||||||
pub mod h1;
|
pub mod h1;
|
||||||
|
#[cfg(feature = "http2")]
|
||||||
pub mod h2;
|
pub mod h2;
|
||||||
pub mod header;
|
pub mod header;
|
||||||
mod helpers;
|
mod helpers;
|
||||||
|
@ -52,6 +50,7 @@ mod requests;
|
||||||
mod responses;
|
mod responses;
|
||||||
mod service;
|
mod service;
|
||||||
pub mod test;
|
pub mod test;
|
||||||
|
#[cfg(feature = "ws")]
|
||||||
pub mod ws;
|
pub mod ws;
|
||||||
|
|
||||||
pub use self::builder::HttpServiceBuilder;
|
pub use self::builder::HttpServiceBuilder;
|
||||||
|
|
|
@ -16,6 +16,18 @@ pub type BoxedPayloadStream = Pin<Box<dyn Stream<Item = Result<Bytes, PayloadErr
|
||||||
#[deprecated(since = "4.0.0", note = "Renamed to `BoxedPayloadStream`.")]
|
#[deprecated(since = "4.0.0", note = "Renamed to `BoxedPayloadStream`.")]
|
||||||
pub type PayloadStream = BoxedPayloadStream;
|
pub type PayloadStream = BoxedPayloadStream;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "http2"))]
|
||||||
|
pin_project! {
|
||||||
|
/// A streaming payload.
|
||||||
|
#[project = PayloadProj]
|
||||||
|
pub enum Payload<S = BoxedPayloadStream> {
|
||||||
|
None,
|
||||||
|
H1 { payload: crate::h1::Payload },
|
||||||
|
Stream { #[pin] payload: S },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "http2")]
|
||||||
pin_project! {
|
pin_project! {
|
||||||
/// A streaming payload.
|
/// A streaming payload.
|
||||||
#[project = PayloadProj]
|
#[project = PayloadProj]
|
||||||
|
@ -33,14 +45,16 @@ impl<S> From<crate::h1::Payload> for Payload<S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "http2")]
|
||||||
impl<S> From<crate::h2::Payload> for Payload<S> {
|
impl<S> From<crate::h2::Payload> for Payload<S> {
|
||||||
fn from(payload: crate::h2::Payload) -> Self {
|
fn from(payload: crate::h2::Payload) -> Self {
|
||||||
Payload::H2 { payload }
|
Payload::H2 { payload }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> From<h2::RecvStream> for Payload<S> {
|
#[cfg(feature = "http2")]
|
||||||
fn from(stream: h2::RecvStream) -> Self {
|
impl<S> From<::h2::RecvStream> for Payload<S> {
|
||||||
|
fn from(stream: ::h2::RecvStream) -> Self {
|
||||||
Payload::H2 {
|
Payload::H2 {
|
||||||
payload: crate::h2::Payload::new(stream),
|
payload: crate::h2::Payload::new(stream),
|
||||||
}
|
}
|
||||||
|
@ -71,7 +85,10 @@ where
|
||||||
match self.project() {
|
match self.project() {
|
||||||
PayloadProj::None => Poll::Ready(None),
|
PayloadProj::None => Poll::Ready(None),
|
||||||
PayloadProj::H1 { payload } => Pin::new(payload).poll_next(cx),
|
PayloadProj::H1 { payload } => Pin::new(payload).poll_next(cx),
|
||||||
|
|
||||||
|
#[cfg(feature = "http2")]
|
||||||
PayloadProj::H2 { payload } => Pin::new(payload).poll_next(cx),
|
PayloadProj::H2 { payload } => Pin::new(payload).poll_next(cx),
|
||||||
|
|
||||||
PayloadProj::Stream { payload } => payload.poll_next(cx),
|
PayloadProj::Stream { payload } => payload.poll_next(cx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ use crate::{
|
||||||
body::{BoxBody, MessageBody},
|
body::{BoxBody, MessageBody},
|
||||||
builder::HttpServiceBuilder,
|
builder::HttpServiceBuilder,
|
||||||
error::DispatchError,
|
error::DispatchError,
|
||||||
h1, h2, ConnectCallback, OnConnectData, Protocol, Request, Response, ServiceConfig,
|
h1, ConnectCallback, OnConnectData, Protocol, Request, Response, ServiceConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A `ServiceFactory` for HTTP/1.1 or HTTP/2 protocol.
|
/// A `ServiceFactory` for HTTP/1.1 or HTTP/2 protocol.
|
||||||
|
@ -502,10 +502,11 @@ where
|
||||||
let conn_data = OnConnectData::from_io(&io, self.on_connect_ext.as_deref());
|
let conn_data = OnConnectData::from_io(&io, self.on_connect_ext.as_deref());
|
||||||
|
|
||||||
match proto {
|
match proto {
|
||||||
|
#[cfg(feature = "http2")]
|
||||||
Protocol::Http2 => HttpServiceHandlerResponse {
|
Protocol::Http2 => HttpServiceHandlerResponse {
|
||||||
state: State::H2Handshake {
|
state: State::H2Handshake {
|
||||||
handshake: Some((
|
handshake: Some((
|
||||||
h2::handshake_with_timeout(io, &self.cfg),
|
crate::h2::handshake_with_timeout(io, &self.cfg),
|
||||||
self.cfg.clone(),
|
self.cfg.clone(),
|
||||||
self.flow.clone(),
|
self.flow.clone(),
|
||||||
conn_data,
|
conn_data,
|
||||||
|
@ -514,6 +515,11 @@ where
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
#[cfg(not(feature = "http2"))]
|
||||||
|
Protocol::Http2 => {
|
||||||
|
panic!("HTTP/2 support is disabled (enable with the `http2` feature flag)")
|
||||||
|
}
|
||||||
|
|
||||||
Protocol::Http1 => HttpServiceHandlerResponse {
|
Protocol::Http1 => HttpServiceHandlerResponse {
|
||||||
state: State::H1 {
|
state: State::H1 {
|
||||||
dispatcher: h1::Dispatcher::new(
|
dispatcher: h1::Dispatcher::new(
|
||||||
|
@ -531,6 +537,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "http2"))]
|
||||||
pin_project! {
|
pin_project! {
|
||||||
#[project = StateProj]
|
#[project = StateProj]
|
||||||
enum State<T, S, B, X, U>
|
enum State<T, S, B, X, U>
|
||||||
|
@ -552,10 +559,37 @@ pin_project! {
|
||||||
U::Error: fmt::Display,
|
U::Error: fmt::Display,
|
||||||
{
|
{
|
||||||
H1 { #[pin] dispatcher: h1::Dispatcher<T, S, B, X, U> },
|
H1 { #[pin] dispatcher: h1::Dispatcher<T, S, B, X, U> },
|
||||||
H2 { #[pin] dispatcher: h2::Dispatcher<T, S, B, X, U> },
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "http2")]
|
||||||
|
pin_project! {
|
||||||
|
#[project = StateProj]
|
||||||
|
enum State<T, S, B, X, U>
|
||||||
|
where
|
||||||
|
T: AsyncRead,
|
||||||
|
T: AsyncWrite,
|
||||||
|
T: Unpin,
|
||||||
|
|
||||||
|
S: Service<Request>,
|
||||||
|
S::Future: 'static,
|
||||||
|
S::Error: Into<Response<BoxBody>>,
|
||||||
|
|
||||||
|
B: MessageBody,
|
||||||
|
|
||||||
|
X: Service<Request, Response = Request>,
|
||||||
|
X::Error: Into<Response<BoxBody>>,
|
||||||
|
|
||||||
|
U: Service<(Request, Framed<T, h1::Codec>), Response = ()>,
|
||||||
|
U::Error: fmt::Display,
|
||||||
|
{
|
||||||
|
H1 { #[pin] dispatcher: h1::Dispatcher<T, S, B, X, U> },
|
||||||
|
|
||||||
|
H2 { #[pin] dispatcher: crate::h2::Dispatcher<T, S, B, X, U> },
|
||||||
|
|
||||||
H2Handshake {
|
H2Handshake {
|
||||||
handshake: Option<(
|
handshake: Option<(
|
||||||
h2::HandshakeWithTimeout<T>,
|
crate::h2::HandshakeWithTimeout<T>,
|
||||||
ServiceConfig,
|
ServiceConfig,
|
||||||
Rc<HttpFlow<S, X, U>>,
|
Rc<HttpFlow<S, X, U>>,
|
||||||
OnConnectData,
|
OnConnectData,
|
||||||
|
@ -614,21 +648,25 @@ where
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
match self.as_mut().project().state.project() {
|
match self.as_mut().project().state.project() {
|
||||||
StateProj::H1 { dispatcher } => dispatcher.poll(cx),
|
StateProj::H1 { dispatcher } => dispatcher.poll(cx),
|
||||||
|
|
||||||
|
#[cfg(feature = "http2")]
|
||||||
StateProj::H2 { dispatcher } => dispatcher.poll(cx),
|
StateProj::H2 { dispatcher } => dispatcher.poll(cx),
|
||||||
|
|
||||||
|
#[cfg(feature = "http2")]
|
||||||
StateProj::H2Handshake { handshake: data } => {
|
StateProj::H2Handshake { handshake: data } => {
|
||||||
match ready!(Pin::new(&mut data.as_mut().unwrap().0).poll(cx)) {
|
match ready!(Pin::new(&mut data.as_mut().unwrap().0).poll(cx)) {
|
||||||
Ok((conn, timer)) => {
|
Ok((conn, timer)) => {
|
||||||
let (_, config, flow, conn_data, peer_addr) = data.take().unwrap();
|
let (_, config, flow, conn_data, peer_addr) = data.take().unwrap();
|
||||||
|
|
||||||
self.as_mut().project().state.set(State::H2 {
|
self.as_mut().project().state.set(State::H2 {
|
||||||
dispatcher: h2::Dispatcher::new(
|
dispatcher: crate::h2::Dispatcher::new(
|
||||||
conn, flow, config, peer_addr, conn_data, timer,
|
conn, flow, config, peer_addr, conn_data, timer,
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
self.poll(cx)
|
self.poll(cx)
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
trace!("H2 handshake error: {}", err);
|
log::trace!("H2 handshake error: {}", err);
|
||||||
Poll::Ready(Err(err))
|
Poll::Ready(Err(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,11 @@ use bitflags::bitflags;
|
||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
use bytestring::ByteString;
|
use bytestring::ByteString;
|
||||||
|
|
||||||
use super::frame::Parser;
|
use super::{
|
||||||
use super::proto::{CloseReason, OpCode};
|
frame::Parser,
|
||||||
use super::ProtocolError;
|
proto::{CloseReason, OpCode},
|
||||||
|
ProtocolError,
|
||||||
|
};
|
||||||
|
|
||||||
/// A WebSocket message.
|
/// A WebSocket message.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
|
@ -251,7 +253,7 @@ impl Decoder for Codec {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
error!("Unfinished fragment {:?}", opcode);
|
log::error!("Unfinished fragment {:?}", opcode);
|
||||||
Err(ProtocolError::ContinuationFragment(opcode))
|
Err(ProtocolError::ContinuationFragment(opcode))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use std::future::Future;
|
use std::{
|
||||||
use std::pin::Pin;
|
future::Future,
|
||||||
use std::task::{Context, Poll};
|
pin::Pin,
|
||||||
|
task::{Context, Poll},
|
||||||
|
};
|
||||||
|
|
||||||
use actix_codec::{AsyncRead, AsyncWrite, Framed};
|
use actix_codec::{AsyncRead, AsyncWrite, Framed};
|
||||||
use actix_service::{IntoService, Service};
|
use actix_service::{IntoService, Service};
|
||||||
|
|
|
@ -3,9 +3,11 @@ use std::convert::TryFrom;
|
||||||
use bytes::{Buf, BufMut, BytesMut};
|
use bytes::{Buf, BufMut, BytesMut};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
use crate::ws::mask::apply_mask;
|
use super::{
|
||||||
use crate::ws::proto::{CloseCode, CloseReason, OpCode};
|
mask::apply_mask,
|
||||||
use crate::ws::ProtocolError;
|
proto::{CloseCode, CloseReason, OpCode},
|
||||||
|
ProtocolError,
|
||||||
|
};
|
||||||
|
|
||||||
/// A struct representing a WebSocket frame.
|
/// A struct representing a WebSocket frame.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -60,7 +60,7 @@ dangerous-h2c = []
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-codec = "0.4.1"
|
actix-codec = "0.4.1"
|
||||||
actix-service = "2.0.0"
|
actix-service = "2.0.0"
|
||||||
actix-http = "3.0.0-beta.19"
|
actix-http = { version = "3.0.0-beta.19", features = ["http2", "ws"] }
|
||||||
actix-rt = { version = "2.1", default-features = false }
|
actix-rt = { version = "2.1", default-features = false }
|
||||||
actix-tls = { version = "3.0.0", features = ["connect", "uri"] }
|
actix-tls = { version = "3.0.0", features = ["connect", "uri"] }
|
||||||
actix-utils = "3.0.0"
|
actix-utils = "3.0.0"
|
||||||
|
|
Loading…
Reference in a new issue