mirror of https://github.com/fafhrd91/actix-web
add http2 feature flag
This commit is contained in:
parent
97cd9f6103
commit
d71b800792
|
@ -29,6 +29,9 @@ path = "src/lib.rs"
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
|
||||||
|
http2 = [
|
||||||
|
"h2",
|
||||||
|
]
|
||||||
|
|
||||||
ws = [
|
ws = [
|
||||||
"local-channel",
|
"local-channel",
|
||||||
|
@ -65,7 +68,6 @@ 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"
|
||||||
|
@ -77,6 +79,9 @@ percent-encoding = "2.1"
|
||||||
pin-project-lite = "0.2"
|
pin-project-lite = "0.2"
|
||||||
smallvec = "1.6.1"
|
smallvec = "1.6.1"
|
||||||
|
|
||||||
|
# http2
|
||||||
|
h2 = { version = "0.3.9", optional = true }
|
||||||
|
|
||||||
# websockets
|
# websockets
|
||||||
local-channel = { version = "0.1", optional = true }
|
local-channel = { version = "0.1", optional = true }
|
||||||
base64 = { version = "0.13", optional = true }
|
base64 = { version = "0.13", 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
|
||||||
|
|
|
@ -280,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)]
|
||||||
|
@ -296,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -359,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.
|
||||||
|
@ -382,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;
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue