feat(server): Make the server code an optional feature (#2334)

cc #2223 

BREAKING CHANGE: The HTTP server code is now an optional feature. To
  enable the server, add `features = ["server"]` to the dependency in
  your `Cargo.toml`.
This commit is contained in:
Sean McArthur
2020-11-18 11:02:20 -08:00
committed by GitHub
parent 4e55583d30
commit bdb5e5d694
18 changed files with 185 additions and 102 deletions

View File

@@ -75,6 +75,7 @@ default = [
"runtime", "runtime",
"stream", "stream",
"client", "client",
"server",
"http1", "http1",
"http2", "http2",
] ]
@@ -82,6 +83,7 @@ full = [
"client", "client",
"http1", "http1",
"http2", "http2",
"server",
"stream", "stream",
"runtime", "runtime",
] ]
@@ -100,7 +102,9 @@ tcp = [
http1 = [] http1 = []
http2 = ["h2"] http2 = ["h2"]
# Client/Server
client = [] client = []
server = []
# `impl Stream` for things # `impl Stream` for things
stream = [] stream = []

View File

@@ -21,7 +21,7 @@ use crate::common::{task, watch, Pin, Poll};
#[cfg(any(feature = "http1", feature = "http2"))] #[cfg(any(feature = "http1", feature = "http2"))]
#[cfg(feature = "client")] #[cfg(feature = "client")]
use crate::common::{Future, Never}; use crate::common::{Future, Never};
#[cfg(feature = "http2")] #[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
use crate::proto::h2::ping; use crate::proto::h2::ping;
use crate::upgrade::OnUpgrade; use crate::upgrade::OnUpgrade;
@@ -46,7 +46,7 @@ enum Kind {
want_tx: watch::Sender, want_tx: watch::Sender,
rx: mpsc::Receiver<Result<Bytes, crate::Error>>, rx: mpsc::Receiver<Result<Bytes, crate::Error>>,
}, },
#[cfg(feature = "http2")] #[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
H2 { H2 {
ping: ping::Recorder, ping: ping::Recorder,
content_length: DecodedLength, content_length: DecodedLength,
@@ -200,7 +200,7 @@ impl Body {
Body { kind, extra: None } Body { kind, extra: None }
} }
#[cfg(feature = "http2")] #[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
pub(crate) fn h2( pub(crate) fn h2(
recv: h2::RecvStream, recv: h2::RecvStream,
content_length: DecodedLength, content_length: DecodedLength,
@@ -301,7 +301,7 @@ impl Body {
None => Poll::Ready(None), None => Poll::Ready(None),
} }
} }
#[cfg(feature = "http2")] #[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
Kind::H2 { Kind::H2 {
ref ping, ref ping,
recv: ref mut h2, recv: ref mut h2,
@@ -359,7 +359,7 @@ impl HttpBody for Body {
#[cfg_attr(not(feature = "http2"), allow(unused))] cx: &mut task::Context<'_>, #[cfg_attr(not(feature = "http2"), allow(unused))] cx: &mut task::Context<'_>,
) -> Poll<Result<Option<HeaderMap>, Self::Error>> { ) -> Poll<Result<Option<HeaderMap>, Self::Error>> {
match self.kind { match self.kind {
#[cfg(feature = "http2")] #[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
Kind::H2 { Kind::H2 {
recv: ref mut h2, recv: ref mut h2,
ref ping, ref ping,
@@ -379,7 +379,7 @@ impl HttpBody for Body {
match self.kind { match self.kind {
Kind::Once(ref val) => val.is_none(), Kind::Once(ref val) => val.is_none(),
Kind::Chan { content_length, .. } => content_length == DecodedLength::ZERO, Kind::Chan { content_length, .. } => content_length == DecodedLength::ZERO,
#[cfg(feature = "http2")] #[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
Kind::H2 { recv: ref h2, .. } => h2.is_end_stream(), Kind::H2 { recv: ref h2, .. } => h2.is_end_stream(),
#[cfg(feature = "stream")] #[cfg(feature = "stream")]
Kind::Wrapped(..) => false, Kind::Wrapped(..) => false,
@@ -405,7 +405,7 @@ impl HttpBody for Body {
#[cfg(feature = "stream")] #[cfg(feature = "stream")]
Kind::Wrapped(..) => SizeHint::default(), Kind::Wrapped(..) => SizeHint::default(),
Kind::Chan { content_length, .. } => opt_len!(content_length), Kind::Chan { content_length, .. } => opt_len!(content_length),
#[cfg(feature = "http2")] #[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
Kind::H2 { content_length, .. } => opt_len!(content_length), Kind::H2 { content_length, .. } => opt_len!(content_length),
} }
} }

View File

@@ -11,16 +11,19 @@ macro_rules! cfg_feature {
} }
} }
macro_rules! cfg_any_http { macro_rules! cfg_proto {
($($item:item)*) => { ($($item:item)*) => {
cfg_feature! { cfg_feature! {
#![any(feature = "http1", feature = "http2")] #![all(
any(feature = "http1", feature = "http2"),
any(feature = "client", feature = "server"),
)]
$($item)* $($item)*
} }
} }
} }
cfg_any_http! { cfg_proto! {
macro_rules! cfg_http1 { macro_rules! cfg_http1 {
($($item:item)*) => { ($($item:item)*) => {
cfg_feature! { cfg_feature! {
@@ -47,4 +50,13 @@ cfg_any_http! {
} }
} }
} }
macro_rules! cfg_server {
($($item:item)*) => {
cfg_feature! {
#![feature = "server"]
$($item)*
}
}
}
} }

View File

@@ -3,17 +3,23 @@ use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use std::sync::Arc; use std::sync::Arc;
#[cfg(feature = "server")]
use crate::body::{Body, HttpBody}; use crate::body::{Body, HttpBody};
#[cfg(feature = "http2")] #[cfg(feature = "http2")]
#[cfg(feature = "server")]
use crate::proto::h2::server::H2Stream; use crate::proto::h2::server::H2Stream;
use crate::rt::Executor; use crate::rt::Executor;
#[cfg(feature = "server")]
use crate::server::conn::spawn_all::{NewSvcTask, Watcher}; use crate::server::conn::spawn_all::{NewSvcTask, Watcher};
#[cfg(feature = "server")]
use crate::service::HttpService; use crate::service::HttpService;
#[cfg(feature = "server")]
pub trait ConnStreamExec<F, B: HttpBody>: Clone { pub trait ConnStreamExec<F, B: HttpBody>: Clone {
fn execute_h2stream(&mut self, fut: H2Stream<F, B>); fn execute_h2stream(&mut self, fut: H2Stream<F, B>);
} }
#[cfg(feature = "server")]
pub trait NewSvcExec<I, N, S: HttpService<Body>, E, W: Watcher<I, S, E>>: Clone { pub trait NewSvcExec<I, N, S: HttpService<Body>, E, W: Watcher<I, S, E>>: Clone {
fn execute_new_svc(&mut self, fut: NewSvcTask<I, N, S, E, W>); fn execute_new_svc(&mut self, fut: NewSvcTask<I, N, S, E, W>);
} }
@@ -60,6 +66,7 @@ impl fmt::Debug for Exec {
} }
} }
#[cfg(feature = "server")]
impl<F, B> ConnStreamExec<F, B> for Exec impl<F, B> ConnStreamExec<F, B> for Exec
where where
H2Stream<F, B>: Future<Output = ()> + Send + 'static, H2Stream<F, B>: Future<Output = ()> + Send + 'static,
@@ -70,6 +77,7 @@ where
} }
} }
#[cfg(feature = "server")]
impl<I, N, S, E, W> NewSvcExec<I, N, S, E, W> for Exec impl<I, N, S, E, W> NewSvcExec<I, N, S, E, W> for Exec
where where
NewSvcTask<I, N, S, E, W>: Future<Output = ()> + Send + 'static, NewSvcTask<I, N, S, E, W>: Future<Output = ()> + Send + 'static,
@@ -83,6 +91,7 @@ where
// ==== impl Executor ===== // ==== impl Executor =====
#[cfg(feature = "server")]
impl<E, F, B> ConnStreamExec<F, B> for E impl<E, F, B> ConnStreamExec<F, B> for E
where where
E: Executor<H2Stream<F, B>> + Clone, E: Executor<H2Stream<F, B>> + Clone,
@@ -94,6 +103,7 @@ where
} }
} }
#[cfg(feature = "server")]
impl<I, N, S, E, W> NewSvcExec<I, N, S, E, W> for E impl<I, N, S, E, W> NewSvcExec<I, N, S, E, W> for E
where where
E: Executor<NewSvcTask<I, N, S, E, W>> + Clone, E: Executor<NewSvcTask<I, N, S, E, W>> + Clone,
@@ -119,7 +129,7 @@ pub struct H2Stream<F, B>(std::marker::PhantomData<(F, B)>);
impl<F, B, E> Future for H2Stream<F, B> impl<F, B, E> Future for H2Stream<F, B>
where where
F: Future<Output = Result<http::Response<B>, E>>, F: Future<Output = Result<http::Response<B>, E>>,
B: HttpBody, B: crate::body::HttpBody,
B::Error: Into<Box<dyn std::error::Error + Send + Sync>>, B::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
E: Into<Box<dyn std::error::Error + Send + Sync>>, E: Into<Box<dyn std::error::Error + Send + Sync>>,
{ {

View File

@@ -15,6 +15,7 @@ pub(crate) struct Rewind<T> {
impl<T> Rewind<T> { impl<T> Rewind<T> {
#[cfg(any(feature = "http2", test))] #[cfg(any(feature = "http2", test))]
#[cfg(feature = "server")]
pub(crate) fn new(io: T) -> Self { pub(crate) fn new(io: T) -> Self {
Rewind { Rewind {
pre: None, pre: None,
@@ -29,7 +30,7 @@ impl<T> Rewind<T> {
} }
} }
#[cfg(any(all(feature = "http1", feature = "http2"), test))] #[cfg(any(all(feature = "http1", feature = "http2", feature = "server"), test))]
pub(crate) fn rewind(&mut self, bs: Bytes) { pub(crate) fn rewind(&mut self, bs: Bytes) {
debug_assert!(self.pre.is_none()); debug_assert!(self.pre.is_none());
self.pre = Some(bs); self.pre = Some(bs);

View File

@@ -9,8 +9,10 @@ macro_rules! ready {
pub(crate) mod buf; pub(crate) mod buf;
#[cfg(any(feature = "http1", feature = "http2"))] #[cfg(any(feature = "http1", feature = "http2"))]
#[cfg(feature = "server")]
pub(crate) mod date; pub(crate) mod date;
#[cfg(any(feature = "http1", feature = "http2"))] #[cfg(any(feature = "http1", feature = "http2"))]
#[cfg(feature = "server")]
pub(crate) mod drain; pub(crate) mod drain;
#[cfg(any(feature = "http1", feature = "http2"))] #[cfg(any(feature = "http1", feature = "http2"))]
pub(crate) mod exec; pub(crate) mod exec;
@@ -24,8 +26,6 @@ pub(crate) mod sync_wrapper;
pub(crate) mod task; pub(crate) mod task;
pub(crate) mod watch; pub(crate) mod watch;
//#[cfg(any(feature = "http1", feature = "http2"))]
//pub(crate) use self::exec::{BoxSendFuture, Exec};
#[cfg(any(feature = "http1", feature = "http2"))] #[cfg(any(feature = "http1", feature = "http2"))]
#[cfg(feature = "client")] #[cfg(feature = "client")]
pub(crate) use self::lazy::{lazy, Started as Lazy}; pub(crate) use self::lazy::{lazy, Started as Lazy};
@@ -33,6 +33,7 @@ pub use self::never::Never;
pub(crate) use self::task::Poll; pub(crate) use self::task::Poll;
// group up types normally needed for `Future` // group up types normally needed for `Future`
#[cfg(any(feature = "http1", feature = "http2"))] cfg_proto! {
pub(crate) use std::marker::Unpin; pub(crate) use std::marker::Unpin;
}
pub(crate) use std::{future::Future, pin::Pin}; pub(crate) use std::{future::Future, pin::Pin};

View File

@@ -36,10 +36,15 @@ pub(crate) enum Kind {
/// Error occurred while connecting. /// Error occurred while connecting.
Connect, Connect,
/// Error creating a TcpListener. /// Error creating a TcpListener.
#[cfg(all(any(feature = "http1", feature = "http2"), feature = "tcp"))] #[cfg(all(
any(feature = "http1", feature = "http2"),
feature = "tcp",
feature = "server"
))]
Listen, Listen,
/// Error accepting on an Incoming stream. /// Error accepting on an Incoming stream.
#[cfg(any(feature = "http1", feature = "http2"))] #[cfg(any(feature = "http1", feature = "http2"))]
#[cfg(feature = "server")]
Accept, Accept,
/// Error while reading a body from connection. /// Error while reading a body from connection.
#[cfg(any(feature = "http1", feature = "http2", feature = "stream"))] #[cfg(any(feature = "http1", feature = "http2", feature = "stream"))]
@@ -77,6 +82,7 @@ pub(crate) enum User {
Body, Body,
/// Error calling user's MakeService. /// Error calling user's MakeService.
#[cfg(any(feature = "http1", feature = "http2"))] #[cfg(any(feature = "http1", feature = "http2"))]
#[cfg(feature = "server")]
MakeService, MakeService,
/// Error from future of user's Service. /// Error from future of user's Service.
#[cfg(any(feature = "http1", feature = "http2"))] #[cfg(any(feature = "http1", feature = "http2"))]
@@ -85,6 +91,7 @@ pub(crate) enum User {
/// ///
/// For example, sending both `content-length` and `transfer-encoding`. /// For example, sending both `content-length` and `transfer-encoding`.
#[cfg(feature = "http1")] #[cfg(feature = "http1")]
#[cfg(feature = "server")]
UnexpectedHeader, UnexpectedHeader,
/// User tried to create a Request with bad version. /// User tried to create a Request with bad version.
#[cfg(any(feature = "http1", feature = "http2"))] #[cfg(any(feature = "http1", feature = "http2"))]
@@ -96,6 +103,7 @@ pub(crate) enum User {
UnsupportedRequestMethod, UnsupportedRequestMethod,
/// User tried to respond with a 1xx (not 101) response code. /// User tried to respond with a 1xx (not 101) response code.
#[cfg(feature = "http1")] #[cfg(feature = "http1")]
#[cfg(feature = "server")]
UnsupportedStatusCode, UnsupportedStatusCode,
/// User tried to send a Request with Client with non-absolute URI. /// User tried to send a Request with Client with non-absolute URI.
#[cfg(any(feature = "http1", feature = "http2"))] #[cfg(any(feature = "http1", feature = "http2"))]
@@ -178,6 +186,7 @@ impl Error {
} }
#[cfg(feature = "http1")] #[cfg(feature = "http1")]
#[cfg(feature = "server")]
pub(crate) fn kind(&self) -> &Kind { pub(crate) fn kind(&self) -> &Kind {
&self.inner.kind &self.inner.kind
} }
@@ -234,11 +243,13 @@ impl Error {
} }
#[cfg(all(any(feature = "http1", feature = "http2"), feature = "tcp"))] #[cfg(all(any(feature = "http1", feature = "http2"), feature = "tcp"))]
#[cfg(feature = "server")]
pub(crate) fn new_listen<E: Into<Cause>>(cause: E) -> Error { pub(crate) fn new_listen<E: Into<Cause>>(cause: E) -> Error {
Error::new(Kind::Listen).with(cause) Error::new(Kind::Listen).with(cause)
} }
#[cfg(any(feature = "http1", feature = "http2"))] #[cfg(any(feature = "http1", feature = "http2"))]
#[cfg(feature = "server")]
pub(crate) fn new_accept<E: Into<Cause>>(cause: E) -> Error { pub(crate) fn new_accept<E: Into<Cause>>(cause: E) -> Error {
Error::new(Kind::Accept).with(cause) Error::new(Kind::Accept).with(cause)
} }
@@ -272,6 +283,7 @@ impl Error {
} }
#[cfg(feature = "http1")] #[cfg(feature = "http1")]
#[cfg(feature = "server")]
pub(crate) fn new_user_header() -> Error { pub(crate) fn new_user_header() -> Error {
Error::new_user(User::UnexpectedHeader) Error::new_user(User::UnexpectedHeader)
} }
@@ -289,6 +301,7 @@ impl Error {
} }
#[cfg(feature = "http1")] #[cfg(feature = "http1")]
#[cfg(feature = "server")]
pub(crate) fn new_user_unsupported_status_code() -> Error { pub(crate) fn new_user_unsupported_status_code() -> Error {
Error::new_user(User::UnsupportedStatusCode) Error::new_user(User::UnsupportedStatusCode)
} }
@@ -309,6 +322,7 @@ impl Error {
} }
#[cfg(any(feature = "http1", feature = "http2"))] #[cfg(any(feature = "http1", feature = "http2"))]
#[cfg(feature = "server")]
pub(crate) fn new_user_make_service<E: Into<Cause>>(cause: E) -> Error { pub(crate) fn new_user_make_service<E: Into<Cause>>(cause: E) -> Error {
Error::new_user(User::MakeService).with(cause) Error::new_user(User::MakeService).with(cause)
} }
@@ -354,8 +368,10 @@ impl Error {
Kind::Connect => "error trying to connect", Kind::Connect => "error trying to connect",
Kind::Canceled => "operation was canceled", Kind::Canceled => "operation was canceled",
#[cfg(all(any(feature = "http1", feature = "http2"), feature = "tcp"))] #[cfg(all(any(feature = "http1", feature = "http2"), feature = "tcp"))]
#[cfg(feature = "server")]
Kind::Listen => "error creating server listener", Kind::Listen => "error creating server listener",
#[cfg(any(feature = "http1", feature = "http2"))] #[cfg(any(feature = "http1", feature = "http2"))]
#[cfg(feature = "server")]
Kind::Accept => "error accepting connection", Kind::Accept => "error accepting connection",
#[cfg(any(feature = "http1", feature = "http2", feature = "stream"))] #[cfg(any(feature = "http1", feature = "http2", feature = "stream"))]
Kind::Body => "error reading a body from connection", Kind::Body => "error reading a body from connection",
@@ -372,10 +388,12 @@ impl Error {
#[cfg(any(feature = "http1", feature = "http2"))] #[cfg(any(feature = "http1", feature = "http2"))]
Kind::User(User::Body) => "error from user's HttpBody stream", Kind::User(User::Body) => "error from user's HttpBody stream",
#[cfg(any(feature = "http1", feature = "http2"))] #[cfg(any(feature = "http1", feature = "http2"))]
#[cfg(feature = "server")]
Kind::User(User::MakeService) => "error from user's MakeService", Kind::User(User::MakeService) => "error from user's MakeService",
#[cfg(any(feature = "http1", feature = "http2"))] #[cfg(any(feature = "http1", feature = "http2"))]
Kind::User(User::Service) => "error from user's Service", Kind::User(User::Service) => "error from user's Service",
#[cfg(feature = "http1")] #[cfg(feature = "http1")]
#[cfg(feature = "server")]
Kind::User(User::UnexpectedHeader) => "user sent unexpected header", Kind::User(User::UnexpectedHeader) => "user sent unexpected header",
#[cfg(any(feature = "http1", feature = "http2"))] #[cfg(any(feature = "http1", feature = "http2"))]
#[cfg(feature = "client")] #[cfg(feature = "client")]
@@ -384,6 +402,7 @@ impl Error {
#[cfg(feature = "client")] #[cfg(feature = "client")]
Kind::User(User::UnsupportedRequestMethod) => "request has unsupported HTTP method", Kind::User(User::UnsupportedRequestMethod) => "request has unsupported HTTP method",
#[cfg(feature = "http1")] #[cfg(feature = "http1")]
#[cfg(feature = "server")]
Kind::User(User::UnsupportedStatusCode) => { Kind::User(User::UnsupportedStatusCode) => {
"response has 1xx status code, not supported by server" "response has 1xx status code, not supported by server"
} }

View File

@@ -30,6 +30,7 @@ fn connection_has(value: &HeaderValue, needle: &str) -> bool {
} }
#[cfg(feature = "http1")] #[cfg(feature = "http1")]
#[cfg(feature = "server")]
pub fn content_length_parse(value: &HeaderValue) -> Option<u64> { pub fn content_length_parse(value: &HeaderValue) -> Option<u64> {
value.to_str().ok().and_then(|s| s.parse().ok()) value.to_str().ok().and_then(|s| s.parse().ok())
} }

View File

@@ -68,12 +68,9 @@ pub mod rt;
pub mod service; pub mod service;
pub mod upgrade; pub mod upgrade;
cfg_any_http! { cfg_proto! {
mod headers; mod headers;
mod proto; mod proto;
pub mod server;
pub use crate::server::Server;
} }
cfg_feature! { cfg_feature! {
@@ -82,3 +79,10 @@ cfg_feature! {
pub mod client; pub mod client;
pub use crate::client::Client; pub use crate::client::Client;
} }
cfg_feature! {
#![all(feature = "server", any(feature = "http1", feature = "http2"))]
pub mod server;
pub use crate::server::Server;
}

View File

@@ -57,6 +57,7 @@ where
} }
} }
#[cfg(feature = "server")]
pub fn set_flush_pipeline(&mut self, enabled: bool) { pub fn set_flush_pipeline(&mut self, enabled: bool) {
self.io.set_flush_pipeline(enabled); self.io.set_flush_pipeline(enabled);
} }
@@ -83,6 +84,7 @@ where
self.state.title_case_headers = true; self.state.title_case_headers = true;
} }
#[cfg(feature = "server")]
pub(crate) fn set_allow_half_close(&mut self) { pub(crate) fn set_allow_half_close(&mut self) {
self.state.allow_half_close = true; self.state.allow_half_close = true;
} }
@@ -485,6 +487,7 @@ where
Encode { Encode {
head: &mut head, head: &mut head,
body, body,
#[cfg(feature = "server")]
keep_alive: self.state.wants_keep_alive(), keep_alive: self.state.wants_keep_alive(),
req_method: &mut self.state.method, req_method: &mut self.state.method,
title_case_headers: self.state.title_case_headers, title_case_headers: self.state.title_case_headers,
@@ -690,6 +693,7 @@ where
self.state.close_write(); self.state.close_write();
} }
#[cfg(feature = "server")]
pub fn disable_keep_alive(&mut self) { pub fn disable_keep_alive(&mut self) {
if self.state.is_idle() { if self.state.is_idle() {
trace!("disable_keep_alive; closing idle connection"); trace!("disable_keep_alive; closing idle connection");

View File

@@ -1,7 +1,7 @@
use std::error::Error as StdError; use std::error::Error as StdError;
use bytes::{Buf, Bytes}; use bytes::{Buf, Bytes};
use http::{Request, StatusCode}; use http::Request;
use tokio::io::{AsyncRead, AsyncWrite}; use tokio::io::{AsyncRead, AsyncWrite};
use super::{Http1Transaction, Wants}; use super::{Http1Transaction, Wants};
@@ -10,7 +10,6 @@ use crate::common::{task, Future, Pin, Poll, Unpin};
use crate::proto::{ use crate::proto::{
BodyLength, Conn, Dispatched, MessageHead, RequestHead, BodyLength, Conn, Dispatched, MessageHead, RequestHead,
}; };
use crate::service::HttpService;
pub(crate) struct Dispatcher<D, Bs: HttpBody, I, T> { pub(crate) struct Dispatcher<D, Bs: HttpBody, I, T> {
conn: Conn<I, Bs::Data, T>, conn: Conn<I, Bs::Data, T>,
@@ -34,9 +33,13 @@ pub(crate) trait Dispatch {
fn should_poll(&self) -> bool; fn should_poll(&self) -> bool;
} }
pub struct Server<S: HttpService<B>, B> { cfg_server! {
use crate::service::HttpService;
pub struct Server<S: HttpService<B>, B> {
in_flight: Pin<Box<Option<S::Future>>>, in_flight: Pin<Box<Option<S::Future>>>,
pub(crate) service: S, pub(crate) service: S,
}
} }
cfg_client! { cfg_client! {
@@ -74,6 +77,7 @@ where
} }
} }
#[cfg(feature = "server")]
pub fn disable_keep_alive(&mut self) { pub fn disable_keep_alive(&mut self) {
self.conn.disable_keep_alive(); self.conn.disable_keep_alive();
if self.conn.is_write_closed() { if self.conn.is_write_closed() {
@@ -441,10 +445,11 @@ impl<'a, T> Drop for OptGuard<'a, T> {
// ===== impl Server ===== // ===== impl Server =====
impl<S, B> Server<S, B> cfg_server! {
where impl<S, B> Server<S, B>
where
S: HttpService<B>, S: HttpService<B>,
{ {
pub fn new(service: S) -> Server<S, B> { pub fn new(service: S) -> Server<S, B> {
Server { Server {
in_flight: Box::pin(None), in_flight: Box::pin(None),
@@ -455,18 +460,18 @@ where
pub fn into_service(self) -> S { pub fn into_service(self) -> S {
self.service self.service
} }
} }
// Service is never pinned // Service is never pinned
impl<S: HttpService<B>, B> Unpin for Server<S, B> {} impl<S: HttpService<B>, B> Unpin for Server<S, B> {}
impl<S, Bs> Dispatch for Server<S, Body> impl<S, Bs> Dispatch for Server<S, Body>
where where
S: HttpService<Body, ResBody = Bs>, S: HttpService<Body, ResBody = Bs>,
S::Error: Into<Box<dyn StdError + Send + Sync>>, S::Error: Into<Box<dyn StdError + Send + Sync>>,
Bs: HttpBody, Bs: HttpBody,
{ {
type PollItem = MessageHead<StatusCode>; type PollItem = MessageHead<http::StatusCode>;
type PollBody = Bs; type PollBody = Bs;
type PollError = S::Error; type PollError = S::Error;
type RecvItem = RequestHead; type RecvItem = RequestHead;
@@ -520,6 +525,7 @@ where
fn should_poll(&self) -> bool { fn should_poll(&self) -> bool {
self.in_flight.is_some() self.in_flight.is_some()
} }
}
} }
// ===== impl Client ===== // ===== impl Client =====

View File

@@ -35,6 +35,7 @@ enum Kind {
/// ///
/// This is mostly only used with HTTP/1.0 with a length. This kind requires /// This is mostly only used with HTTP/1.0 with a length. This kind requires
/// the connection to be closed when the body is finished. /// the connection to be closed when the body is finished.
#[cfg(feature = "server")]
CloseDelimited, CloseDelimited,
} }
@@ -61,6 +62,7 @@ impl Encoder {
Encoder::new(Kind::Length(len)) Encoder::new(Kind::Length(len))
} }
#[cfg(feature = "server")]
pub fn close_delimited() -> Encoder { pub fn close_delimited() -> Encoder {
Encoder::new(Kind::CloseDelimited) Encoder::new(Kind::CloseDelimited)
} }
@@ -72,6 +74,7 @@ impl Encoder {
} }
} }
#[cfg(feature = "server")]
pub fn set_last(mut self, is_last: bool) -> Self { pub fn set_last(mut self, is_last: bool) -> Self {
self.is_last = is_last; self.is_last = is_last;
self self
@@ -83,6 +86,7 @@ impl Encoder {
pub fn is_close_delimited(&self) -> bool { pub fn is_close_delimited(&self) -> bool {
match self.kind { match self.kind {
#[cfg(feature = "server")]
Kind::CloseDelimited => true, Kind::CloseDelimited => true,
_ => false, _ => false,
} }
@@ -94,6 +98,7 @@ impl Encoder {
Kind::Chunked => Ok(Some(EncodedBuf { Kind::Chunked => Ok(Some(EncodedBuf {
kind: BufKind::ChunkedEnd(b"0\r\n\r\n"), kind: BufKind::ChunkedEnd(b"0\r\n\r\n"),
})), })),
#[cfg(feature = "server")]
Kind::CloseDelimited => Ok(None), Kind::CloseDelimited => Ok(None),
Kind::Length(_) => Err(NotEof), Kind::Length(_) => Err(NotEof),
} }
@@ -125,6 +130,7 @@ impl Encoder {
BufKind::Exact(msg) BufKind::Exact(msg)
} }
} }
#[cfg(feature = "server")]
Kind::CloseDelimited => { Kind::CloseDelimited => {
trace!("close delimited write {}B", len); trace!("close delimited write {}B", len);
BufKind::Exact(msg) BufKind::Exact(msg)
@@ -168,6 +174,7 @@ impl Encoder {
} }
} }
} }
#[cfg(feature = "server")]
Kind::CloseDelimited => { Kind::CloseDelimited => {
trace!("close delimited write {}B", len); trace!("close delimited write {}B", len);
dst.buffer(msg); dst.buffer(msg);

View File

@@ -66,6 +66,7 @@ where
} }
} }
#[cfg(feature = "server")]
pub fn set_flush_pipeline(&mut self, enabled: bool) { pub fn set_flush_pipeline(&mut self, enabled: bool) {
debug_assert!(!self.write_buf.has_remaining()); debug_assert!(!self.write_buf.has_remaining());
self.flush_pipeline = enabled; self.flush_pipeline = enabled;

View File

@@ -18,12 +18,15 @@ mod encode;
mod io; mod io;
mod role; mod role;
pub(crate) type ServerTransaction = role::Server;
cfg_client! { cfg_client! {
pub(crate) type ClientTransaction = role::Client; pub(crate) type ClientTransaction = role::Client;
} }
cfg_server! {
pub(crate) type ServerTransaction = role::Server;
}
pub(crate) trait Http1Transaction { pub(crate) trait Http1Transaction {
type Incoming; type Incoming;
type Outgoing: Default; type Outgoing: Default;
@@ -73,6 +76,7 @@ pub(crate) struct ParseContext<'a> {
pub(crate) struct Encode<'a, T> { pub(crate) struct Encode<'a, T> {
head: &'a mut MessageHead<T>, head: &'a mut MessageHead<T>,
body: Option<BodyLength>, body: Option<BodyLength>,
#[cfg(feature = "server")]
keep_alive: bool, keep_alive: bool,
req_method: &'a mut Option<Method>, req_method: &'a mut Option<Method>,
title_case_headers: bool, title_case_headers: bool,

View File

@@ -10,6 +10,7 @@ use http::header::{self, Entry, HeaderName, HeaderValue};
use http::{HeaderMap, Method, StatusCode, Version}; use http::{HeaderMap, Method, StatusCode, Version};
use crate::body::DecodedLength; use crate::body::DecodedLength;
#[cfg(feature = "server")]
use crate::common::date; use crate::common::date;
use crate::error::Parse; use crate::error::Parse;
use crate::headers; use crate::headers;
@@ -94,10 +95,13 @@ where
// There are 2 main roles, Client and Server. // There are 2 main roles, Client and Server.
#[cfg(feature = "client")]
pub(crate) enum Client {} pub(crate) enum Client {}
#[cfg(feature = "server")]
pub(crate) enum Server {} pub(crate) enum Server {}
#[cfg(feature = "server")]
impl Http1Transaction for Server { impl Http1Transaction for Server {
type Incoming = RequestLine; type Incoming = RequestLine;
type Outgoing = StatusCode; type Outgoing = StatusCode;
@@ -618,6 +622,7 @@ impl Http1Transaction for Server {
} }
} }
#[cfg(feature = "server")]
impl Server { impl Server {
fn can_have_body(method: &Option<Method>, status: StatusCode) -> bool { fn can_have_body(method: &Option<Method>, status: StatusCode) -> bool {
Server::can_chunked(method, status) Server::can_chunked(method, status)
@@ -640,6 +645,7 @@ impl Server {
} }
} }
#[cfg(feature = "client")]
impl Http1Transaction for Client { impl Http1Transaction for Client {
type Incoming = StatusCode; type Incoming = StatusCode;
type Outgoing = RequestLine; type Outgoing = RequestLine;
@@ -779,6 +785,7 @@ impl Http1Transaction for Client {
} }
} }
#[cfg(feature = "client")]
impl Client { impl Client {
/// Returns Some(length, wants_upgrade) if successful. /// Returns Some(length, wants_upgrade) if successful.
/// ///
@@ -846,9 +853,6 @@ impl Client {
Ok(Some((DecodedLength::CLOSE_DELIMITED, false))) Ok(Some((DecodedLength::CLOSE_DELIMITED, false)))
} }
} }
}
impl Client {
fn set_length(head: &mut RequestHead, body: Option<BodyLength>) -> Encoder { fn set_length(head: &mut RequestHead, body: Option<BodyLength>) -> Encoder {
let body = if let Some(body) = body { let body = if let Some(body) = body {
body body

View File

@@ -14,14 +14,16 @@ use crate::common::{task, Future, Pin, Poll};
use crate::headers::content_length_parse_all; use crate::headers::content_length_parse_all;
pub(crate) mod ping; pub(crate) mod ping;
pub(crate) mod server;
cfg_client! { cfg_client! {
pub(crate) mod client; pub(crate) mod client;
pub(crate) use self::client::ClientTask; pub(crate) use self::client::ClientTask;
} }
pub(crate) use self::server::Server; cfg_server! {
pub(crate) mod server;
pub(crate) use self::server::Server;
}
/// Default initial stream window size defined in HTTP2 spec. /// Default initial stream window size defined in HTTP2 spec.
pub(crate) const SPEC_WINDOW_SIZE: u32 = 65_535; pub(crate) const SPEC_WINDOW_SIZE: u32 = 65_535;

View File

@@ -3,10 +3,12 @@
cfg_http1! { cfg_http1! {
pub(crate) mod h1; pub(crate) mod h1;
pub(crate) use self::h1::{Conn, ServerTransaction}; pub(crate) use self::h1::Conn;
#[cfg(feature = "client")] #[cfg(feature = "client")]
pub(crate) use self::h1::dispatch; pub(crate) use self::h1::dispatch;
#[cfg(feature = "server")]
pub(crate) use self::h1::ServerTransaction;
} }
cfg_http2! { cfg_http2! {

View File

@@ -49,6 +49,7 @@ pub(crate) use self::http::HttpService;
#[cfg(feature = "client")] #[cfg(feature = "client")]
pub(crate) use self::make::MakeConnection; pub(crate) use self::make::MakeConnection;
#[cfg(any(feature = "http1", feature = "http2"))] #[cfg(any(feature = "http1", feature = "http2"))]
#[cfg(feature = "server")]
pub(crate) use self::make::MakeServiceRef; pub(crate) use self::make::MakeServiceRef;
#[cfg(any(feature = "http1", feature = "http2"))] #[cfg(any(feature = "http1", feature = "http2"))]
#[cfg(feature = "client")] #[cfg(feature = "client")]