hyper-0.12.35/Cargo.toml.orig010066400017500001750000000067521353675575500141620ustar0000000000000000[package] name = "hyper" version = "0.12.35" # don't forget to update html_root_url description = "A fast and correct HTTP library." readme = "README.md" homepage = "https://hyper.rs" documentation = "https://docs.rs/hyper" repository = "https://github.com/hyperium/hyper" license = "MIT" authors = ["Sean McArthur "] keywords = ["http", "hyper", "hyperium"] categories = ["network-programming", "web-programming::http-client", "web-programming::http-server"] include = [ "Cargo.toml", "LICENSE", "src/**/*", "build.rs", ] [dependencies] bytes = "0.4.4" futures = "0.1.21" futures-cpupool = { version = "0.1.6", optional = true } http = "0.1.15" http-body = "0.1" httparse = "1.0" h2 = "0.1.10" iovec = "0.1" itoa = "0.4.1" log = "0.4" net2 = { version = "0.2.32", optional = true } time = "0.1" tokio = { version = "0.1.14", optional = true, default-features = false, features = ["rt-full"] } tokio-buf = "0.1" tokio-executor = { version = "0.1.0", optional = true } tokio-io = "0.1" tokio-reactor = { version = "0.1", optional = true } tokio-tcp = { version = "0.1", optional = true } tokio-threadpool = { version = "0.1.3", optional = true } tokio-timer = { version = "0.2", optional = true } want = "0.2" [build-dependencies] rustc_version = "0.2" [dev-dependencies] futures-timer = "0.1" num_cpus = "1.0" pretty_env_logger = "0.3" spmc = "0.3" url = "1.0" tokio-fs = "0.1" tokio-mockstream = "1.1.0" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" [features] default = [ "__internal_flaky_tests", "runtime", ] runtime = [ "futures-cpupool", "net2", "tokio", "tokio-executor", "tokio-reactor", "tokio-tcp", "tokio-threadpool", "tokio-timer", ] nightly = [] __internal_flaky_tests = [] __internal_happy_eyeballs_tests = [] [profile.release] codegen-units = 1 incremental = false [profile.bench] codegen-units = 1 incremental = false [[example]] name = "client" path = "examples/client.rs" required-features = ["runtime"] [[example]] name = "client_json" path = "examples/client_json.rs" required-features = ["runtime"] [[example]] name = "echo" path = "examples/echo.rs" required-features = ["runtime"] [[example]] name = "hello" path = "examples/hello.rs" required-features = ["runtime"] [[example]] name = "multi_server" path = "examples/multi_server.rs" required-features = ["runtime"] [[example]] name = "params" path = "examples/params.rs" required-features = ["runtime"] [[example]] name = "proxy" path = "examples/proxy.rs" required-features = ["runtime"] [[example]] name = "send_file" path = "examples/send_file.rs" required-features = ["runtime"] [[example]] name = "single_threaded" path = "examples/single_threaded.rs" required-features = ["runtime"] [[example]] name = "state" path = "examples/state.rs" required-features = ["runtime"] [[example]] name = "upgrades" path = "examples/upgrades.rs" required-features = ["runtime"] [[example]] name = "web_api" path = "examples/web_api.rs" required-features = ["runtime"] [[bench]] name = "end_to_end" path = "benches/end_to_end.rs" required-features = ["runtime"] [[bench]] name = "pipeline" path = "benches/pipeline.rs" required-features = ["runtime"] [[bench]] name = "server" path = "benches/server.rs" required-features = ["runtime"] [[test]] name = "client" path = "tests/client.rs" required-features = ["runtime"] [[test]] name = "integration" path = "tests/integration.rs" required-features = ["runtime"] [[test]] name = "server" path = "tests/server.rs" required-features = ["runtime"] hyper-0.12.35/Cargo.toml0000644000000110070000000000000103670ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g. crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "hyper" version = "0.12.35" authors = ["Sean McArthur "] include = ["Cargo.toml", "LICENSE", "src/**/*", "build.rs"] description = "A fast and correct HTTP library." homepage = "https://hyper.rs" documentation = "https://docs.rs/hyper" readme = "README.md" keywords = ["http", "hyper", "hyperium"] categories = ["network-programming", "web-programming::http-client", "web-programming::http-server"] license = "MIT" repository = "https://github.com/hyperium/hyper" [profile.bench] codegen-units = 1 incremental = false [profile.release] codegen-units = 1 incremental = false [[example]] name = "client" path = "examples/client.rs" required-features = ["runtime"] [[example]] name = "client_json" path = "examples/client_json.rs" required-features = ["runtime"] [[example]] name = "echo" path = "examples/echo.rs" required-features = ["runtime"] [[example]] name = "hello" path = "examples/hello.rs" required-features = ["runtime"] [[example]] name = "multi_server" path = "examples/multi_server.rs" required-features = ["runtime"] [[example]] name = "params" path = "examples/params.rs" required-features = ["runtime"] [[example]] name = "proxy" path = "examples/proxy.rs" required-features = ["runtime"] [[example]] name = "send_file" path = "examples/send_file.rs" required-features = ["runtime"] [[example]] name = "single_threaded" path = "examples/single_threaded.rs" required-features = ["runtime"] [[example]] name = "state" path = "examples/state.rs" required-features = ["runtime"] [[example]] name = "upgrades" path = "examples/upgrades.rs" required-features = ["runtime"] [[example]] name = "web_api" path = "examples/web_api.rs" required-features = ["runtime"] [[test]] name = "client" path = "tests/client.rs" required-features = ["runtime"] [[test]] name = "integration" path = "tests/integration.rs" required-features = ["runtime"] [[test]] name = "server" path = "tests/server.rs" required-features = ["runtime"] [[bench]] name = "end_to_end" path = "benches/end_to_end.rs" required-features = ["runtime"] [[bench]] name = "pipeline" path = "benches/pipeline.rs" required-features = ["runtime"] [[bench]] name = "server" path = "benches/server.rs" required-features = ["runtime"] [dependencies.bytes] version = "0.4.4" [dependencies.futures] version = "0.1.21" [dependencies.futures-cpupool] version = "0.1.6" optional = true [dependencies.h2] version = "0.1.10" [dependencies.http] version = "0.1.15" [dependencies.http-body] version = "0.1" [dependencies.httparse] version = "1.0" [dependencies.iovec] version = "0.1" [dependencies.itoa] version = "0.4.1" [dependencies.log] version = "0.4" [dependencies.net2] version = "0.2.32" optional = true [dependencies.time] version = "0.1" [dependencies.tokio] version = "0.1.14" features = ["rt-full"] optional = true default-features = false [dependencies.tokio-buf] version = "0.1" [dependencies.tokio-executor] version = "0.1.0" optional = true [dependencies.tokio-io] version = "0.1" [dependencies.tokio-reactor] version = "0.1" optional = true [dependencies.tokio-tcp] version = "0.1" optional = true [dependencies.tokio-threadpool] version = "0.1.3" optional = true [dependencies.tokio-timer] version = "0.2" optional = true [dependencies.want] version = "0.2" [dev-dependencies.futures-timer] version = "0.1" [dev-dependencies.num_cpus] version = "1.0" [dev-dependencies.pretty_env_logger] version = "0.3" [dev-dependencies.serde] version = "1.0" [dev-dependencies.serde_derive] version = "1.0" [dev-dependencies.serde_json] version = "1.0" [dev-dependencies.spmc] version = "0.3" [dev-dependencies.tokio-fs] version = "0.1" [dev-dependencies.tokio-mockstream] version = "1.1.0" [dev-dependencies.url] version = "1.0" [build-dependencies.rustc_version] version = "0.2" [features] __internal_flaky_tests = [] __internal_happy_eyeballs_tests = [] default = ["__internal_flaky_tests", "runtime"] nightly = [] runtime = ["futures-cpupool", "net2", "tokio", "tokio-executor", "tokio-reactor", "tokio-tcp", "tokio-threadpool", "tokio-timer"] hyper-0.12.35/Cargo.toml.orig0000644000000110100000000000000113200ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "hyper" version = "0.12.35" authors = ["Sean McArthur "] include = ["Cargo.toml", "LICENSE", "src/**/*", "build.rs"] description = "A fast and correct HTTP library." homepage = "https://hyper.rs" documentation = "https://docs.rs/hyper" readme = "README.md" keywords = ["http", "hyper", "hyperium"] categories = ["network-programming", "web-programming::http-client", "web-programming::http-server"] license = "MIT" repository = "https://github.com/hyperium/hyper" [profile.bench] codegen-units = 1 incremental = false [profile.release] codegen-units = 1 incremental = false [[example]] name = "client" path = "examples/client.rs" required-features = ["runtime"] [[example]] name = "client_json" path = "examples/client_json.rs" required-features = ["runtime"] [[example]] name = "echo" path = "examples/echo.rs" required-features = ["runtime"] [[example]] name = "hello" path = "examples/hello.rs" required-features = ["runtime"] [[example]] name = "multi_server" path = "examples/multi_server.rs" required-features = ["runtime"] [[example]] name = "params" path = "examples/params.rs" required-features = ["runtime"] [[example]] name = "proxy" path = "examples/proxy.rs" required-features = ["runtime"] [[example]] name = "send_file" path = "examples/send_file.rs" required-features = ["runtime"] [[example]] name = "single_threaded" path = "examples/single_threaded.rs" required-features = ["runtime"] [[example]] name = "state" path = "examples/state.rs" required-features = ["runtime"] [[example]] name = "upgrades" path = "examples/upgrades.rs" required-features = ["runtime"] [[example]] name = "web_api" path = "examples/web_api.rs" required-features = ["runtime"] [[test]] name = "client" path = "tests/client.rs" required-features = ["runtime"] [[test]] name = "integration" path = "tests/integration.rs" required-features = ["runtime"] [[test]] name = "server" path = "tests/server.rs" required-features = ["runtime"] [[bench]] name = "end_to_end" path = "benches/end_to_end.rs" required-features = ["runtime"] [[bench]] name = "pipeline" path = "benches/pipeline.rs" required-features = ["runtime"] [[bench]] name = "server" path = "benches/server.rs" required-features = ["runtime"] [dependencies.bytes] version = "0.4.4" [dependencies.futures] version = "0.1.21" [dependencies.futures-cpupool] version = "0.1.6" optional = true [dependencies.h2] version = "0.1.10" [dependencies.http] version = "0.1.15" [dependencies.http-body] version = "0.1" [dependencies.httparse] version = "1.0" [dependencies.iovec] version = "0.1" [dependencies.itoa] version = "0.4.1" [dependencies.log] version = "0.4" [dependencies.net2] version = "0.2.32" optional = true [dependencies.time] version = "0.1" [dependencies.tokio] version = "0.1.14" features = ["rt-full"] optional = true default-features = false [dependencies.tokio-buf] version = "0.1" [dependencies.tokio-executor] version = "0.1.0" optional = true [dependencies.tokio-io] version = "0.1" [dependencies.tokio-reactor] version = "0.1" optional = true [dependencies.tokio-tcp] version = "0.1" optional = true [dependencies.tokio-threadpool] version = "0.1.3" optional = true [dependencies.tokio-timer] version = "0.2" optional = true [dependencies.want] version = "0.2" [dev-dependencies.futures-timer] version = "0.1" [dev-dependencies.num_cpus] version = "1.0" [dev-dependencies.pretty_env_logger] version = "0.3" [dev-dependencies.serde] version = "1.0" [dev-dependencies.serde_derive] version = "1.0" [dev-dependencies.serde_json] version = "1.0" [dev-dependencies.spmc] version = "0.3" [dev-dependencies.tokio-fs] version = "0.1" [dev-dependencies.tokio-mockstream] version = "1.1.0" [dev-dependencies.url] version = "1.0" [build-dependencies.rustc_version] version = "0.2" [features] __internal_flaky_tests = [] __internal_happy_eyeballs_tests = [] default = ["__internal_flaky_tests", "runtime"] nightly = [] runtime = ["futures-cpupool", "net2", "tokio", "tokio-executor", "tokio-reactor", "tokio-tcp", "tokio-threadpool", "tokio-timer"] hyper-0.12.35/LICENSE010066400017500001750000000020471346064762000122540ustar0000000000000000Copyright (c) 2014-2018 Sean McArthur Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. hyper-0.12.35/build.rs010066400017500001750000000005211353675567300127230ustar0000000000000000extern crate rustc_version; use rustc_version::{version, Version}; fn main() { let version = version().unwrap(); if version >= Version::parse("1.30.0").unwrap() { println!("cargo:rustc-cfg=error_source"); } if version >= Version::parse("1.34.0").unwrap() { println!("cargo:rustc-cfg=try_from"); } } hyper-0.12.35/src/body/body.rs010066400017500001750000000356651353675572100143200ustar0000000000000000use std::borrow::Cow; use std::error::Error as StdError; use std::fmt; use bytes::Bytes; use futures::sync::{mpsc, oneshot}; use futures::{Async, Future, Poll, Stream, Sink, AsyncSink, StartSend}; use tokio_buf::SizeHint; use h2; use http::HeaderMap; use common::Never; use super::internal::{FullDataArg, FullDataRet}; use super::{Chunk, Payload}; use upgrade::OnUpgrade; type BodySender = mpsc::Sender>; /// A stream of `Chunk`s, used when receiving bodies. /// /// A good default `Payload` to use in many applications. /// /// Also implements `futures::Stream`, so stream combinators may be used. #[must_use = "streams do nothing unless polled"] pub struct Body { kind: Kind, /// Keep the extra bits in an `Option>`, so that /// Body stays small in the common case (no extras needed). extra: Option>, } enum Kind { Once(Option), Chan { content_length: Option, abort_rx: oneshot::Receiver<()>, rx: mpsc::Receiver>, }, H2 { content_length: Option, recv: h2::RecvStream, }, Wrapped(Box> + Send>), } struct Extra { /// Allow the client to pass a future to delay the `Body` from returning /// EOF. This allows the `Client` to try to put the idle connection /// back into the pool before the body is "finished". /// /// The reason for this is so that creating a new request after finishing /// streaming the body of a response could sometimes result in creating /// a brand new connection, since the pool didn't know about the idle /// connection yet. delayed_eof: Option, on_upgrade: OnUpgrade, } type DelayEofUntil = oneshot::Receiver; enum DelayEof { /// Initial state, stream hasn't seen EOF yet. NotEof(DelayEofUntil), /// Transitions to this state once we've seen `poll` try to /// return EOF (`None`). This future is then polled, and /// when it completes, the Body finally returns EOF (`None`). Eof(DelayEofUntil), } /// A sender half used with `Body::channel()`. /// /// Useful when wanting to stream chunks from another thread. See /// [`Body::channel`](Body::channel) for more. #[must_use = "Sender does nothing unless sent on"] #[derive(Debug)] pub struct Sender { abort_tx: oneshot::Sender<()>, tx: BodySender, } impl Body { /// Create an empty `Body` stream. /// /// # Example /// /// ``` /// use hyper::{Body, Request}; /// /// // create a `GET /` request /// let get = Request::new(Body::empty()); /// ``` #[inline] pub fn empty() -> Body { Body::new(Kind::Once(None)) } /// Create a `Body` stream with an associated sender half. /// /// Useful when wanting to stream chunks from another thread. #[inline] pub fn channel() -> (Sender, Body) { Self::new_channel(None) } pub(crate) fn new_channel(content_length: Option) -> (Sender, Body) { let (tx, rx) = mpsc::channel(0); let (abort_tx, abort_rx) = oneshot::channel(); let tx = Sender { abort_tx: abort_tx, tx: tx, }; let rx = Body::new(Kind::Chan { content_length, abort_rx, rx, }); (tx, rx) } /// Wrap a futures `Stream` in a box inside `Body`. /// /// # Example /// /// ``` /// # extern crate futures; /// # extern crate hyper; /// # use hyper::Body; /// # fn main() { /// let chunks = vec![ /// "hello", /// " ", /// "world", /// ]; /// /// let stream = futures::stream::iter_ok::<_, ::std::io::Error>(chunks); /// /// let body = Body::wrap_stream(stream); /// # } /// ``` pub fn wrap_stream(stream: S) -> Body where S: Stream + Send + 'static, S::Error: Into>, Chunk: From, { let mapped = stream.map(Chunk::from).map_err(Into::into); Body::new(Kind::Wrapped(Box::new(mapped))) } /// Converts this `Body` into a `Future` of a pending HTTP upgrade. /// /// See [the `upgrade` module](::upgrade) for more. pub fn on_upgrade(self) -> OnUpgrade { self .extra .map(|ex| ex.on_upgrade) .unwrap_or_else(OnUpgrade::none) } fn new(kind: Kind) -> Body { Body { kind: kind, extra: None, } } pub(crate) fn h2(recv: h2::RecvStream, content_length: Option) -> Self { Body::new(Kind::H2 { content_length, recv, }) } pub(crate) fn set_on_upgrade(&mut self, upgrade: OnUpgrade) { debug_assert!(!upgrade.is_none(), "set_on_upgrade with empty upgrade"); let extra = self.extra_mut(); debug_assert!(extra.on_upgrade.is_none(), "set_on_upgrade twice"); extra.on_upgrade = upgrade; } pub(crate) fn delayed_eof(&mut self, fut: DelayEofUntil) { self.extra_mut().delayed_eof = Some(DelayEof::NotEof(fut)); } fn take_delayed_eof(&mut self) -> Option { self .extra .as_mut() .and_then(|extra| extra.delayed_eof.take()) } fn extra_mut(&mut self) -> &mut Extra { self .extra .get_or_insert_with(|| Box::new(Extra { delayed_eof: None, on_upgrade: OnUpgrade::none(), })) } fn poll_eof(&mut self) -> Poll, ::Error> { match self.take_delayed_eof() { Some(DelayEof::NotEof(mut delay)) => { match self.poll_inner() { ok @ Ok(Async::Ready(Some(..))) | ok @ Ok(Async::NotReady) => { self.extra_mut().delayed_eof = Some(DelayEof::NotEof(delay)); ok }, Ok(Async::Ready(None)) => match delay.poll() { Ok(Async::Ready(never)) => match never {}, Ok(Async::NotReady) => { self.extra_mut().delayed_eof = Some(DelayEof::Eof(delay)); Ok(Async::NotReady) }, Err(_done) => { Ok(Async::Ready(None)) }, }, Err(e) => Err(e), } }, Some(DelayEof::Eof(mut delay)) => { match delay.poll() { Ok(Async::Ready(never)) => match never {}, Ok(Async::NotReady) => { self.extra_mut().delayed_eof = Some(DelayEof::Eof(delay)); Ok(Async::NotReady) }, Err(_done) => { Ok(Async::Ready(None)) }, } }, None => self.poll_inner(), } } fn poll_inner(&mut self) -> Poll, ::Error> { match self.kind { Kind::Once(ref mut val) => Ok(Async::Ready(val.take())), Kind::Chan { content_length: ref mut len, ref mut rx, ref mut abort_rx, } => { if let Ok(Async::Ready(())) = abort_rx.poll() { return Err(::Error::new_body_write_aborted()); } match rx.poll().expect("mpsc cannot error") { Async::Ready(Some(Ok(chunk))) => { if let Some(ref mut len) = *len { debug_assert!(*len >= chunk.len() as u64); *len = *len - chunk.len() as u64; } Ok(Async::Ready(Some(chunk))) } Async::Ready(Some(Err(err))) => Err(err), Async::Ready(None) => Ok(Async::Ready(None)), Async::NotReady => Ok(Async::NotReady), } } Kind::H2 { recv: ref mut h2, .. } => h2 .poll() .map(|async| { async.map(|opt| { opt.map(|bytes| { let _ = h2.release_capacity().release_capacity(bytes.len()); Chunk::from(bytes) }) }) }) .map_err(::Error::new_body), Kind::Wrapped(ref mut s) => s.poll().map_err(::Error::new_body), } } } impl Default for Body { /// Returns [`Body::empty()`](Body::empty). #[inline] fn default() -> Body { Body::empty() } } impl Payload for Body { type Data = Chunk; type Error = ::Error; fn poll_data(&mut self) -> Poll, Self::Error> { self.poll_eof() } fn poll_trailers(&mut self) -> Poll, Self::Error> { match self.kind { Kind::H2 { recv: ref mut h2, .. } => h2.poll_trailers().map_err(::Error::new_h2), _ => Ok(Async::Ready(None)), } } fn is_end_stream(&self) -> bool { match self.kind { Kind::Once(ref val) => val.is_none(), Kind::Chan { content_length, .. } => content_length == Some(0), Kind::H2 { recv: ref h2, .. } => h2.is_end_stream(), Kind::Wrapped(..) => false, } } fn content_length(&self) -> Option { match self.kind { Kind::Once(Some(ref val)) => Some(val.len() as u64), Kind::Once(None) => Some(0), Kind::Wrapped(..) => None, Kind::Chan { content_length, .. } | Kind::H2 { content_length, .. } => content_length, } } // We can improve the performance of `Body` when we know it is a Once kind. #[doc(hidden)] fn __hyper_full_data(&mut self, _: FullDataArg) -> FullDataRet { match self.kind { Kind::Once(ref mut val) => FullDataRet(val.take()), _ => FullDataRet(None), } } } impl ::http_body::Body for Body { type Data = Chunk; type Error = ::Error; fn poll_data(&mut self) -> Poll, Self::Error> { ::poll_data(self) } fn poll_trailers(&mut self) -> Poll, Self::Error> { ::poll_trailers(self) } fn is_end_stream(&self) -> bool { ::is_end_stream(self) } fn size_hint(&self) -> SizeHint { let mut hint = SizeHint::default(); let content_length = ::content_length(self); if let Some(size) = content_length { hint.set_upper(size); hint.set_lower(size) } hint } } impl Stream for Body { type Item = Chunk; type Error = ::Error; fn poll(&mut self) -> Poll, Self::Error> { self.poll_data() } } impl fmt::Debug for Body { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { #[derive(Debug)] struct Streaming; #[derive(Debug)] struct Empty; #[derive(Debug)] struct Once<'a>(&'a Chunk); let mut builder = f.debug_tuple("Body"); match self.kind { Kind::Once(None) => builder.field(&Empty), Kind::Once(Some(ref chunk)) => builder.field(&Once(chunk)), _ => builder.field(&Streaming), }; builder.finish() } } impl Sender { /// Check to see if this `Sender` can send more data. pub fn poll_ready(&mut self) -> Poll<(), ::Error> { match self.abort_tx.poll_cancel() { Ok(Async::Ready(())) | Err(_) => return Err(::Error::new_closed()), Ok(Async::NotReady) => (), } self.tx.poll_ready().map_err(|_| ::Error::new_closed()) } /// Sends data on this channel. /// /// This should be called after `poll_ready` indicated the channel /// could accept another `Chunk`. /// /// Returns `Err(Chunk)` if the channel could not (currently) accept /// another `Chunk`. pub fn send_data(&mut self, chunk: Chunk) -> Result<(), Chunk> { self.tx .try_send(Ok(chunk)) .map_err(|err| err.into_inner().expect("just sent Ok")) } /// Aborts the body in an abnormal fashion. pub fn abort(self) { let _ = self.abort_tx.send(()); } pub(crate) fn send_error(&mut self, err: ::Error) { let _ = self.tx.try_send(Err(err)); } } impl Sink for Sender { type SinkItem = Chunk; type SinkError = ::Error; fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { Ok(Async::Ready(())) } fn start_send(&mut self, msg: Chunk) -> StartSend { match self.poll_ready()? { Async::Ready(_) => { self.send_data(msg).map_err(|_| ::Error::new_closed())?; Ok(AsyncSink::Ready) } Async::NotReady => Ok(AsyncSink::NotReady(msg)), } } } impl From for Body { #[inline] fn from(chunk: Chunk) -> Body { if chunk.is_empty() { Body::empty() } else { Body::new(Kind::Once(Some(chunk))) } } } impl From> + Send + 'static>> for Body { #[inline] fn from( stream: Box< dyn Stream> + Send + 'static, >, ) -> Body { Body::new(Kind::Wrapped(stream)) } } impl From for Body { #[inline] fn from(bytes: Bytes) -> Body { Body::from(Chunk::from(bytes)) } } impl From> for Body { #[inline] fn from(vec: Vec) -> Body { Body::from(Chunk::from(vec)) } } impl From<&'static [u8]> for Body { #[inline] fn from(slice: &'static [u8]) -> Body { Body::from(Chunk::from(slice)) } } impl From> for Body { #[inline] fn from(cow: Cow<'static, [u8]>) -> Body { match cow { Cow::Borrowed(b) => Body::from(b), Cow::Owned(o) => Body::from(o), } } } impl From for Body { #[inline] fn from(s: String) -> Body { Body::from(Chunk::from(s.into_bytes())) } } impl From<&'static str> for Body { #[inline] fn from(slice: &'static str) -> Body { Body::from(Chunk::from(slice.as_bytes())) } } impl From> for Body { #[inline] fn from(cow: Cow<'static, str>) -> Body { match cow { Cow::Borrowed(b) => Body::from(b), Cow::Owned(o) => Body::from(o), } } } #[test] fn test_body_stream_concat() { let body = Body::from("hello world"); let total = body.concat2().wait().unwrap(); assert_eq!(total.as_ref(), b"hello world"); } hyper-0.12.35/src/body/chunk.rs010066400017500001750000000071601353675567300144660ustar0000000000000000use std::fmt; use bytes::{Buf, Bytes}; /// A piece of a message body. /// /// These are returned by [`Body`](::Body). It is an efficient buffer type. /// /// A `Chunk` can be easily created by many of Rust's standard types that /// represent a collection of bytes, using `Chunk::from`. pub struct Chunk { /// The buffer of bytes making up this body. bytes: Bytes, } // An unexported type to prevent locking `Chunk::into_iter()` to `Bytes::into_iter()`. #[derive(Debug)] pub struct IntoIter { inner: ::IntoIter, } impl Chunk { /// Converts this `Chunk` directly into the `Bytes` type without copies. /// /// This is simply an inherent alias for `Bytes::from(chunk)`, which exists, /// but doesn't appear in rustdocs. #[inline] pub fn into_bytes(self) -> Bytes { self.into() } } impl Buf for Chunk { #[inline] fn remaining(&self) -> usize { //perf: Bytes::len() isn't inline yet, //so it's slightly slower than checking //the length of the slice. self.bytes().len() } #[inline] fn bytes(&self) -> &[u8] { &self.bytes } #[inline] fn advance(&mut self, cnt: usize) { self.bytes.advance(cnt); } } impl From> for Chunk { #[inline] fn from(v: Vec) -> Chunk { Chunk::from(Bytes::from(v)) } } impl From<&'static [u8]> for Chunk { #[inline] fn from(slice: &'static [u8]) -> Chunk { Chunk::from(Bytes::from_static(slice)) } } impl From for Chunk { #[inline] fn from(s: String) -> Chunk { s.into_bytes().into() } } impl From<&'static str> for Chunk { #[inline] fn from(slice: &'static str) -> Chunk { slice.as_bytes().into() } } impl From for Chunk { #[inline] fn from(bytes: Bytes) -> Chunk { Chunk { bytes: bytes, } } } impl From for Bytes { #[inline] fn from(chunk: Chunk) -> Bytes { chunk.bytes } } impl ::std::ops::Deref for Chunk { type Target = [u8]; #[inline] fn deref(&self) -> &Self::Target { self.as_ref() } } impl AsRef<[u8]> for Chunk { #[inline] fn as_ref(&self) -> &[u8] { &self.bytes } } impl fmt::Debug for Chunk { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.bytes, f) } } impl Default for Chunk { #[inline] fn default() -> Chunk { Chunk::from(Bytes::new()) } } impl IntoIterator for Chunk { type Item = u8; type IntoIter = IntoIter; #[inline] fn into_iter(self) -> Self::IntoIter { IntoIter { inner: self.bytes.into_iter(), } } } impl Extend for Chunk { #[inline] fn extend(&mut self, iter: T) where T: IntoIterator { self.bytes.extend(iter) } } impl Iterator for IntoIter { type Item = u8; #[inline] fn next(&mut self) -> Option { self.inner.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl ExactSizeIterator for IntoIter {} #[cfg(test)] mod tests { #[cfg(feature = "nightly")] use test::Bencher; #[cfg(feature = "nightly")] #[bench] fn bench_chunk_static_buf(b: &mut Bencher) { use bytes::BufMut; let s = "Hello, World!"; b.bytes = s.len() as u64; let mut dst = Vec::with_capacity(128); b.iter(|| { let chunk = ::Chunk::from(s); dst.put(chunk); ::test::black_box(&dst); dst.clear(); }) } } hyper-0.12.35/src/body/mod.rs010066400017500001750000000034521353675567300141350ustar0000000000000000//! Streaming bodies for Requests and Responses //! //! For both [Clients](::client) and [Servers](::server), requests and //! responses use streaming bodies, instead of complete buffering. This //! allows applications to not use memory they don't need, and allows exerting //! back-pressure on connections by only reading when asked. //! //! There are two pieces to this in hyper: //! //! - The [`Payload`](body::Payload) trait the describes all possible bodies. hyper //! allows any body type that implements `Payload`, allowing applications to //! have fine-grained control over their streaming. //! - The [`Body`](Body) concrete type, which is an implementation of `Payload`, //! and returned by hyper as a "receive stream" (so, for server requests and //! client responses). It is also a decent default implementation if you don't //! have very custom needs of your send streams. pub use self::body::{Body, Sender}; pub use self::chunk::Chunk; pub use self::payload::Payload; mod body; mod chunk; mod payload; // The full_data API is not stable, so these types are to try to prevent // users from being able to: // // - Implment `__hyper_full_data` on their own Payloads. // - Call `__hyper_full_data` on any Payload. // // That's because to implement it, they need to name these types, and // they can't because they aren't exported. And to call it, they would // need to create one of these values, which they also can't. pub(crate) mod internal { #[allow(missing_debug_implementations)] pub struct FullDataArg(pub(crate) ()); #[allow(missing_debug_implementations)] pub struct FullDataRet(pub(crate) Option); } fn _assert_send_sync() { fn _assert_send() {} fn _assert_sync() {} _assert_send::(); _assert_send::(); _assert_sync::(); } hyper-0.12.35/src/body/payload.rs010066400017500001750000000064441353675567300150130ustar0000000000000000use std::error::Error as StdError; use bytes::Buf; use futures::{Async, Poll}; use http::HeaderMap; use super::internal::{FullDataArg, FullDataRet}; /// This trait represents a streaming body of a `Request` or `Response`. /// /// The built-in implementation of this trait is [`Body`](::Body), in case you /// don't need to customize a send stream for your own application. pub trait Payload: Send + 'static { /// A buffer of bytes representing a single chunk of a body. type Data: Buf + Send; /// The error type of this stream. type Error: Into>; /// Poll for a `Data` buffer. /// /// Similar to `Stream::poll_next`, this yields `Some(Data)` until /// the body ends, when it yields `None`. fn poll_data(&mut self) -> Poll, Self::Error>; /// Poll for an optional **single** `HeaderMap` of trailers. /// /// This should **only** be called after `poll_data` has ended. /// /// Note: Trailers aren't currently used for HTTP/1, only for HTTP/2. fn poll_trailers(&mut self) -> Poll, Self::Error> { Ok(Async::Ready(None)) } /// A hint that the `Body` is complete, and doesn't need to be polled more. /// /// This can be useful to determine if the there is any body or trailers /// without having to poll. An empty `Body` could return `true` and hyper /// would be able to know that only the headers need to be sent. Or, it can /// also be checked after each `poll_data` call, to allow hyper to try to /// end the underlying stream with the last chunk, instead of needing to /// send an extra `DATA` frame just to mark the stream as finished. /// /// As a hint, it is used to try to optimize, and thus is OK for a default /// implementation to return `false`. fn is_end_stream(&self) -> bool { false } /// Return a length of the total bytes that will be streamed, if known. /// /// If an exact size of bytes is known, this would allow hyper to send a /// `Content-Length` header automatically, not needing to fall back to /// `Transfer-Encoding: chunked`. /// /// This does not need to be kept updated after polls, it will only be /// called once to create the headers. fn content_length(&self) -> Option { None } // This API is unstable, and is impossible to use outside of hyper. Some // form of it may become stable in a later version. // // The only thing a user *could* do is reference the method, but DON'T // DO THAT! :) #[doc(hidden)] fn __hyper_full_data(&mut self, FullDataArg) -> FullDataRet { FullDataRet(None) } } impl Payload for Box { type Data = E::Data; type Error = E::Error; fn poll_data(&mut self) -> Poll, Self::Error> { (**self).poll_data() } fn poll_trailers(&mut self) -> Poll, Self::Error> { (**self).poll_trailers() } fn is_end_stream(&self) -> bool { (**self).is_end_stream() } fn content_length(&self) -> Option { (**self).content_length() } #[doc(hidden)] fn __hyper_full_data(&mut self, arg: FullDataArg) -> FullDataRet { (**self).__hyper_full_data(arg) } } hyper-0.12.35/src/client/conn.rs010066400017500001750000000464771353675567300146520ustar0000000000000000//! Lower-level client connection API. //! //! The types in this module are to provide a lower-level API based around a //! single connection. Connecting to a host, pooling connections, and the like //! are not handled at this level. This module provides the building blocks to //! customize those things externally. //! //! If don't have need to manage connections yourself, consider using the //! higher-level [Client](super) API. use std::fmt; use std::marker::PhantomData; use std::mem; use std::sync::Arc; use bytes::Bytes; use futures::{Async, Future, Poll}; use futures::future::{self, Either, Executor}; use h2; use tokio_io::{AsyncRead, AsyncWrite}; use body::Payload; use common::Exec; use upgrade::Upgraded; use proto; use super::dispatch; use {Body, Request, Response}; type Http1Dispatcher = proto::dispatch::Dispatcher< proto::dispatch::Client, B, T, R, >; type ConnEither = Either< Http1Dispatcher, proto::h2::Client, >; /// Returns a `Handshake` future over some IO. /// /// This is a shortcut for `Builder::new().handshake(io)`. pub fn handshake(io: T) -> Handshake where T: AsyncRead + AsyncWrite + Send + 'static, { Builder::new() .handshake(io) } /// The sender side of an established connection. pub struct SendRequest { dispatch: dispatch::Sender, Response>, } /// A future that processes all HTTP state for the IO object. /// /// In most cases, this should just be spawned into an executor, so that it /// can process incoming and outgoing messages, notice hangups, and the like. #[must_use = "futures do nothing unless polled"] pub struct Connection where T: AsyncRead + AsyncWrite + Send + 'static, B: Payload + 'static, { inner: Option>, } /// A builder to configure an HTTP connection. /// /// After setting options, the builder is used to create a `Handshake` future. #[derive(Clone, Debug)] pub struct Builder { pub(super) exec: Exec, h1_writev: bool, h1_title_case_headers: bool, h1_read_buf_exact_size: Option, h1_max_buf_size: Option, http2: bool, h2_builder: h2::client::Builder, } /// A future setting up HTTP over an IO object. /// /// If successful, yields a `(SendRequest, Connection)` pair. #[must_use = "futures do nothing unless polled"] pub struct Handshake { builder: Builder, io: Option, _marker: PhantomData, } /// A future returned by `SendRequest::send_request`. /// /// Yields a `Response` if successful. #[must_use = "futures do nothing unless polled"] pub struct ResponseFuture { // for now, a Box is used to hide away the internal `B` // that can be returned if canceled inner: Box, Error=::Error> + Send>, } /// Deconstructed parts of a `Connection`. /// /// This allows taking apart a `Connection` at a later time, in order to /// reclaim the IO object, and additional related pieces. #[derive(Debug)] pub struct Parts { /// The original IO object used in the handshake. pub io: T, /// A buffer of bytes that have been read but not processed as HTTP. /// /// For instance, if the `Connection` is used for an HTTP upgrade request, /// it is possible the server sent back the first bytes of the new protocol /// along with the response upgrade. /// /// You will want to check for any existing bytes if you plan to continue /// communicating on the IO object. pub read_buf: Bytes, _inner: (), } // ========== internal client api /// A `Future` for when `SendRequest::poll_ready()` is ready. // FIXME: allow() required due to `impl Trait` leaking types to this lint #[allow(missing_debug_implementations)] #[must_use = "futures do nothing unless polled"] pub(super) struct WhenReady { tx: Option>, } // A `SendRequest` that can be cloned to send HTTP2 requests. // private for now, probably not a great idea of a type... #[must_use = "futures do nothing unless polled"] pub(super) struct Http2SendRequest { dispatch: dispatch::UnboundedSender, Response>, } // ===== impl SendRequest impl SendRequest { /// Polls to determine whether this sender can be used yet for a request. /// /// If the associated connection is closed, this returns an Error. pub fn poll_ready(&mut self) -> Poll<(), ::Error> { self.dispatch.poll_ready() } pub(super) fn when_ready(self) -> WhenReady { WhenReady { tx: Some(self), } } pub(super) fn is_ready(&self) -> bool { self.dispatch.is_ready() } pub(super) fn is_closed(&self) -> bool { self.dispatch.is_closed() } pub(super) fn into_http2(self) -> Http2SendRequest { Http2SendRequest { dispatch: self.dispatch.unbound(), } } } impl SendRequest where B: Payload + 'static, { /// Sends a `Request` on the associated connection. /// /// Returns a future that if successful, yields the `Response`. /// /// # Note /// /// There are some key differences in what automatic things the `Client` /// does for you that will not be done here: /// /// - `Client` requires absolute-form `Uri`s, since the scheme and /// authority are needed to connect. They aren't required here. /// - Since the `Client` requires absolute-form `Uri`s, it can add /// the `Host` header based on it. You must add a `Host` header yourself /// before calling this method. /// - Since absolute-form `Uri`s are not required, if received, they will /// be serialized as-is. /// /// # Example /// /// ``` /// # extern crate futures; /// # extern crate hyper; /// # extern crate http; /// # use http::header::HOST; /// # use hyper::client::conn::SendRequest; /// # use hyper::Body; /// use futures::Future; /// use hyper::Request; /// /// # fn doc(mut tx: SendRequest) { /// // build a Request /// let req = Request::builder() /// .uri("/foo/bar") /// .header(HOST, "hyper.rs") /// .body(Body::empty()) /// .unwrap(); /// /// // send it and get a future back /// let fut = tx.send_request(req) /// .map(|res| { /// // got the Response /// assert!(res.status().is_success()); /// }); /// # drop(fut); /// # } /// # fn main() {} /// ``` pub fn send_request(&mut self, req: Request) -> ResponseFuture { let inner = match self.dispatch.send(req) { Ok(rx) => { Either::A(rx.then(move |res| { match res { Ok(Ok(res)) => Ok(res), Ok(Err(err)) => Err(err), // this is definite bug if it happens, but it shouldn't happen! Err(_) => panic!("dispatch dropped without returning error"), } })) }, Err(_req) => { debug!("connection was not ready"); let err = ::Error::new_canceled().with("connection was not ready"); Either::B(future::err(err)) } }; ResponseFuture { inner: Box::new(inner), } } pub(crate) fn send_request_retryable(&mut self, req: Request) -> impl Future, Error = (::Error, Option>)> where B: Send, { match self.dispatch.try_send(req) { Ok(rx) => { Either::A(rx.then(move |res| { match res { Ok(Ok(res)) => Ok(res), Ok(Err(err)) => Err(err), // this is definite bug if it happens, but it shouldn't happen! Err(_) => panic!("dispatch dropped without returning error"), } })) }, Err(req) => { debug!("connection was not ready"); let err = ::Error::new_canceled().with("connection was not ready"); Either::B(future::err((err, Some(req)))) } } } } /* TODO(0.12.0): when we change from tokio-service to tower. impl Service for SendRequest { type Request = Request; type Response = Response; type Error = ::Error; type Future = ResponseFuture; fn call(&self, req: Self::Request) -> Self::Future { } } */ impl fmt::Debug for SendRequest { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("SendRequest") .finish() } } // ===== impl Http2SendRequest impl Http2SendRequest { pub(super) fn is_ready(&self) -> bool { self.dispatch.is_ready() } pub(super) fn is_closed(&self) -> bool { self.dispatch.is_closed() } } impl Http2SendRequest where B: Payload + 'static, { pub(super) fn send_request_retryable(&mut self, req: Request) -> impl Future, Error=(::Error, Option>)> where B: Send, { match self.dispatch.try_send(req) { Ok(rx) => { Either::A(rx.then(move |res| { match res { Ok(Ok(res)) => Ok(res), Ok(Err(err)) => Err(err), // this is definite bug if it happens, but it shouldn't happen! Err(_) => panic!("dispatch dropped without returning error"), } })) }, Err(req) => { debug!("connection was not ready"); let err = ::Error::new_canceled().with("connection was not ready"); Either::B(future::err((err, Some(req)))) } } } } impl fmt::Debug for Http2SendRequest { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Http2SendRequest") .finish() } } impl Clone for Http2SendRequest { fn clone(&self) -> Self { Http2SendRequest { dispatch: self.dispatch.clone(), } } } // ===== impl Connection impl Connection where T: AsyncRead + AsyncWrite + Send + 'static, B: Payload + 'static, { /// Return the inner IO object, and additional information. /// /// Only works for HTTP/1 connections. HTTP/2 connections will panic. pub fn into_parts(self) -> Parts { let (io, read_buf, _) = match self.inner.expect("already upgraded") { Either::A(h1) => h1.into_inner(), Either::B(_h2) => { panic!("http2 cannot into_inner"); } }; Parts { io: io, read_buf: read_buf, _inner: (), } } /// Poll the connection for completion, but without calling `shutdown` /// on the underlying IO. /// /// This is useful to allow running a connection while doing an HTTP /// upgrade. Once the upgrade is completed, the connection would be "done", /// but it is not desired to actally shutdown the IO object. Instead you /// would take it back using `into_parts`. /// /// Use [`poll_fn`](https://docs.rs/futures/0.1.25/futures/future/fn.poll_fn.html) /// and [`try_ready!`](https://docs.rs/futures/0.1.25/futures/macro.try_ready.html) /// to work with this function; or use the `without_shutdown` wrapper. pub fn poll_without_shutdown(&mut self) -> Poll<(), ::Error> { match self.inner.as_mut().expect("already upgraded") { &mut Either::A(ref mut h1) => { h1.poll_without_shutdown() }, &mut Either::B(ref mut h2) => { h2.poll().map(|x| x.map(|_| ())) } } } /// Prevent shutdown of the underlying IO object at the end of service the request, /// instead run `into_parts`. This is a convenience wrapper over `poll_without_shutdown`. pub fn without_shutdown(self) -> impl Future, Error=::Error> { let mut conn = Some(self); ::futures::future::poll_fn(move || -> ::Result<_> { try_ready!(conn.as_mut().unwrap().poll_without_shutdown()); Ok(conn.take().unwrap().into_parts().into()) }) } } impl Future for Connection where T: AsyncRead + AsyncWrite + Send + 'static, B: Payload + 'static, { type Item = (); type Error = ::Error; fn poll(&mut self) -> Poll { match try_ready!(self.inner.poll()) { Some(proto::Dispatched::Shutdown) | None => { Ok(Async::Ready(())) }, Some(proto::Dispatched::Upgrade(pending)) => { let h1 = match mem::replace(&mut self.inner, None) { Some(Either::A(h1)) => h1, _ => unreachable!("Upgrade expects h1"), }; let (io, buf, _) = h1.into_inner(); pending.fulfill(Upgraded::new(Box::new(io), buf)); Ok(Async::Ready(())) } } } } impl fmt::Debug for Connection where T: AsyncRead + AsyncWrite + fmt::Debug + Send + 'static, B: Payload + 'static, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Connection") .finish() } } // ===== impl Builder impl Builder { /// Creates a new connection builder. #[inline] pub fn new() -> Builder { let mut h2_builder = h2::client::Builder::default(); h2_builder.enable_push(false); Builder { exec: Exec::Default, h1_writev: true, h1_read_buf_exact_size: None, h1_title_case_headers: false, h1_max_buf_size: None, http2: false, h2_builder, } } /// Provide an executor to execute background HTTP2 tasks. pub fn executor(&mut self, exec: E) -> &mut Builder where E: Executor + Send>> + Send + Sync + 'static, { self.exec = Exec::Executor(Arc::new(exec)); self } pub(super) fn h1_writev(&mut self, enabled: bool) -> &mut Builder { self.h1_writev = enabled; self } pub(super) fn h1_title_case_headers(&mut self, enabled: bool) -> &mut Builder { self.h1_title_case_headers = enabled; self } pub(super) fn h1_read_buf_exact_size(&mut self, sz: Option) -> &mut Builder { self.h1_read_buf_exact_size = sz; self.h1_max_buf_size = None; self } pub(super) fn h1_max_buf_size(&mut self, max: usize) -> &mut Self { assert!( max >= proto::h1::MINIMUM_MAX_BUFFER_SIZE, "the max_buf_size cannot be smaller than the minimum that h1 specifies." ); self.h1_max_buf_size = Some(max); self.h1_read_buf_exact_size = None; self } /// Sets whether HTTP2 is required. /// /// Default is false. pub fn http2_only(&mut self, enabled: bool) -> &mut Builder { self.http2 = enabled; self } /// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`][spec] option for HTTP2 /// stream-level flow control. /// /// Default is 65,535 /// /// [spec]: https://http2.github.io/http2-spec/#SETTINGS_INITIAL_WINDOW_SIZE pub fn http2_initial_stream_window_size(&mut self, sz: impl Into>) -> &mut Self { if let Some(sz) = sz.into() { self.h2_builder.initial_window_size(sz); } self } /// Sets the max connection-level flow control for HTTP2 /// /// Default is 65,535 pub fn http2_initial_connection_window_size(&mut self, sz: impl Into>) -> &mut Self { if let Some(sz) = sz.into() { self.h2_builder.initial_connection_window_size(sz); } self } /// Constructs a connection with the configured options and IO. #[inline] pub fn handshake(&self, io: T) -> Handshake where T: AsyncRead + AsyncWrite + Send + 'static, B: Payload + 'static, { trace!("client handshake HTTP/{}", if self.http2 { 2 } else { 1 }); Handshake { builder: self.clone(), io: Some(io), _marker: PhantomData, } } } // ===== impl Handshake impl Future for Handshake where T: AsyncRead + AsyncWrite + Send + 'static, B: Payload + 'static, { type Item = (SendRequest, Connection); type Error = ::Error; fn poll(&mut self) -> Poll { let io = self.io.take().expect("polled more than once"); let (tx, rx) = dispatch::channel(); let either = if !self.builder.http2 { let mut conn = proto::Conn::new(io); if !self.builder.h1_writev { conn.set_write_strategy_flatten(); } if self.builder.h1_title_case_headers { conn.set_title_case_headers(); } if let Some(sz) = self.builder.h1_read_buf_exact_size { conn.set_read_buf_exact_size(sz); } if let Some(max) = self.builder.h1_max_buf_size { conn.set_max_buf_size(max); } let cd = proto::h1::dispatch::Client::new(rx); let dispatch = proto::h1::Dispatcher::new(cd, conn); Either::A(dispatch) } else { let h2 = proto::h2::Client::new(io, rx, &self.builder.h2_builder, self.builder.exec.clone()); Either::B(h2) }; Ok(Async::Ready(( SendRequest { dispatch: tx, }, Connection { inner: Some(either), }, ))) } } impl fmt::Debug for Handshake { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Handshake") .finish() } } // ===== impl ResponseFuture impl Future for ResponseFuture { type Item = Response; type Error = ::Error; #[inline] fn poll(&mut self) -> Poll { self.inner.poll() } } impl fmt::Debug for ResponseFuture { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("ResponseFuture") .finish() } } // ===== impl WhenReady impl Future for WhenReady { type Item = SendRequest; type Error = ::Error; fn poll(&mut self) -> Poll { let mut tx = self.tx.take().expect("polled after complete"); match tx.poll_ready()? { Async::Ready(()) => Ok(Async::Ready(tx)), Async::NotReady => { self.tx = Some(tx); Ok(Async::NotReady) } } } } // assert trait markers trait AssertSend: Send {} trait AssertSendSync: Send + Sync {} #[doc(hidden)] impl AssertSendSync for SendRequest {} #[doc(hidden)] impl AssertSend for Connection where T: AsyncRead + AsyncWrite + Send + 'static, B: Payload + 'static, {} #[doc(hidden)] impl AssertSendSync for Connection where T: AsyncRead + AsyncWrite + Send + 'static, B: Payload + 'static, B::Data: Send + Sync + 'static, {} #[doc(hidden)] impl AssertSendSync for Builder {} #[doc(hidden)] impl AssertSend for ResponseFuture {} hyper-0.12.35/src/client/connect/dns.rs010066400017500001750000000244001353675567300161100ustar0000000000000000//! The `Resolve` trait, support types, and some basic implementations. //! //! This module contains: //! //! - A [`GaiResolver`](dns::GaiResolver) that is the default resolver for the //! `HttpConnector`. //! - The [`Resolve`](dns::Resolve) trait and related types to build a custom //! resolver for use with the `HttpConnector`. use std::{fmt, io, vec}; use std::error::Error; use std::net::{ IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, }; use std::str::FromStr; use std::sync::Arc; use futures::{Async, Future, Poll}; use futures::future::{Executor, ExecuteError}; use futures::sync::oneshot; use futures_cpupool::{Builder as CpuPoolBuilder}; use tokio_threadpool; use self::sealed::GaiTask; /// Resolve a hostname to a set of IP addresses. pub trait Resolve { /// The set of IP addresses to try to connect to. type Addrs: Iterator; /// A Future of the resolved set of addresses. type Future: Future; /// Resolve a hostname. fn resolve(&self, name: Name) -> Self::Future; } /// A domain name to resolve into IP addresses. #[derive(Clone, Hash, Eq, PartialEq)] pub struct Name { host: String, } /// A resolver using blocking `getaddrinfo` calls in a threadpool. #[derive(Clone)] pub struct GaiResolver { executor: GaiExecutor, } /// An iterator of IP addresses returned from `getaddrinfo`. pub struct GaiAddrs { inner: IpAddrs, } /// A future to resole a name returned by `GaiResolver`. pub struct GaiFuture { rx: oneshot::SpawnHandle, } impl Name { pub(super) fn new(host: String) -> Name { Name { host, } } /// View the hostname as a string slice. pub fn as_str(&self) -> &str { &self.host } } impl fmt::Debug for Name { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.host, f) } } impl fmt::Display for Name { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.host, f) } } impl FromStr for Name { type Err = InvalidNameError; fn from_str(host: &str) -> Result { // Possibly add validation later Ok(Name::new(host.to_owned())) } } /// Error indicating a given string was not a valid domain name. #[derive(Debug)] pub struct InvalidNameError(()); impl fmt::Display for InvalidNameError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.description().fmt(f) } } impl Error for InvalidNameError { fn description(&self) -> &str { "Not a valid domain name" } } impl GaiResolver { /// Construct a new `GaiResolver`. /// /// Takes number of DNS worker threads. pub fn new(threads: usize) -> Self { let pool = CpuPoolBuilder::new() .name_prefix("hyper-dns") .pool_size(threads) .create(); GaiResolver::new_with_executor(pool) } /// Construct a new `GaiResolver` with a shared thread pool executor. /// /// Takes an executor to run blocking `getaddrinfo` tasks on. pub fn new_with_executor(executor: E) -> Self where E: Executor + Send + Sync, { GaiResolver { executor: GaiExecutor(Arc::new(executor)), } } } impl Resolve for GaiResolver { type Addrs = GaiAddrs; type Future = GaiFuture; fn resolve(&self, name: Name) -> Self::Future { let blocking = GaiBlocking::new(name.host); let rx = oneshot::spawn(blocking, &self.executor); GaiFuture { rx, } } } impl fmt::Debug for GaiResolver { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("GaiResolver") } } impl Future for GaiFuture { type Item = GaiAddrs; type Error = io::Error; fn poll(&mut self) -> Poll { let addrs = try_ready!(self.rx.poll()); Ok(Async::Ready(GaiAddrs { inner: addrs, })) } } impl fmt::Debug for GaiFuture { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("GaiFuture") } } impl Iterator for GaiAddrs { type Item = IpAddr; fn next(&mut self) -> Option { self.inner.next().map(|sa| sa.ip()) } } impl fmt::Debug for GaiAddrs { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("GaiAddrs") } } #[derive(Clone)] struct GaiExecutor(Arc + Send + Sync>); impl Executor> for GaiExecutor { fn execute(&self, future: oneshot::Execute) -> Result<(), ExecuteError>> { self.0.execute(GaiTask { work: future }) .map_err(|err| ExecuteError::new(err.kind(), err.into_future().work)) } } pub(super) struct GaiBlocking { host: String, } impl GaiBlocking { pub(super) fn new(host: String) -> GaiBlocking { GaiBlocking { host } } } impl Future for GaiBlocking { type Item = IpAddrs; type Error = io::Error; fn poll(&mut self) -> Poll { debug!("resolving host={:?}", self.host); (&*self.host, 0).to_socket_addrs() .map(|i| Async::Ready(IpAddrs { iter: i })) } } pub(super) struct IpAddrs { iter: vec::IntoIter, } impl IpAddrs { pub(super) fn new(addrs: Vec) -> Self { IpAddrs { iter: addrs.into_iter() } } pub(super) fn try_parse(host: &str, port: u16) -> Option { if let Ok(addr) = host.parse::() { let addr = SocketAddrV4::new(addr, port); return Some(IpAddrs { iter: vec![SocketAddr::V4(addr)].into_iter() }) } let host = { // trim_left/trim_right deprecated... // TODO: use trim_start/trim_end in Rust 1.30 #[allow(deprecated)] { host .trim_left_matches('[') .trim_right_matches(']') } }; if let Ok(addr) = host.parse::() { let addr = SocketAddrV6::new(addr, port, 0, 0); return Some(IpAddrs { iter: vec![SocketAddr::V6(addr)].into_iter() }) } None } pub(super) fn split_by_preference(self) -> (IpAddrs, IpAddrs) { let preferring_v6 = self.iter .as_slice() .first() .map(SocketAddr::is_ipv6) .unwrap_or(false); let (preferred, fallback) = self.iter .partition::, _>(|addr| addr.is_ipv6() == preferring_v6); (IpAddrs::new(preferred), IpAddrs::new(fallback)) } pub(super) fn is_empty(&self) -> bool { self.iter.as_slice().is_empty() } } impl Iterator for IpAddrs { type Item = SocketAddr; #[inline] fn next(&mut self) -> Option { self.iter.next() } } // Make this Future unnameable outside of this crate. pub(super) mod sealed { use super::*; // Blocking task to be executed on a thread pool. pub struct GaiTask { pub(super) work: oneshot::Execute } impl fmt::Debug for GaiTask { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("GaiTask") } } impl Future for GaiTask { type Item = (); type Error = (); fn poll(&mut self) -> Poll<(), ()> { self.work.poll() } } } /// A resolver using `getaddrinfo` calls via the `tokio_threadpool::blocking` API. /// /// Unlike the `GaiResolver` this will not spawn dedicated threads, but only works when running on the /// multi-threaded Tokio runtime. #[derive(Clone, Debug)] pub struct TokioThreadpoolGaiResolver(()); /// The future returned by `TokioThreadpoolGaiResolver`. #[derive(Debug)] pub struct TokioThreadpoolGaiFuture { name: Name, } impl TokioThreadpoolGaiResolver { /// Creates a new DNS resolver that will use tokio threadpool's blocking /// feature. /// /// **Requires** its futures to be run on the threadpool runtime. pub fn new() -> Self { TokioThreadpoolGaiResolver(()) } } impl Resolve for TokioThreadpoolGaiResolver { type Addrs = GaiAddrs; type Future = TokioThreadpoolGaiFuture; fn resolve(&self, name: Name) -> TokioThreadpoolGaiFuture { TokioThreadpoolGaiFuture { name } } } impl Future for TokioThreadpoolGaiFuture { type Item = GaiAddrs; type Error = io::Error; fn poll(&mut self) -> Poll { match tokio_threadpool::blocking(|| (self.name.as_str(), 0).to_socket_addrs()) { Ok(Async::Ready(Ok(iter))) => Ok(Async::Ready(GaiAddrs { inner: IpAddrs { iter } })), Ok(Async::Ready(Err(e))) => Err(e), Ok(Async::NotReady) => Ok(Async::NotReady), Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)), } } } #[cfg(test)] mod tests { use std::net::{Ipv4Addr, Ipv6Addr}; use super::*; #[test] fn test_ip_addrs_split_by_preference() { let v4_addr = (Ipv4Addr::new(127, 0, 0, 1), 80).into(); let v6_addr = (Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 80).into(); let (mut preferred, mut fallback) = IpAddrs { iter: vec![v4_addr, v6_addr].into_iter() }.split_by_preference(); assert!(preferred.next().unwrap().is_ipv4()); assert!(fallback.next().unwrap().is_ipv6()); let (mut preferred, mut fallback) = IpAddrs { iter: vec![v6_addr, v4_addr].into_iter() }.split_by_preference(); assert!(preferred.next().unwrap().is_ipv6()); assert!(fallback.next().unwrap().is_ipv4()); } #[test] fn test_name_from_str() { const DOMAIN: &str = "test.example.com"; let name = Name::from_str(DOMAIN).expect("Should be a valid domain"); assert_eq!(name.as_str(), DOMAIN); assert_eq!(name.to_string(), DOMAIN); } #[test] fn ip_addrs_try_parse_v6() { let uri = ::http::Uri::from_static("http://[::1]:8080/"); let dst = super::super::Destination { uri }; let mut addrs = IpAddrs::try_parse( dst.host(), dst.port().expect("port") ).expect("try_parse"); let expected = "[::1]:8080".parse::().expect("expected"); assert_eq!(addrs.next(), Some(expected)); } } hyper-0.12.35/src/client/connect/http.rs010066400017500001750000000643231353675567300163130ustar0000000000000000use std::borrow::Cow; use std::fmt; use std::error::Error as StdError; use std::io; use std::mem; use std::net::{IpAddr, SocketAddr}; use std::time::{Duration, Instant}; use futures::{Async, Future, Poll}; use futures::future::{Executor}; use http::uri::Scheme; use net2::TcpBuilder; use tokio_reactor::Handle; use tokio_tcp::{TcpStream, ConnectFuture}; use tokio_timer::Delay; use super::{Connect, Connected, Destination}; use super::dns::{self, GaiResolver, Resolve, TokioThreadpoolGaiResolver}; /// A connector for the `http` scheme. /// /// Performs DNS resolution in a thread pool, and then connects over TCP. /// /// # Note /// /// Sets the [`HttpInfo`](HttpInfo) value on responses, which includes /// transport information such as the remote socket address used. #[derive(Clone)] pub struct HttpConnector { enforce_http: bool, handle: Option, happy_eyeballs_timeout: Option, keep_alive_timeout: Option, local_address: Option, nodelay: bool, resolver: R, reuse_address: bool, send_buffer_size: Option, recv_buffer_size: Option, } /// Extra information about the transport when an HttpConnector is used. /// /// # Example /// /// ``` /// use hyper::Uri; /// use hyper::client::{Client, connect::HttpInfo}; /// use hyper::rt::Future; /// /// let client = Client::new(); /// /// let fut = client.get(Uri::from_static("http://example.local")) /// .inspect(|resp| { /// resp /// .extensions() /// .get::() /// .map(|info| { /// println!("remote addr = {}", info.remote_addr()); /// }); /// }); /// ``` /// /// # Note /// /// If a different connector is used besides [`HttpConnector`](HttpConnector), /// this value will not exist in the extensions. Consult that specific /// connector to see what "extra" information it might provide to responses. #[derive(Clone, Debug)] pub struct HttpInfo { remote_addr: SocketAddr, } impl HttpConnector { /// Construct a new HttpConnector. /// /// Takes number of DNS worker threads. #[inline] pub fn new(threads: usize) -> HttpConnector { HttpConnector::new_with_resolver(GaiResolver::new(threads)) } #[doc(hidden)] #[deprecated(note = "Use HttpConnector::set_reactor to set a reactor handle")] pub fn new_with_handle(threads: usize, handle: Handle) -> HttpConnector { let resolver = GaiResolver::new(threads); let mut http = HttpConnector::new_with_resolver(resolver); http.set_reactor(Some(handle)); http } /// Construct a new HttpConnector. /// /// Takes an executor to run blocking `getaddrinfo` tasks on. pub fn new_with_executor(executor: E, handle: Option) -> HttpConnector where E: Executor + Send + Sync { let resolver = GaiResolver::new_with_executor(executor); let mut http = HttpConnector::new_with_resolver(resolver); http.set_reactor(handle); http } } impl HttpConnector { /// Construct a new HttpConnector using the `TokioThreadpoolGaiResolver`. /// /// This resolver **requires** the threadpool runtime to be used. pub fn new_with_tokio_threadpool_resolver() -> Self { HttpConnector::new_with_resolver(TokioThreadpoolGaiResolver::new()) } } impl HttpConnector { /// Construct a new HttpConnector. /// /// Takes a `Resolve` to handle DNS lookups. pub fn new_with_resolver(resolver: R) -> HttpConnector { HttpConnector { enforce_http: true, handle: None, happy_eyeballs_timeout: Some(Duration::from_millis(300)), keep_alive_timeout: None, local_address: None, nodelay: false, resolver, reuse_address: false, send_buffer_size: None, recv_buffer_size: None, } } /// Option to enforce all `Uri`s have the `http` scheme. /// /// Enabled by default. #[inline] pub fn enforce_http(&mut self, is_enforced: bool) { self.enforce_http = is_enforced; } /// Set a handle to a `Reactor` to register connections to. /// /// If `None`, the implicit default reactor will be used. #[inline] pub fn set_reactor(&mut self, handle: Option) { self.handle = handle; } /// Set that all sockets have `SO_KEEPALIVE` set with the supplied duration. /// /// If `None`, the option will not be set. /// /// Default is `None`. #[inline] pub fn set_keepalive(&mut self, dur: Option) { self.keep_alive_timeout = dur; } /// Set that all sockets have `SO_NODELAY` set to the supplied value `nodelay`. /// /// Default is `false`. #[inline] pub fn set_nodelay(&mut self, nodelay: bool) { self.nodelay = nodelay; } /// Sets the value of the SO_SNDBUF option on the socket. #[inline] pub fn set_send_buffer_size(&mut self, size: Option) { self.send_buffer_size = size; } /// Sets the value of the SO_RCVBUF option on the socket. #[inline] pub fn set_recv_buffer_size(&mut self, size: Option) { self.recv_buffer_size = size; } /// Set that all sockets are bound to the configured address before connection. /// /// If `None`, the sockets will not be bound. /// /// Default is `None`. #[inline] pub fn set_local_address(&mut self, addr: Option) { self.local_address = addr; } /// Set timeout for [RFC 6555 (Happy Eyeballs)][RFC 6555] algorithm. /// /// If hostname resolves to both IPv4 and IPv6 addresses and connection /// cannot be established using preferred address family before timeout /// elapses, then connector will in parallel attempt connection using other /// address family. /// /// If `None`, parallel connection attempts are disabled. /// /// Default is 300 milliseconds. /// /// [RFC 6555]: https://tools.ietf.org/html/rfc6555 #[inline] pub fn set_happy_eyeballs_timeout(&mut self, dur: Option) { self.happy_eyeballs_timeout = dur; } /// Set that all socket have `SO_REUSEADDR` set to the supplied value `reuse_address`. /// /// Default is `false`. #[inline] pub fn set_reuse_address(&mut self, reuse_address: bool) -> &mut Self { self.reuse_address = reuse_address; self } } // R: Debug required for now to allow adding it to debug output later... impl fmt::Debug for HttpConnector { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("HttpConnector") .finish() } } impl Connect for HttpConnector where R: Resolve + Clone + Send + Sync, R::Future: Send, { type Transport = TcpStream; type Error = io::Error; type Future = HttpConnecting; fn connect(&self, dst: Destination) -> Self::Future { trace!( "Http::connect; scheme={}, host={}, port={:?}", dst.scheme(), dst.host(), dst.port(), ); if self.enforce_http { if dst.uri.scheme_part() != Some(&Scheme::HTTP) { return invalid_url(InvalidUrl::NotHttp, &self.handle); } } else if dst.uri.scheme_part().is_none() { return invalid_url(InvalidUrl::MissingScheme, &self.handle); } let host = match dst.uri.host() { Some(s) => s, None => return invalid_url(InvalidUrl::MissingAuthority, &self.handle), }; let port = match dst.uri.port_part() { Some(port) => port.as_u16(), None => if dst.uri.scheme_part() == Some(&Scheme::HTTPS) { 443 } else { 80 }, }; HttpConnecting { state: State::Lazy(self.resolver.clone(), host.into(), self.local_address), handle: self.handle.clone(), happy_eyeballs_timeout: self.happy_eyeballs_timeout, keep_alive_timeout: self.keep_alive_timeout, nodelay: self.nodelay, port, reuse_address: self.reuse_address, send_buffer_size: self.send_buffer_size, recv_buffer_size: self.recv_buffer_size, } } } impl HttpInfo { /// Get the remote address of the transport used. pub fn remote_addr(&self) -> SocketAddr { self.remote_addr } } #[inline] fn invalid_url(err: InvalidUrl, handle: &Option) -> HttpConnecting { HttpConnecting { state: State::Error(Some(io::Error::new(io::ErrorKind::InvalidInput, err))), handle: handle.clone(), keep_alive_timeout: None, nodelay: false, port: 0, happy_eyeballs_timeout: None, reuse_address: false, send_buffer_size: None, recv_buffer_size: None, } } #[derive(Debug, Clone, Copy)] enum InvalidUrl { MissingScheme, NotHttp, MissingAuthority, } impl fmt::Display for InvalidUrl { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.description()) } } impl StdError for InvalidUrl { fn description(&self) -> &str { match *self { InvalidUrl::MissingScheme => "invalid URL, missing scheme", InvalidUrl::NotHttp => "invalid URL, scheme must be http", InvalidUrl::MissingAuthority => "invalid URL, missing domain", } } } /// A Future representing work to connect to a URL. #[must_use = "futures do nothing unless polled"] pub struct HttpConnecting { state: State, handle: Option, happy_eyeballs_timeout: Option, keep_alive_timeout: Option, nodelay: bool, port: u16, reuse_address: bool, send_buffer_size: Option, recv_buffer_size: Option, } enum State { Lazy(R, String, Option), Resolving(R::Future, Option), Connecting(ConnectingTcp), Error(Option), } impl Future for HttpConnecting { type Item = (TcpStream, Connected); type Error = io::Error; fn poll(&mut self) -> Poll { loop { let state; match self.state { State::Lazy(ref resolver, ref mut host, local_addr) => { // If the host is already an IP addr (v4 or v6), // skip resolving the dns and start connecting right away. if let Some(addrs) = dns::IpAddrs::try_parse(host, self.port) { state = State::Connecting(ConnectingTcp::new( local_addr, addrs, self.happy_eyeballs_timeout, self.reuse_address)); } else { let name = dns::Name::new(mem::replace(host, String::new())); state = State::Resolving(resolver.resolve(name), local_addr); } }, State::Resolving(ref mut future, local_addr) => { match future.poll()? { Async::NotReady => return Ok(Async::NotReady), Async::Ready(addrs) => { let port = self.port; let addrs = addrs .map(|addr| SocketAddr::new(addr, port)) .collect(); let addrs = dns::IpAddrs::new(addrs); state = State::Connecting(ConnectingTcp::new( local_addr, addrs, self.happy_eyeballs_timeout, self.reuse_address)); } }; }, State::Connecting(ref mut c) => { let sock = try_ready!(c.poll(&self.handle)); if let Some(dur) = self.keep_alive_timeout { sock.set_keepalive(Some(dur))?; } if let Some(size) = self.send_buffer_size { sock.set_send_buffer_size(size)?; } if let Some(size) = self.recv_buffer_size { sock.set_recv_buffer_size(size)?; } sock.set_nodelay(self.nodelay)?; let extra = HttpInfo { remote_addr: sock.peer_addr()?, }; let connected = Connected::new() .extra(extra); return Ok(Async::Ready((sock, connected))); }, State::Error(ref mut e) => return Err(e.take().expect("polled more than once")), } self.state = state; } } } impl fmt::Debug for HttpConnecting { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("HttpConnecting") } } struct ConnectingTcp { local_addr: Option, preferred: ConnectingTcpRemote, fallback: Option, reuse_address: bool, } impl ConnectingTcp { fn new( local_addr: Option, remote_addrs: dns::IpAddrs, fallback_timeout: Option, reuse_address: bool, ) -> ConnectingTcp { if let Some(fallback_timeout) = fallback_timeout { let (preferred_addrs, fallback_addrs) = remote_addrs.split_by_preference(); if fallback_addrs.is_empty() { return ConnectingTcp { local_addr, preferred: ConnectingTcpRemote::new(preferred_addrs), fallback: None, reuse_address, }; } ConnectingTcp { local_addr, preferred: ConnectingTcpRemote::new(preferred_addrs), fallback: Some(ConnectingTcpFallback { delay: Delay::new(Instant::now() + fallback_timeout), remote: ConnectingTcpRemote::new(fallback_addrs), }), reuse_address, } } else { ConnectingTcp { local_addr, preferred: ConnectingTcpRemote::new(remote_addrs), fallback: None, reuse_address, } } } } struct ConnectingTcpFallback { delay: Delay, remote: ConnectingTcpRemote, } struct ConnectingTcpRemote { addrs: dns::IpAddrs, current: Option, } impl ConnectingTcpRemote { fn new(addrs: dns::IpAddrs) -> Self { Self { addrs, current: None, } } } impl ConnectingTcpRemote { // not a Future, since passing a &Handle to poll fn poll( &mut self, local_addr: &Option, handle: &Option, reuse_address: bool, ) -> Poll { let mut err = None; loop { if let Some(ref mut current) = self.current { match current.poll() { Ok(Async::Ready(tcp)) => { debug!("connected to {:?}", tcp.peer_addr().ok()); return Ok(Async::Ready(tcp)); }, Ok(Async::NotReady) => return Ok(Async::NotReady), Err(e) => { trace!("connect error {:?}", e); err = Some(e); if let Some(addr) = self.addrs.next() { debug!("connecting to {}", addr); *current = connect(&addr, local_addr, handle, reuse_address)?; continue; } } } } else if let Some(addr) = self.addrs.next() { debug!("connecting to {}", addr); self.current = Some(connect(&addr, local_addr, handle, reuse_address)?); continue; } return Err(err.take().expect("missing connect error")); } } } fn connect(addr: &SocketAddr, local_addr: &Option, handle: &Option, reuse_address: bool) -> io::Result { let builder = match addr { &SocketAddr::V4(_) => TcpBuilder::new_v4()?, &SocketAddr::V6(_) => TcpBuilder::new_v6()?, }; if reuse_address { builder.reuse_address(reuse_address)?; } if let Some(ref local_addr) = *local_addr { // Caller has requested this socket be bound before calling connect builder.bind(SocketAddr::new(local_addr.clone(), 0))?; } else if cfg!(windows) { // Windows requires a socket be bound before calling connect let any: SocketAddr = match addr { &SocketAddr::V4(_) => { ([0, 0, 0, 0], 0).into() }, &SocketAddr::V6(_) => { ([0, 0, 0, 0, 0, 0, 0, 0], 0).into() } }; builder.bind(any)?; } let handle = match *handle { Some(ref handle) => Cow::Borrowed(handle), None => Cow::Owned(Handle::default()), }; Ok(TcpStream::connect_std(builder.to_tcp_stream()?, addr, &handle)) } impl ConnectingTcp { // not a Future, since passing a &Handle to poll fn poll(&mut self, handle: &Option) -> Poll { match self.fallback.take() { None => self.preferred.poll(&self.local_addr, handle, self.reuse_address), Some(mut fallback) => match self.preferred.poll(&self.local_addr, handle, self.reuse_address) { Ok(Async::Ready(stream)) => { // Preferred successful - drop fallback. Ok(Async::Ready(stream)) } Ok(Async::NotReady) => match fallback.delay.poll() { Ok(Async::Ready(_)) => match fallback.remote.poll(&self.local_addr, handle, self.reuse_address) { Ok(Async::Ready(stream)) => { // Fallback successful - drop current preferred, // but keep fallback as new preferred. self.preferred = fallback.remote; Ok(Async::Ready(stream)) } Ok(Async::NotReady) => { // Neither preferred nor fallback are ready. self.fallback = Some(fallback); Ok(Async::NotReady) } Err(_) => { // Fallback failed - resume with preferred only. Ok(Async::NotReady) } }, Ok(Async::NotReady) => { // Too early to attempt fallback. self.fallback = Some(fallback); Ok(Async::NotReady) } Err(_) => { // Fallback delay failed - resume with preferred only. Ok(Async::NotReady) } } Err(_) => { // Preferred failed - use fallback as new preferred. self.preferred = fallback.remote; self.preferred.poll(&self.local_addr, handle, self.reuse_address) } } } } } #[cfg(test)] mod tests { use std::io; use futures::Future; use super::{Connect, Destination, HttpConnector}; #[test] fn test_errors_missing_authority() { let uri = "/foo/bar?baz".parse().unwrap(); let dst = Destination { uri, }; let connector = HttpConnector::new(1); assert_eq!(connector.connect(dst).wait().unwrap_err().kind(), io::ErrorKind::InvalidInput); } #[test] fn test_errors_enforce_http() { let uri = "https://example.domain/foo/bar?baz".parse().unwrap(); let dst = Destination { uri, }; let connector = HttpConnector::new(1); assert_eq!(connector.connect(dst).wait().unwrap_err().kind(), io::ErrorKind::InvalidInput); } #[test] fn test_errors_missing_scheme() { let uri = "example.domain".parse().unwrap(); let dst = Destination { uri, }; let connector = HttpConnector::new(1); assert_eq!(connector.connect(dst).wait().unwrap_err().kind(), io::ErrorKind::InvalidInput); } #[test] #[cfg_attr(not(feature = "__internal_happy_eyeballs_tests"), ignore)] fn client_happy_eyeballs() { extern crate pretty_env_logger; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, TcpListener}; use std::time::{Duration, Instant}; use futures::{Async, Poll}; use tokio::runtime::current_thread::Runtime; use tokio_reactor::Handle; use super::dns; use super::ConnectingTcp; let _ = pretty_env_logger::try_init(); let server4 = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = server4.local_addr().unwrap(); let _server6 = TcpListener::bind(&format!("[::1]:{}", addr.port())).unwrap(); let mut rt = Runtime::new().unwrap(); let local_timeout = Duration::default(); let unreachable_v4_timeout = measure_connect(unreachable_ipv4_addr()).1; let unreachable_v6_timeout = measure_connect(unreachable_ipv6_addr()).1; let fallback_timeout = ::std::cmp::max(unreachable_v4_timeout, unreachable_v6_timeout) + Duration::from_millis(250); let scenarios = &[ // Fast primary, without fallback. (&[local_ipv4_addr()][..], 4, local_timeout, false), (&[local_ipv6_addr()][..], 6, local_timeout, false), // Fast primary, with (unused) fallback. (&[local_ipv4_addr(), local_ipv6_addr()][..], 4, local_timeout, false), (&[local_ipv6_addr(), local_ipv4_addr()][..], 6, local_timeout, false), // Unreachable + fast primary, without fallback. (&[unreachable_ipv4_addr(), local_ipv4_addr()][..], 4, unreachable_v4_timeout, false), (&[unreachable_ipv6_addr(), local_ipv6_addr()][..], 6, unreachable_v6_timeout, false), // Unreachable + fast primary, with (unused) fallback. (&[unreachable_ipv4_addr(), local_ipv4_addr(), local_ipv6_addr()][..], 4, unreachable_v4_timeout, false), (&[unreachable_ipv6_addr(), local_ipv6_addr(), local_ipv4_addr()][..], 6, unreachable_v6_timeout, true), // Slow primary, with (used) fallback. (&[slow_ipv4_addr(), local_ipv4_addr(), local_ipv6_addr()][..], 6, fallback_timeout, false), (&[slow_ipv6_addr(), local_ipv6_addr(), local_ipv4_addr()][..], 4, fallback_timeout, true), // Slow primary, with (used) unreachable + fast fallback. (&[slow_ipv4_addr(), unreachable_ipv6_addr(), local_ipv6_addr()][..], 6, fallback_timeout + unreachable_v6_timeout, false), (&[slow_ipv6_addr(), unreachable_ipv4_addr(), local_ipv4_addr()][..], 4, fallback_timeout + unreachable_v4_timeout, true), ]; // Scenarios for IPv6 -> IPv4 fallback require that host can access IPv6 network. // Otherwise, connection to "slow" IPv6 address will error-out immediatelly. let ipv6_accessible = measure_connect(slow_ipv6_addr()).0; for &(hosts, family, timeout, needs_ipv6_access) in scenarios { if needs_ipv6_access && !ipv6_accessible { continue; } let addrs = hosts.iter().map(|host| (host.clone(), addr.port()).into()).collect(); let connecting_tcp = ConnectingTcp::new(None, dns::IpAddrs::new(addrs), Some(fallback_timeout), false); let fut = ConnectingTcpFuture(connecting_tcp); let start = Instant::now(); let res = rt.block_on(fut).unwrap(); let duration = start.elapsed(); // Allow actual duration to be +/- 150ms off. let min_duration = if timeout >= Duration::from_millis(150) { timeout - Duration::from_millis(150) } else { Duration::default() }; let max_duration = timeout + Duration::from_millis(150); assert_eq!(res, family); assert!(duration >= min_duration); assert!(duration <= max_duration); } struct ConnectingTcpFuture(ConnectingTcp); impl Future for ConnectingTcpFuture { type Item = u8; type Error = ::std::io::Error; fn poll(&mut self) -> Poll { match self.0.poll(&Some(Handle::default())) { Ok(Async::Ready(stream)) => Ok(Async::Ready( if stream.peer_addr().unwrap().is_ipv4() { 4 } else { 6 } )), Ok(Async::NotReady) => Ok(Async::NotReady), Err(err) => Err(err), } } } fn local_ipv4_addr() -> IpAddr { Ipv4Addr::new(127, 0, 0, 1).into() } fn local_ipv6_addr() -> IpAddr { Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).into() } fn unreachable_ipv4_addr() -> IpAddr { Ipv4Addr::new(127, 0, 0, 2).into() } fn unreachable_ipv6_addr() -> IpAddr { Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 2).into() } fn slow_ipv4_addr() -> IpAddr { // RFC 6890 reserved IPv4 address. Ipv4Addr::new(198, 18, 0, 25).into() } fn slow_ipv6_addr() -> IpAddr { // RFC 6890 reserved IPv6 address. Ipv6Addr::new(2001, 2, 0, 0, 0, 0, 0, 254).into() } fn measure_connect(addr: IpAddr) -> (bool, Duration) { let start = Instant::now(); let result = ::std::net::TcpStream::connect_timeout( &(addr, 80).into(), Duration::from_secs(1)); let reachable = result.is_ok() || result.unwrap_err().kind() == io::ErrorKind::TimedOut; let duration = start.elapsed(); (reachable, duration) } } } hyper-0.12.35/src/client/connect/mod.rs010066400017500001750000000454741353675567300161210ustar0000000000000000//! The `Connect` trait, and supporting types. //! //! This module contains: //! //! - A default [`HttpConnector`](HttpConnector) that does DNS resolution and //! establishes connections over TCP. //! - The [`Connect`](Connect) trait and related types to build custom connectors. use std::error::Error as StdError; use std::{fmt, mem}; #[cfg(try_from)] use std::convert::TryFrom; use bytes::{BufMut, Bytes, BytesMut}; use futures::Future; use http::{uri, Response, Uri}; use tokio_io::{AsyncRead, AsyncWrite}; #[cfg(feature = "runtime")] pub mod dns; #[cfg(feature = "runtime")] mod http; #[cfg(feature = "runtime")] pub use self::http::{HttpConnector, HttpInfo}; /// Connect to a destination, returning an IO transport. /// /// A connector receives a [`Destination`](Destination) describing how a /// connection should be estabilished, and returns a `Future` of the /// ready connection. pub trait Connect: Send + Sync { /// The connected IO Stream. type Transport: AsyncRead + AsyncWrite + Send + 'static; /// An error occured when trying to connect. type Error: Into>; /// A Future that will resolve to the connected Transport. type Future: Future + Send; /// Connect to a destination. fn connect(&self, dst: Destination) -> Self::Future; } /// A set of properties to describe where and how to try to connect. /// /// This type is passed an argument for the [`Connect`](Connect) trait. #[derive(Clone, Debug)] pub struct Destination { pub(super) uri: Uri, } /// Extra information about the connected transport. /// /// This can be used to inform recipients about things like if ALPN /// was used, or if connected to an HTTP proxy. #[derive(Debug)] pub struct Connected { pub(super) alpn: Alpn, pub(super) is_proxied: bool, pub(super) extra: Option, } pub(super) struct Extra(Box); #[derive(Clone, Copy, Debug, PartialEq)] pub(super) enum Alpn { H2, None, } impl Destination { /// Try to convert a `Uri` into a `Destination` /// /// # Error /// /// Returns an error if the uri contains no authority or /// no scheme. pub fn try_from_uri(uri: Uri) -> ::Result { uri.authority_part().ok_or(::error::Parse::Uri)?; uri.scheme_part().ok_or(::error::Parse::Uri)?; Ok(Destination { uri }) } /// Get the protocol scheme. #[inline] pub fn scheme(&self) -> &str { self.uri .scheme_str() .unwrap_or("") } /// Get the hostname. #[inline] pub fn host(&self) -> &str { self.uri .host() .unwrap_or("") } /// Get the port, if specified. #[inline] pub fn port(&self) -> Option { self.uri.port_u16() } /// Update the scheme of this destination. /// /// # Example /// /// ```rust /// # use hyper::client::connect::Destination; /// # fn with_dst(mut dst: Destination) { /// // let mut dst = some_destination... /// // Change from "http://"... /// assert_eq!(dst.scheme(), "http"); /// /// // to "ws://"... /// dst.set_scheme("ws"); /// assert_eq!(dst.scheme(), "ws"); /// # } /// ``` /// /// # Error /// /// Returns an error if the string is not a valid scheme. pub fn set_scheme(&mut self, scheme: &str) -> ::Result<()> { let scheme = scheme.parse().map_err(::error::Parse::from)?; self.update_uri(move |parts| { parts.scheme = Some(scheme); }) } /// Update the host of this destination. /// /// # Example /// /// ```rust /// # use hyper::client::connect::Destination; /// # fn with_dst(mut dst: Destination) { /// // let mut dst = some_destination... /// // Change from "hyper.rs"... /// assert_eq!(dst.host(), "hyper.rs"); /// /// // to "some.proxy"... /// dst.set_host("some.proxy"); /// assert_eq!(dst.host(), "some.proxy"); /// # } /// ``` /// /// # Error /// /// Returns an error if the string is not a valid hostname. pub fn set_host(&mut self, host: &str) -> ::Result<()> { // Prevent any userinfo setting, it's bad! if host.contains('@') { return Err(::error::Parse::Uri.into()); } let auth = if let Some(port) = self.port() { let bytes = Bytes::from(format!("{}:{}", host, port)); uri::Authority::from_shared(bytes) .map_err(::error::Parse::from)? } else { let auth = host.parse::().map_err(::error::Parse::from)?; if auth.port_part().is_some() { // std::uri::Authority::Uri return Err(::error::Parse::Uri.into()); } auth }; self.update_uri(move |parts| { parts.authority = Some(auth); }) } /// Update the port of this destination. /// /// # Example /// /// ```rust /// # use hyper::client::connect::Destination; /// # fn with_dst(mut dst: Destination) { /// // let mut dst = some_destination... /// // Change from "None"... /// assert_eq!(dst.port(), None); /// /// // to "4321"... /// dst.set_port(4321); /// assert_eq!(dst.port(), Some(4321)); /// /// // Or remove the port... /// dst.set_port(None); /// assert_eq!(dst.port(), None); /// # } /// ``` pub fn set_port

(&mut self, port: P) where P: Into>, { self.set_port_opt(port.into()); } fn set_port_opt(&mut self, port: Option) { use std::fmt::Write; let auth = if let Some(port) = port { let host = self.host(); // Need space to copy the hostname, plus ':', // plus max 5 port digits... let cap = host.len() + 1 + 5; let mut buf = BytesMut::with_capacity(cap); buf.put_slice(host.as_bytes()); buf.put_u8(b':'); write!(buf, "{}", port) .expect("should have space for 5 digits"); uri::Authority::from_shared(buf.freeze()) .expect("valid host + :port should be valid authority") } else { self.host().parse() .expect("valid host without port should be valid authority") }; self.update_uri(move |parts| { parts.authority = Some(auth); }) .expect("valid uri should be valid with port"); } fn update_uri(&mut self, f: F) -> ::Result<()> where F: FnOnce(&mut uri::Parts) { // Need to store a default Uri while we modify the current one... let old_uri = mem::replace(&mut self.uri, Uri::default()); // However, mutate a clone, so we can revert if there's an error... let mut parts: uri::Parts = old_uri.clone().into(); f(&mut parts); match Uri::from_parts(parts) { Ok(uri) => { self.uri = uri; Ok(()) }, Err(err) => { self.uri = old_uri; Err(::error::Parse::from(err).into()) }, } } /* /// Returns whether this connection must negotiate HTTP/2 via ALPN. pub fn must_h2(&self) -> bool { match self.alpn { Alpn::Http1 => false, Alpn::H2 => true, } } */ } #[cfg(try_from)] impl TryFrom for Destination { type Error = ::error::Error; fn try_from(uri: Uri) -> Result { Destination::try_from_uri(uri) } } impl Connected { /// Create new `Connected` type with empty metadata. pub fn new() -> Connected { Connected { alpn: Alpn::None, is_proxied: false, extra: None, } } /// Set whether the connected transport is to an HTTP proxy. /// /// This setting will affect if HTTP/1 requests written on the transport /// will have the request-target in absolute-form or origin-form: /// /// - When `proxy(false)`: /// /// ```http /// GET /guide HTTP/1.1 /// ``` /// /// - When `proxy(true)`: /// /// ```http /// GET http://hyper.rs/guide HTTP/1.1 /// ``` /// /// Default is `false`. pub fn proxy(mut self, is_proxied: bool) -> Connected { self.is_proxied = is_proxied; self } /// Set extra connection information to be set in the extensions of every `Response`. pub fn extra(mut self, extra: T) -> Connected { if let Some(prev) = self.extra { self.extra = Some(Extra(Box::new(ExtraChain(prev.0, extra)))); } else { self.extra = Some(Extra(Box::new(ExtraEnvelope(extra)))); } self } /// Set that the connected transport negotiated HTTP/2 as it's /// next protocol. pub fn negotiated_h2(mut self) -> Connected { self.alpn = Alpn::H2; self } // Don't public expose that `Connected` is `Clone`, unsure if we want to // keep that contract... pub(super) fn clone(&self) -> Connected { Connected { alpn: self.alpn.clone(), is_proxied: self.is_proxied, extra: self.extra.clone(), } } } // ===== impl Extra ===== impl Extra { pub(super) fn set(&self, res: &mut Response<::Body>) { self.0.set(res); } } impl Clone for Extra { fn clone(&self) -> Extra { Extra(self.0.clone_box()) } } impl fmt::Debug for Extra { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Extra") .finish() } } trait ExtraInner: Send + Sync { fn clone_box(&self) -> Box; fn set(&self, res: &mut Response<::Body>); } // This indirection allows the `Connected` to have a type-erased "extra" value, // while that type still knows its inner extra type. This allows the correct // TypeId to be used when inserting into `res.extensions_mut()`. #[derive(Clone)] struct ExtraEnvelope(T); impl ExtraInner for ExtraEnvelope where T: Clone + Send + Sync + 'static { fn clone_box(&self) -> Box { Box::new(self.clone()) } fn set(&self, res: &mut Response<::Body>) { res.extensions_mut().insert(self.0.clone()); } } struct ExtraChain(Box, T); impl Clone for ExtraChain { fn clone(&self) -> Self { ExtraChain(self.0.clone_box(), self.1.clone()) } } impl ExtraInner for ExtraChain where T: Clone + Send + Sync + 'static { fn clone_box(&self) -> Box { Box::new(self.clone()) } fn set(&self, res: &mut Response<::Body>) { self.0.set(res); res.extensions_mut().insert(self.1.clone()); } } #[cfg(test)] mod tests { use super::{Connected, Destination, TryFrom}; #[test] fn test_destination_set_scheme() { let mut dst = Destination { uri: "http://hyper.rs".parse().expect("initial parse"), }; assert_eq!(dst.scheme(), "http"); assert_eq!(dst.host(), "hyper.rs"); dst.set_scheme("https").expect("set https"); assert_eq!(dst.scheme(), "https"); assert_eq!(dst.host(), "hyper.rs"); dst.set_scheme("").unwrap_err(); assert_eq!(dst.scheme(), "https", "error doesn't modify dst"); assert_eq!(dst.host(), "hyper.rs", "error doesn't modify dst"); } #[test] fn test_destination_set_host() { let mut dst = Destination { uri: "http://hyper.rs".parse().expect("initial parse"), }; assert_eq!(dst.scheme(), "http"); assert_eq!(dst.host(), "hyper.rs"); assert_eq!(dst.port(), None); dst.set_host("seanmonstar.com").expect("set https"); assert_eq!(dst.scheme(), "http"); assert_eq!(dst.host(), "seanmonstar.com"); assert_eq!(dst.port(), None); dst.set_host("/im-not a host! >:)").unwrap_err(); assert_eq!(dst.scheme(), "http", "error doesn't modify dst"); assert_eq!(dst.host(), "seanmonstar.com", "error doesn't modify dst"); assert_eq!(dst.port(), None, "error doesn't modify dst"); // Check port isn't snuck into `set_host`. dst.set_host("seanmonstar.com:3030").expect_err("set_host sneaky port"); assert_eq!(dst.scheme(), "http", "error doesn't modify dst"); assert_eq!(dst.host(), "seanmonstar.com", "error doesn't modify dst"); assert_eq!(dst.port(), None, "error doesn't modify dst"); // Check userinfo isn't snuck into `set_host`. dst.set_host("sean@nope").expect_err("set_host sneaky userinfo"); assert_eq!(dst.scheme(), "http", "error doesn't modify dst"); assert_eq!(dst.host(), "seanmonstar.com", "error doesn't modify dst"); assert_eq!(dst.port(), None, "error doesn't modify dst"); // Allow IPv6 hosts dst.set_host("[::1]").expect("set_host with IPv6"); assert_eq!(dst.host(), "[::1]"); assert_eq!(dst.port(), None, "IPv6 didn't affect port"); // However, IPv6 with a port is rejected. dst.set_host("[::2]:1337").expect_err("set_host with IPv6 and sneaky port"); assert_eq!(dst.host(), "[::1]"); assert_eq!(dst.port(), None); // ----------------- // Also test that an exist port is set correctly. let mut dst = Destination { uri: "http://hyper.rs:8080".parse().expect("initial parse 2"), }; assert_eq!(dst.scheme(), "http"); assert_eq!(dst.host(), "hyper.rs"); assert_eq!(dst.port(), Some(8080)); dst.set_host("seanmonstar.com").expect("set host"); assert_eq!(dst.scheme(), "http"); assert_eq!(dst.host(), "seanmonstar.com"); assert_eq!(dst.port(), Some(8080)); dst.set_host("/im-not a host! >:)").unwrap_err(); assert_eq!(dst.scheme(), "http", "error doesn't modify dst"); assert_eq!(dst.host(), "seanmonstar.com", "error doesn't modify dst"); assert_eq!(dst.port(), Some(8080), "error doesn't modify dst"); // Check port isn't snuck into `set_host`. dst.set_host("seanmonstar.com:3030").expect_err("set_host sneaky port"); assert_eq!(dst.scheme(), "http", "error doesn't modify dst"); assert_eq!(dst.host(), "seanmonstar.com", "error doesn't modify dst"); assert_eq!(dst.port(), Some(8080), "error doesn't modify dst"); // Check userinfo isn't snuck into `set_host`. dst.set_host("sean@nope").expect_err("set_host sneaky userinfo"); assert_eq!(dst.scheme(), "http", "error doesn't modify dst"); assert_eq!(dst.host(), "seanmonstar.com", "error doesn't modify dst"); assert_eq!(dst.port(), Some(8080), "error doesn't modify dst"); // Allow IPv6 hosts dst.set_host("[::1]").expect("set_host with IPv6"); assert_eq!(dst.host(), "[::1]"); assert_eq!(dst.port(), Some(8080), "IPv6 didn't affect port"); // However, IPv6 with a port is rejected. dst.set_host("[::2]:1337").expect_err("set_host with IPv6 and sneaky port"); assert_eq!(dst.host(), "[::1]"); assert_eq!(dst.port(), Some(8080)); } #[test] fn test_destination_set_port() { let mut dst = Destination { uri: "http://hyper.rs".parse().expect("initial parse"), }; assert_eq!(dst.scheme(), "http"); assert_eq!(dst.host(), "hyper.rs"); assert_eq!(dst.port(), None); dst.set_port(None); assert_eq!(dst.scheme(), "http"); assert_eq!(dst.host(), "hyper.rs"); assert_eq!(dst.port(), None); dst.set_port(8080); assert_eq!(dst.scheme(), "http"); assert_eq!(dst.host(), "hyper.rs"); assert_eq!(dst.port(), Some(8080)); // Also test that an exist port is set correctly. let mut dst = Destination { uri: "http://hyper.rs:8080".parse().expect("initial parse 2"), }; assert_eq!(dst.scheme(), "http"); assert_eq!(dst.host(), "hyper.rs"); assert_eq!(dst.port(), Some(8080)); dst.set_port(3030); assert_eq!(dst.scheme(), "http"); assert_eq!(dst.host(), "hyper.rs"); assert_eq!(dst.port(), Some(3030)); dst.set_port(None); assert_eq!(dst.scheme(), "http"); assert_eq!(dst.host(), "hyper.rs"); assert_eq!(dst.port(), None); } #[cfg(try_from)] #[test] fn test_try_from_destination() { let uri: http::Uri = "http://hyper.rs".parse().expect("initial parse"); let result = Destination::try_from(uri); assert_eq!(result.is_ok(), true); } #[cfg(try_from)] #[test] fn test_try_from_no_scheme() { let uri: http::Uri = "hyper.rs".parse().expect("initial parse error"); let result = Destination::try_from(uri); assert_eq!(result.is_err(), true); } #[derive(Clone, Debug, PartialEq)] struct Ex1(usize); #[derive(Clone, Debug, PartialEq)] struct Ex2(&'static str); #[derive(Clone, Debug, PartialEq)] struct Ex3(&'static str); #[test] fn test_connected_extra() { let c1 = Connected::new() .extra(Ex1(41)); let mut res1 = ::Response::new(::Body::empty()); assert_eq!(res1.extensions().get::(), None); c1 .extra .as_ref() .expect("c1 extra") .set(&mut res1); assert_eq!(res1.extensions().get::(), Some(&Ex1(41))); } #[test] fn test_connected_extra_chain() { // If a user composes connectors and at each stage, there's "extra" // info to attach, it shouldn't override the previous extras. let c1 = Connected::new() .extra(Ex1(45)) .extra(Ex2("zoom")) .extra(Ex3("pew pew")); let mut res1 = ::Response::new(::Body::empty()); assert_eq!(res1.extensions().get::(), None); assert_eq!(res1.extensions().get::(), None); assert_eq!(res1.extensions().get::(), None); c1 .extra .as_ref() .expect("c1 extra") .set(&mut res1); assert_eq!(res1.extensions().get::(), Some(&Ex1(45))); assert_eq!(res1.extensions().get::(), Some(&Ex2("zoom"))); assert_eq!(res1.extensions().get::(), Some(&Ex3("pew pew"))); // Just like extensions, inserting the same type overrides previous type. let c2 = Connected::new() .extra(Ex1(33)) .extra(Ex2("hiccup")) .extra(Ex1(99)); let mut res2 = ::Response::new(::Body::empty()); c2 .extra .as_ref() .expect("c2 extra") .set(&mut res2); assert_eq!(res2.extensions().get::(), Some(&Ex1(99))); assert_eq!(res2.extensions().get::(), Some(&Ex2("hiccup"))); } } hyper-0.12.35/src/client/dispatch.rs010066400017500001750000000246541353675567300155050ustar0000000000000000use futures::{future, Async, Future, Poll, Stream}; use futures::sync::{mpsc, oneshot}; use want; use common::Never; pub type RetryPromise = oneshot::Receiver)>>; pub type Promise = oneshot::Receiver>; pub fn channel() -> (Sender, Receiver) { let (tx, rx) = mpsc::unbounded(); let (giver, taker) = want::new(); let tx = Sender { buffered_once: false, giver: giver, inner: tx, }; let rx = Receiver { inner: rx, taker: taker, }; (tx, rx) } /// A bounded sender of requests and callbacks for when responses are ready. /// /// While the inner sender is unbounded, the Giver is used to determine /// if the Receiver is ready for another request. pub struct Sender { /// One message is always allowed, even if the Receiver hasn't asked /// for it yet. This boolean keeps track of whether we've sent one /// without notice. buffered_once: bool, /// The Giver helps watch that the the Receiver side has been polled /// when the queue is empty. This helps us know when a request and /// response have been fully processed, and a connection is ready /// for more. giver: want::Giver, /// Actually bounded by the Giver, plus `buffered_once`. inner: mpsc::UnboundedSender>, } /// An unbounded version. /// /// Cannot poll the Giver, but can still use it to determine if the Receiver /// has been dropped. However, this version can be cloned. pub struct UnboundedSender { /// Only used for `is_closed`, since mpsc::UnboundedSender cannot be checked. giver: want::SharedGiver, inner: mpsc::UnboundedSender>, } impl Sender { pub fn poll_ready(&mut self) -> Poll<(), ::Error> { self.giver.poll_want() .map_err(|_| ::Error::new_closed()) } pub fn is_ready(&self) -> bool { self.giver.is_wanting() } pub fn is_closed(&self) -> bool { self.giver.is_canceled() } fn can_send(&mut self) -> bool { if self.giver.give() || !self.buffered_once { // If the receiver is ready *now*, then of course we can send. // // If the receiver isn't ready yet, but we don't have anything // in the channel yet, then allow one message. self.buffered_once = true; true } else { false } } pub fn try_send(&mut self, val: T) -> Result, T> { if !self.can_send() { return Err(val); } let (tx, rx) = oneshot::channel(); self.inner.unbounded_send(Envelope(Some((val, Callback::Retry(tx))))) .map(move |_| rx) .map_err(|e| e.into_inner().0.take().expect("envelope not dropped").0) } pub fn send(&mut self, val: T) -> Result, T> { if !self.can_send() { return Err(val); } let (tx, rx) = oneshot::channel(); self.inner.unbounded_send(Envelope(Some((val, Callback::NoRetry(tx))))) .map(move |_| rx) .map_err(|e| e.into_inner().0.take().expect("envelope not dropped").0) } pub fn unbound(self) -> UnboundedSender { UnboundedSender { giver: self.giver.shared(), inner: self.inner, } } } impl UnboundedSender { pub fn is_ready(&self) -> bool { !self.giver.is_canceled() } pub fn is_closed(&self) -> bool { self.giver.is_canceled() } pub fn try_send(&mut self, val: T) -> Result, T> { let (tx, rx) = oneshot::channel(); self.inner.unbounded_send(Envelope(Some((val, Callback::Retry(tx))))) .map(move |_| rx) .map_err(|e| e.into_inner().0.take().expect("envelope not dropped").0) } } impl Clone for UnboundedSender { fn clone(&self) -> Self { UnboundedSender { giver: self.giver.clone(), inner: self.inner.clone(), } } } pub struct Receiver { inner: mpsc::UnboundedReceiver>, taker: want::Taker, } impl Stream for Receiver { type Item = (T, Callback); type Error = Never; fn poll(&mut self) -> Poll, Self::Error> { match self.inner.poll() { Ok(Async::Ready(item)) => Ok(Async::Ready(item.map(|mut env| { env.0.take().expect("envelope not dropped") }))), Ok(Async::NotReady) => { self.taker.want(); Ok(Async::NotReady) } Err(()) => unreachable!("mpsc never errors"), } } } impl Drop for Receiver { fn drop(&mut self) { // Notify the giver about the closure first, before dropping // the mpsc::Receiver. self.taker.cancel(); } } struct Envelope(Option<(T, Callback)>); impl Drop for Envelope { fn drop(&mut self) { if let Some((val, cb)) = self.0.take() { let _ = cb.send(Err((::Error::new_canceled().with("connection closed"), Some(val)))); } } } pub enum Callback { Retry(oneshot::Sender)>>), NoRetry(oneshot::Sender>), } impl Callback { pub(crate) fn is_canceled(&self) -> bool { match *self { Callback::Retry(ref tx) => tx.is_canceled(), Callback::NoRetry(ref tx) => tx.is_canceled(), } } pub(crate) fn poll_cancel(&mut self) -> Poll<(), ()> { match *self { Callback::Retry(ref mut tx) => tx.poll_cancel(), Callback::NoRetry(ref mut tx) => tx.poll_cancel(), } } pub(crate) fn send(self, val: Result)>) { match self { Callback::Retry(tx) => { let _ = tx.send(val); }, Callback::NoRetry(tx) => { let _ = tx.send(val.map_err(|e| e.0)); } } } pub(crate) fn send_when( self, mut when: impl Future)>, ) -> impl Future { let mut cb = Some(self); // "select" on this callback being canceled, and the future completing future::poll_fn(move || { match when.poll() { Ok(Async::Ready(res)) => { cb.take() .expect("polled after complete") .send(Ok(res)); Ok(().into()) }, Ok(Async::NotReady) => { // check if the callback is canceled try_ready!(cb.as_mut().unwrap().poll_cancel()); trace!("send_when canceled"); Ok(().into()) }, Err(err) => { cb.take() .expect("polled after complete") .send(Err(err)); Ok(().into()) } } }) } } #[cfg(test)] mod tests { extern crate pretty_env_logger; #[cfg(feature = "nightly")] extern crate test; use futures::{future, Future, Stream}; #[derive(Debug)] struct Custom(i32); #[test] fn drop_receiver_sends_cancel_errors() { let _ = pretty_env_logger::try_init(); future::lazy(|| { let (mut tx, mut rx) = super::channel::(); // must poll once for try_send to succeed assert!(rx.poll().expect("rx empty").is_not_ready()); let promise = tx.try_send(Custom(43)).unwrap(); drop(rx); promise.then(|fulfilled| { let err = fulfilled .expect("fulfilled") .expect_err("promise should error"); match (err.0.kind(), err.1) { (&::error::Kind::Canceled, Some(_)) => (), e => panic!("expected Error::Cancel(_), found {:?}", e), } Ok::<(), ()>(()) }) }).wait().unwrap(); } #[test] fn sender_checks_for_want_on_send() { future::lazy(|| { let (mut tx, mut rx) = super::channel::(); // one is allowed to buffer, second is rejected let _ = tx.try_send(Custom(1)).expect("1 buffered"); tx.try_send(Custom(2)).expect_err("2 not ready"); assert!(rx.poll().expect("rx 1").is_ready()); // Even though 1 has been popped, only 1 could be buffered for the // lifetime of the channel. tx.try_send(Custom(2)).expect_err("2 still not ready"); assert!(rx.poll().expect("rx empty").is_not_ready()); let _ = tx.try_send(Custom(2)).expect("2 ready"); Ok::<(), ()>(()) }).wait().unwrap(); } #[test] fn unbounded_sender_doesnt_bound_on_want() { let (tx, rx) = super::channel::(); let mut tx = tx.unbound(); let _ = tx.try_send(Custom(1)).unwrap(); let _ = tx.try_send(Custom(2)).unwrap(); let _ = tx.try_send(Custom(3)).unwrap(); drop(rx); let _ = tx.try_send(Custom(4)).unwrap_err(); } #[cfg(feature = "nightly")] #[bench] fn giver_queue_throughput(b: &mut test::Bencher) { use {Body, Request, Response}; let (mut tx, mut rx) = super::channel::, Response>(); b.iter(move || { ::futures::future::lazy(|| { let _ = tx.send(Request::default()).unwrap(); loop { let ok = rx.poll().unwrap(); if ok.is_not_ready() { break; } } Ok::<_, ()>(()) }).wait().unwrap(); }) } #[cfg(feature = "nightly")] #[bench] fn giver_queue_not_ready(b: &mut test::Bencher) { let (_tx, mut rx) = super::channel::(); b.iter(move || { ::futures::future::lazy(|| { assert!(rx.poll().unwrap().is_not_ready()); Ok::<(), ()>(()) }).wait().unwrap(); }) } #[cfg(feature = "nightly")] #[bench] fn giver_queue_cancel(b: &mut test::Bencher) { let (_tx, mut rx) = super::channel::(); b.iter(move || { rx.taker.cancel(); }) } } hyper-0.12.35/src/client/mod.rs010066400017500001750000001143341353675567300144600ustar0000000000000000//! HTTP Client //! //! There are two levels of APIs provided for construct HTTP clients: //! //! - The higher-level [`Client`](Client) type. //! - The lower-level [`conn`](client::conn) module. //! //! # Client //! //! The [`Client`](Client) is the main way to send HTTP requests to a server. //! The default `Client` provides these things on top of the lower-level API: //! //! - A default **connector**, able to resolve hostnames and connect to //! destinations over plain-text TCP. //! - A **pool** of existing connections, allowing better performance when //! making multiple requests to the same hostname. //! - Automatic setting of the `Host` header, based on the request `Uri`. //! - Automatic request **retries** when a pooled connection is closed by the //! server before any bytes have been written. //! //! Many of these features can configured, by making use of //! [`Client::builder`](Client::builder). //! //! ## Example //! //! For a small example program simply fetching a URL, take a look at the //! [full client example](https://github.com/hyperium/hyper/blob/0.12.x/examples/client.rs). //! //! ``` //! extern crate hyper; //! //! use hyper::{Client, Uri}; //! # #[cfg(feature = "runtime")] //! use hyper::rt::{self, Future, Stream}; //! //! # #[cfg(feature = "runtime")] //! # fn fetch_httpbin() { //! let client = Client::new(); //! //! let fut = client //! //! // Make a GET /ip to 'http://httpbin.org' //! .get(Uri::from_static("http://httpbin.org/ip")) //! //! // And then, if the request gets a response... //! .and_then(|res| { //! println!("status: {}", res.status()); //! //! // Concatenate the body stream into a single buffer... //! // This returns a new future, since we must stream body. //! res.into_body().concat2() //! }) //! //! // And then, if reading the full body succeeds... //! .and_then(|body| { //! // The body is just bytes, but let's print a string... //! let s = ::std::str::from_utf8(&body) //! .expect("httpbin sends utf-8 JSON"); //! //! println!("body: {}", s); //! //! // and_then requires we return a new Future, and it turns //! // out that Result is a Future that is ready immediately. //! Ok(()) //! }) //! //! // Map any errors that might have happened... //! .map_err(|err| { //! println!("error: {}", err); //! }); //! //! // A runtime is needed to execute our asynchronous code. In order to //! // spawn the future into the runtime, it should already have been //! // started and running before calling this code. //! rt::spawn(fut); //! # } //! # fn main () {} //! ``` use std::fmt; use std::mem; use std::sync::Arc; use std::time::Duration; use futures::{Async, Future, Poll}; use futures::future::{self, Either, Executor}; use futures::sync::oneshot; use http::{Method, Request, Response, Uri, Version}; use http::header::{HeaderValue, HOST}; use http::uri::Scheme; use body::{Body, Payload}; use common::{lazy as hyper_lazy, Lazy}; use self::connect::{Alpn, Connect, Connected, Destination}; use self::pool::{Key as PoolKey, Pool, Poolable, Pooled, Reservation}; #[cfg(feature = "runtime")] pub use self::connect::HttpConnector; pub mod conn; pub mod connect; pub(crate) mod dispatch; mod pool; #[cfg(test)] mod tests; /// A Client to make outgoing HTTP requests. pub struct Client { config: Config, conn_builder: conn::Builder, connector: Arc, pool: Pool>, } #[derive(Clone, Copy, Debug)] struct Config { retry_canceled_requests: bool, set_host: bool, ver: Ver, } #[cfg(feature = "runtime")] impl Client { /// Create a new Client with the default [config](Builder). /// /// # Note /// /// The default connector does **not** handle TLS. Speaking to `https` /// destinations will require [configuring a connector that implements /// TLS](https://hyper.rs/guides/client/configuration). #[inline] pub fn new() -> Client { Builder::default().build_http() } } #[cfg(feature = "runtime")] impl Default for Client { fn default() -> Client { Client::new() } } impl Client<(), Body> { /// Create a builder to configure a new `Client`. /// /// # Example /// /// ``` /// # extern crate hyper; /// # #[cfg(feature = "runtime")] /// # fn run () { /// use hyper::Client; /// /// let client = Client::builder() /// .keep_alive(true) /// .http2_only(true) /// .build_http(); /// # let infer: Client<_, hyper::Body> = client; /// # drop(infer); /// # } /// # fn main() {} /// ``` #[inline] pub fn builder() -> Builder { Builder::default() } } impl Client where C: Connect + Sync + 'static, C::Transport: 'static, C::Future: 'static, B: Payload + Send + 'static, B::Data: Send, { /// Send a `GET` request to the supplied `Uri`. /// /// # Note /// /// This requires that the `Payload` type have a `Default` implementation. /// It *should* return an "empty" version of itself, such that /// `Payload::is_end_stream` is `true`. /// /// # Example /// /// ``` /// # extern crate hyper; /// # #[cfg(feature = "runtime")] /// # fn run () { /// use hyper::{Client, Uri}; /// /// let client = Client::new(); /// /// let future = client.get(Uri::from_static("http://httpbin.org/ip")); /// # } /// # fn main() {} /// ``` pub fn get(&self, uri: Uri) -> ResponseFuture where B: Default, { let body = B::default(); if !body.is_end_stream() { warn!("default Payload used for get() does not return true for is_end_stream"); } let mut req = Request::new(body); *req.uri_mut() = uri; self.request(req) } /// Send a constructed `Request` using this `Client`. /// /// # Example /// /// ``` /// # extern crate hyper; /// # #[cfg(feature = "runtime")] /// # fn run () { /// use hyper::{Body, Client, Request}; /// /// let client = Client::new(); /// /// let req = Request::builder() /// .method("POST") /// .uri("http://httpin.org/post") /// .body(Body::from("Hallo!")) /// .expect("request builder"); /// /// let future = client.request(req); /// # } /// # fn main() {} /// ``` pub fn request(&self, mut req: Request) -> ResponseFuture { let is_http_connect = req.method() == &Method::CONNECT; match req.version() { Version::HTTP_11 => (), Version::HTTP_10 => if is_http_connect { warn!("CONNECT is not allowed for HTTP/1.0"); return ResponseFuture::new(Box::new(future::err(::Error::new_user_unsupported_request_method()))); }, other_h2 @ Version::HTTP_2 => if self.config.ver != Ver::Http2 { return ResponseFuture::error_version(other_h2); }, // completely unsupported HTTP version (like HTTP/0.9)! other => return ResponseFuture::error_version(other), }; let domain = match extract_domain(req.uri_mut(), is_http_connect) { Ok(s) => s, Err(err) => { return ResponseFuture::new(Box::new(future::err(err))); } }; let pool_key = Arc::new(domain.to_string()); ResponseFuture::new(Box::new(self.retryably_send_request(req, pool_key))) } fn retryably_send_request(&self, req: Request, pool_key: PoolKey) -> impl Future, Error=::Error> { let client = self.clone(); let uri = req.uri().clone(); let mut send_fut = client.send_request(req, pool_key.clone()); future::poll_fn(move || loop { match send_fut.poll() { Ok(Async::Ready(resp)) => return Ok(Async::Ready(resp)), Ok(Async::NotReady) => return Ok(Async::NotReady), Err(ClientError::Normal(err)) => return Err(err), Err(ClientError::Canceled { connection_reused, mut req, reason, }) => { if !client.config.retry_canceled_requests || !connection_reused { // if client disabled, don't retry // a fresh connection means we definitely can't retry return Err(reason); } trace!("unstarted request canceled, trying again (reason={:?})", reason); *req.uri_mut() = uri.clone(); send_fut = client.send_request(req, pool_key.clone()); } } }) } fn send_request(&self, mut req: Request, pool_key: PoolKey) -> impl Future, Error=ClientError> { let conn = self.connection_for(req.uri().clone(), pool_key); let set_host = self.config.set_host; let executor = self.conn_builder.exec.clone(); conn.and_then(move |mut pooled| { if pooled.is_http1() { if set_host { let uri = req.uri().clone(); req .headers_mut() .entry(HOST) .expect("HOST is always valid header name") .or_insert_with(|| { let hostname = uri.host().expect("authority implies host"); if let Some(port) = uri.port_part() { let s = format!("{}:{}", hostname, port); HeaderValue::from_str(&s) } else { HeaderValue::from_str(hostname) }.expect("uri host is valid header value") }); } // CONNECT always sends authority-form, so check it first... if req.method() == &Method::CONNECT { authority_form(req.uri_mut()); } else if pooled.conn_info.is_proxied { absolute_form(req.uri_mut()); } else { origin_form(req.uri_mut()); }; } else if req.method() == &Method::CONNECT { debug!("client does not support CONNECT requests over HTTP2"); return Either::A(future::err(ClientError::Normal(::Error::new_user_unsupported_request_method()))); } let fut = pooled.send_request_retryable(req) .map_err(ClientError::map_with_reused(pooled.is_reused())); // If the Connector included 'extra' info, add to Response... let extra_info = pooled.conn_info.extra.clone(); let fut = fut.map(move |mut res| { if let Some(extra) = extra_info { extra.set(&mut res); } res }); // As of futures@0.1.21, there is a race condition in the mpsc // channel, such that sending when the receiver is closing can // result in the message being stuck inside the queue. It won't // ever notify until the Sender side is dropped. // // To counteract this, we must check if our senders 'want' channel // has been closed after having tried to send. If so, error out... if pooled.is_closed() { return Either::B(Either::A(fut)); } Either::B(Either::B(fut .and_then(move |mut res| { // If pooled is HTTP/2, we can toss this reference immediately. // // when pooled is dropped, it will try to insert back into the // pool. To delay that, spawn a future that completes once the // sender is ready again. // // This *should* only be once the related `Connection` has polled // for a new request to start. // // It won't be ready if there is a body to stream. if pooled.is_http2() || !pooled.is_pool_enabled() || pooled.is_ready() { drop(pooled); } else if !res.body().is_end_stream() { let (delayed_tx, delayed_rx) = oneshot::channel(); res.body_mut().delayed_eof(delayed_rx); let on_idle = future::poll_fn(move || { pooled.poll_ready() }) .then(move |_| { // At this point, `pooled` is dropped, and had a chance // to insert into the pool (if conn was idle) drop(delayed_tx); Ok(()) }); if let Err(err) = executor.execute(on_idle) { // This task isn't critical, so just log and ignore. warn!("error spawning task to insert idle connection: {}", err); } } else { // There's no body to delay, but the connection isn't // ready yet. Only re-insert when it's ready let on_idle = future::poll_fn(move || { pooled.poll_ready() }) .then(|_| Ok(())); if let Err(err) = executor.execute(on_idle) { // This task isn't critical, so just log and ignore. warn!("error spawning task to insert idle connection: {}", err); } } Ok(res) }))) }) } fn connection_for(&self, uri: Uri, pool_key: PoolKey) -> impl Future>, Error=ClientError> { // This actually races 2 different futures to try to get a ready // connection the fastest, and to reduce connection churn. // // - If the pool has an idle connection waiting, that's used // immediately. // - Otherwise, the Connector is asked to start connecting to // the destination Uri. // - Meanwhile, the pool Checkout is watching to see if any other // request finishes and tries to insert an idle connection. // - If a new connection is started, but the Checkout wins after // (an idle connection becamse available first), the started // connection future is spawned into the runtime to complete, // and then be inserted into the pool as an idle connection. let checkout = self.pool.checkout(pool_key.clone()); let connect = self.connect_to(uri, pool_key); let executor = self.conn_builder.exec.clone(); checkout // The order of the `select` is depended on below... .select2(connect) .map(move |either| match either { // Checkout won, connect future may have been started or not. // // If it has, let it finish and insert back into the pool, // so as to not waste the socket... Either::A((checked_out, connecting)) => { // This depends on the `select` above having the correct // order, such that if the checkout future were ready // immediately, the connect future will never have been // started. // // If it *wasn't* ready yet, then the connect future will // have been started... if connecting.started() { let bg = connecting .map(|_pooled| { // dropping here should just place it in // the Pool for us... }) .map_err(|err| { trace!("background connect error: {}", err); }); // An execute error here isn't important, we're just trying // to prevent a waste of a socket... let _ = executor.execute(bg); } checked_out }, // Connect won, checkout can just be dropped. Either::B((connected, _checkout)) => { connected }, }) .or_else(|either| match either { // Either checkout or connect could get canceled: // // 1. Connect is canceled if this is HTTP/2 and there is // an outstanding HTTP/2 connecting task. // 2. Checkout is canceled if the pool cannot deliver an // idle connection reliably. // // In both cases, we should just wait for the other future. Either::A((err, connecting)) => { if err.is_canceled() { Either::A(Either::A(connecting.map_err(ClientError::Normal))) } else { Either::B(future::err(ClientError::Normal(err))) } }, Either::B((err, checkout)) => { if err.is_canceled() { Either::A(Either::B(checkout.map_err(ClientError::Normal))) } else { Either::B(future::err(ClientError::Normal(err))) } } }) } fn connect_to(&self, uri: Uri, pool_key: PoolKey) -> impl Lazy>, Error=::Error> { let executor = self.conn_builder.exec.clone(); let pool = self.pool.clone(); let mut conn_builder = self.conn_builder.clone(); let ver = self.config.ver; let is_ver_h2 = ver == Ver::Http2; let connector = self.connector.clone(); let dst = Destination { uri, }; hyper_lazy(move || { // Try to take a "connecting lock". // // If the pool_key is for HTTP/2, and there is already a // connection being estabalished, then this can't take a // second lock. The "connect_to" future is Canceled. let connecting = match pool.connecting(&pool_key, ver) { Some(lock) => lock, None => { let canceled = ::Error::new_canceled().with("HTTP/2 connection in progress"); return Either::B(future::err(canceled)); } }; Either::A(connector.connect(dst) .map_err(::Error::new_connect) .and_then(move |(io, connected)| { // If ALPN is h2 and we aren't http2_only already, // then we need to convert our pool checkout into // a single HTTP2 one. let connecting = if connected.alpn == Alpn::H2 && !is_ver_h2 { match connecting.alpn_h2(&pool) { Some(lock) => { trace!("ALPN negotiated h2, updating pool"); lock }, None => { // Another connection has already upgraded, // the pool checkout should finish up for us. let canceled = ::Error::new_canceled().with("ALPN upgraded to HTTP/2"); return Either::B(future::err(canceled)); } } } else { connecting }; let is_h2 = is_ver_h2 || connected.alpn == Alpn::H2; Either::A(conn_builder .http2_only(is_h2) .handshake(io) .and_then(move |(tx, conn)| { trace!("handshake complete, spawning background dispatcher task"); let bg = executor.execute(conn.map_err(|e| { debug!("client connection error: {}", e) })); // This task is critical, so an execute error // should be returned. if let Err(err) = bg { warn!("error spawning critical client task: {}", err); return Either::A(future::err(err)); } // Wait for 'conn' to ready up before we // declare this tx as usable Either::B(tx.when_ready()) }) .map(move |tx| { pool.pooled(connecting, PoolClient { conn_info: connected, tx: if is_h2 { PoolTx::Http2(tx.into_http2()) } else { PoolTx::Http1(tx) }, }) })) })) }) } } impl Clone for Client { fn clone(&self) -> Client { Client { config: self.config.clone(), conn_builder: self.conn_builder.clone(), connector: self.connector.clone(), pool: self.pool.clone(), } } } impl fmt::Debug for Client { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Client") .finish() } } /// A `Future` that will resolve to an HTTP Response. /// /// This is returned by `Client::request` (and `Client::get`). #[must_use = "futures do nothing unless polled"] pub struct ResponseFuture { inner: Box, Error=::Error> + Send>, } impl ResponseFuture { fn new(fut: Box, Error=::Error> + Send>) -> Self { Self { inner: fut, } } fn error_version(ver: Version) -> Self { warn!("Request has unsupported version \"{:?}\"", ver); ResponseFuture::new(Box::new(future::err(::Error::new_user_unsupported_version()))) } } impl fmt::Debug for ResponseFuture { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("Future") } } impl Future for ResponseFuture { type Item = Response; type Error = ::Error; fn poll(&mut self) -> Poll { self.inner.poll() } } // FIXME: allow() required due to `impl Trait` leaking types to this lint #[allow(missing_debug_implementations)] struct PoolClient { conn_info: Connected, tx: PoolTx, } enum PoolTx { Http1(conn::SendRequest), Http2(conn::Http2SendRequest), } impl PoolClient { fn poll_ready(&mut self) -> Poll<(), ::Error> { match self.tx { PoolTx::Http1(ref mut tx) => tx.poll_ready(), PoolTx::Http2(_) => Ok(Async::Ready(())), } } fn is_http1(&self) -> bool { !self.is_http2() } fn is_http2(&self) -> bool { match self.tx { PoolTx::Http1(_) => false, PoolTx::Http2(_) => true, } } fn is_ready(&self) -> bool { match self.tx { PoolTx::Http1(ref tx) => tx.is_ready(), PoolTx::Http2(ref tx) => tx.is_ready(), } } fn is_closed(&self) -> bool { match self.tx { PoolTx::Http1(ref tx) => tx.is_closed(), PoolTx::Http2(ref tx) => tx.is_closed(), } } } impl PoolClient { fn send_request_retryable(&mut self, req: Request) -> impl Future, Error = (::Error, Option>)> where B: Send, { match self.tx { PoolTx::Http1(ref mut tx) => Either::A(tx.send_request_retryable(req)), PoolTx::Http2(ref mut tx) => Either::B(tx.send_request_retryable(req)), } } } impl Poolable for PoolClient where B: Send + 'static, { fn is_open(&self) -> bool { match self.tx { PoolTx::Http1(ref tx) => tx.is_ready(), PoolTx::Http2(ref tx) => tx.is_ready(), } } fn reserve(self) -> Reservation { match self.tx { PoolTx::Http1(tx) => { Reservation::Unique(PoolClient { conn_info: self.conn_info, tx: PoolTx::Http1(tx), }) }, PoolTx::Http2(tx) => { let b = PoolClient { conn_info: self.conn_info.clone(), tx: PoolTx::Http2(tx.clone()), }; let a = PoolClient { conn_info: self.conn_info, tx: PoolTx::Http2(tx), }; Reservation::Shared(a, b) } } } fn can_share(&self) -> bool { self.is_http2() } } // FIXME: allow() required due to `impl Trait` leaking types to this lint #[allow(missing_debug_implementations)] enum ClientError { Normal(::Error), Canceled { connection_reused: bool, req: Request, reason: ::Error, } } impl ClientError { fn map_with_reused(conn_reused: bool) -> impl Fn((::Error, Option>)) -> Self { move |(err, orig_req)| { if let Some(req) = orig_req { ClientError::Canceled { connection_reused: conn_reused, reason: err, req, } } else { ClientError::Normal(err) } } } } /// A marker to identify what version a pooled connection is. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] enum Ver { Auto, Http2, } fn origin_form(uri: &mut Uri) { let path = match uri.path_and_query() { Some(path) if path.as_str() != "/" => { let mut parts = ::http::uri::Parts::default(); parts.path_and_query = Some(path.clone()); Uri::from_parts(parts).expect("path is valid uri") }, _none_or_just_slash => { debug_assert!(Uri::default() == "/"); Uri::default() } }; *uri = path } fn absolute_form(uri: &mut Uri) { debug_assert!(uri.scheme_part().is_some(), "absolute_form needs a scheme"); debug_assert!(uri.authority_part().is_some(), "absolute_form needs an authority"); // If the URI is to HTTPS, and the connector claimed to be a proxy, // then it *should* have tunneled, and so we don't want to send // absolute-form in that case. if uri.scheme_part() == Some(&Scheme::HTTPS) { origin_form(uri); } } fn authority_form(uri: &mut Uri) { if log_enabled!(::log::Level::Warn) { if let Some(path) = uri.path_and_query() { // `https://hyper.rs` would parse with `/` path, don't // annoy people about that... if path != "/" { warn!( "HTTP/1.1 CONNECT request stripping path: {:?}", path ); } } } *uri = match uri.authority_part() { Some(auth) => { let mut parts = ::http::uri::Parts::default(); parts.authority = Some(auth.clone()); Uri::from_parts(parts).expect("authority is valid") }, None => { unreachable!("authority_form with relative uri"); } }; } fn extract_domain(uri: &mut Uri, is_http_connect: bool) -> ::Result { let uri_clone = uri.clone(); match (uri_clone.scheme_part(), uri_clone.authority_part()) { (Some(scheme), Some(auth)) => { Ok(format!("{}://{}", scheme, auth)) } (None, Some(auth)) if is_http_connect => { let port = auth.port_part(); let scheme = match port.as_ref().map(|p| p.as_str()) { Some("443") => { set_scheme(uri, Scheme::HTTPS); "https" } _ => { set_scheme(uri, Scheme::HTTP); "http" }, }; Ok(format!("{}://{}", scheme, auth)) }, _ => { debug!("Client requires absolute-form URIs, received: {:?}", uri); Err(::Error::new_user_absolute_uri_required()) } } } fn set_scheme(uri: &mut Uri, scheme: Scheme) { debug_assert!(uri.scheme_part().is_none(), "set_scheme expects no existing scheme"); let old = mem::replace(uri, Uri::default()); let mut parts: ::http::uri::Parts = old.into(); parts.scheme = Some(scheme); parts.path_and_query = Some("/".parse().expect("slash is a valid path")); *uri = Uri::from_parts(parts).expect("scheme is valid"); } /// A builder to configure a new [`Client`](Client). /// /// # Example /// /// ``` /// # extern crate hyper; /// # #[cfg(feature = "runtime")] /// # fn run () { /// use hyper::Client; /// /// let client = Client::builder() /// .keep_alive(true) /// .http2_only(true) /// .build_http(); /// # let infer: Client<_, hyper::Body> = client; /// # drop(infer); /// # } /// # fn main() {} /// ``` #[derive(Clone)] pub struct Builder { client_config: Config, conn_builder: conn::Builder, pool_config: pool::Config, } impl Default for Builder { fn default() -> Self { Self { client_config: Config { retry_canceled_requests: true, set_host: true, ver: Ver::Auto, }, conn_builder: conn::Builder::new(), pool_config: pool::Config { enabled: true, keep_alive_timeout: Some(Duration::from_secs(90)), max_idle_per_host: ::std::usize::MAX, }, } } } impl Builder { /// Enable or disable keep-alive mechanics. /// /// Default is enabled. #[inline] pub fn keep_alive(&mut self, val: bool) -> &mut Self { self.pool_config.enabled = val; self } /// Set an optional timeout for idle sockets being kept-alive. /// /// Pass `None` to disable timeout. /// /// Default is 90 seconds. #[inline] pub fn keep_alive_timeout(&mut self, val: D) -> &mut Self where D: Into>, { self.pool_config.keep_alive_timeout = val.into(); self } /// Set whether HTTP/1 connections should try to use vectored writes, /// or always flatten into a single buffer. /// /// Note that setting this to false may mean more copies of body data, /// but may also improve performance when an IO transport doesn't /// support vectored writes well, such as most TLS implementations. /// /// Default is `true`. #[inline] pub fn http1_writev(&mut self, val: bool) -> &mut Self { self.conn_builder.h1_writev(val); self } /// Sets the exact size of the read buffer to *always* use. /// /// Note that setting this option unsets the `http1_max_buf_size` option. /// /// Default is an adaptive read buffer. #[inline] pub fn http1_read_buf_exact_size(&mut self, sz: usize) -> &mut Self { self.conn_builder.h1_read_buf_exact_size(Some(sz)); self } /// Set the maximum buffer size for the connection. /// /// Default is ~400kb. /// /// Note that setting this option unsets the `http1_read_exact_buf_size` option. /// /// # Panics /// /// The minimum value allowed is 8192. This method panics if the passed `max` is less than the minimum. #[inline] pub fn http1_max_buf_size(&mut self, max: usize) -> &mut Self { self.conn_builder.h1_max_buf_size(max); self } /// Set whether HTTP/1 connections will write header names as title case at /// the socket level. /// /// Note that this setting does not affect HTTP/2. /// /// Default is false. pub fn http1_title_case_headers(&mut self, val: bool) -> &mut Self { self.conn_builder.h1_title_case_headers(val); self } /// Set whether the connection **must** use HTTP/2. /// /// The destination must either allow HTTP2 Prior Knowledge, or the /// `Connect` should be configured to do use ALPN to upgrade to `h2` /// as part of the connection process. This will not make the `Client` /// utilize ALPN by itself. /// /// Note that setting this to true prevents HTTP/1 from being allowed. /// /// Default is false. pub fn http2_only(&mut self, val: bool) -> &mut Self { self.client_config.ver = if val { Ver::Http2 } else { Ver::Auto }; self } /// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`][spec] option for HTTP2 /// stream-level flow control. /// /// Default is 65,535 /// /// [spec]: https://http2.github.io/http2-spec/#SETTINGS_INITIAL_WINDOW_SIZE pub fn http2_initial_stream_window_size(&mut self, sz: impl Into>) -> &mut Self { self.conn_builder.http2_initial_stream_window_size(sz.into()); self } /// Sets the max connection-level flow control for HTTP2 /// /// Default is 65,535 pub fn http2_initial_connection_window_size(&mut self, sz: impl Into>) -> &mut Self { self.conn_builder.http2_initial_connection_window_size(sz.into()); self } /// Sets the maximum idle connection per host allowed in the pool. /// /// Default is `usize::MAX` (no limit). pub fn max_idle_per_host(&mut self, max_idle: usize) -> &mut Self { self.pool_config.max_idle_per_host = max_idle; self } /// Set whether to retry requests that get disrupted before ever starting /// to write. /// /// This means a request that is queued, and gets given an idle, reused /// connection, and then encounters an error immediately as the idle /// connection was found to be unusable. /// /// When this is set to `false`, the related `ResponseFuture` would instead /// resolve to an `Error::Cancel`. /// /// Default is `true`. #[inline] pub fn retry_canceled_requests(&mut self, val: bool) -> &mut Self { self.client_config.retry_canceled_requests = val; self } /// Set whether to automatically add the `Host` header to requests. /// /// If true, and a request does not include a `Host` header, one will be /// added automatically, derived from the authority of the `Uri`. /// /// Default is `true`. #[inline] pub fn set_host(&mut self, val: bool) -> &mut Self { self.client_config.set_host = val; self } /// Provide an executor to execute background `Connection` tasks. pub fn executor(&mut self, exec: E) -> &mut Self where E: Executor + Send>> + Send + Sync + 'static, { self.conn_builder.executor(exec); self } /// Builder a client with this configuration and the default `HttpConnector`. #[cfg(feature = "runtime")] pub fn build_http(&self) -> Client where B: Payload + Send, B::Data: Send, { let mut connector = HttpConnector::new(4); if self.pool_config.enabled { connector.set_keepalive(self.pool_config.keep_alive_timeout); } self.build(connector) } /// Combine the configuration of this builder with a connector to create a `Client`. pub fn build(&self, connector: C) -> Client where C: Connect, C::Transport: 'static, C::Future: 'static, B: Payload + Send, B::Data: Send, { Client { config: self.client_config, conn_builder: self.conn_builder.clone(), connector: Arc::new(connector), pool: Pool::new(self.pool_config, &self.conn_builder.exec), } } } impl fmt::Debug for Builder { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Builder") .field("client_config", &self.client_config) .field("conn_builder", &self.conn_builder) .field("pool_config", &self.pool_config) .finish() } } #[cfg(test)] mod unit_tests { use super::*; #[test] fn set_relative_uri_with_implicit_path() { let mut uri = "http://hyper.rs".parse().unwrap(); origin_form(&mut uri); assert_eq!(uri.to_string(), "/"); } #[test] fn test_origin_form() { let mut uri = "http://hyper.rs/guides".parse().unwrap(); origin_form(&mut uri); assert_eq!(uri.to_string(), "/guides"); let mut uri = "http://hyper.rs/guides?foo=bar".parse().unwrap(); origin_form(&mut uri); assert_eq!(uri.to_string(), "/guides?foo=bar"); } #[test] fn test_absolute_form() { let mut uri = "http://hyper.rs/guides".parse().unwrap(); absolute_form(&mut uri); assert_eq!(uri.to_string(), "http://hyper.rs/guides"); let mut uri = "https://hyper.rs/guides".parse().unwrap(); absolute_form(&mut uri); assert_eq!(uri.to_string(), "/guides"); } #[test] fn test_authority_form() { extern crate pretty_env_logger; let _ = pretty_env_logger::try_init(); let mut uri = "http://hyper.rs".parse().unwrap(); authority_form(&mut uri); assert_eq!(uri.to_string(), "hyper.rs"); let mut uri = "hyper.rs".parse().unwrap(); authority_form(&mut uri); assert_eq!(uri.to_string(), "hyper.rs"); } #[test] fn test_extract_domain_connect_no_port() { let mut uri = "hyper.rs".parse().unwrap(); let domain = extract_domain(&mut uri, true).expect("extract domain"); assert_eq!(domain, "http://hyper.rs"); } } hyper-0.12.35/src/client/pool.rs010066400017500001750000000770671353675567300146650ustar0000000000000000use std::collections::{HashMap, HashSet, VecDeque}; use std::fmt; use std::ops::{Deref, DerefMut}; use std::sync::{Arc, Mutex, Weak}; use std::time::{Duration, Instant}; use futures::{Future, Async, Poll}; use futures::sync::oneshot; #[cfg(feature = "runtime")] use tokio_timer::Interval; use common::Exec; use super::Ver; // FIXME: allow() required due to `impl Trait` leaking types to this lint #[allow(missing_debug_implementations)] pub(super) struct Pool { // If the pool is disabled, this is None. inner: Option>>>, } // Before using a pooled connection, make sure the sender is not dead. // // This is a trait to allow the `client::pool::tests` to work for `i32`. // // See https://github.com/hyperium/hyper/issues/1429 pub(super) trait Poolable: Send + Sized + 'static { fn is_open(&self) -> bool; /// Reserve this connection. /// /// Allows for HTTP/2 to return a shared reservation. fn reserve(self) -> Reservation; fn can_share(&self) -> bool; } /// When checking out a pooled connection, it might be that the connection /// only supports a single reservation, or it might be usable for many. /// /// Specifically, HTTP/1 requires a unique reservation, but HTTP/2 can be /// used for multiple requests. // FIXME: allow() required due to `impl Trait` leaking types to this lint #[allow(missing_debug_implementations)] pub(super) enum Reservation { /// This connection could be used multiple times, the first one will be /// reinserted into the `idle` pool, and the second will be given to /// the `Checkout`. Shared(T, T), /// This connection requires unique access. It will be returned after /// use is complete. Unique(T), } /// Simple type alias in case the key type needs to be adjusted. pub(super) type Key = Arc; struct PoolInner { // A flag that a connection is being estabilished, and the connection // should be shared. This prevents making multiple HTTP/2 connections // to the same host. connecting: HashSet, // These are internal Conns sitting in the event loop in the KeepAlive // state, waiting to receive a new Request to send on the socket. idle: HashMap>>, max_idle_per_host: usize, // These are outstanding Checkouts that are waiting for a socket to be // able to send a Request one. This is used when "racing" for a new // connection. // // The Client starts 2 tasks, 1 to connect a new socket, and 1 to wait // for the Pool to receive an idle Conn. When a Conn becomes idle, // this list is checked for any parked Checkouts, and tries to notify // them that the Conn could be used instead of waiting for a brand new // connection. waiters: HashMap>>, // A oneshot channel is used to allow the interval to be notified when // the Pool completely drops. That way, the interval can cancel immediately. #[cfg(feature = "runtime")] idle_interval_ref: Option>, #[cfg(feature = "runtime")] exec: Exec, timeout: Option, } // This is because `Weak::new()` *allocates* space for `T`, even if it // doesn't need it! struct WeakOpt(Option>); #[derive(Clone, Copy, Debug)] pub(super) struct Config { pub(super) enabled: bool, pub(super) keep_alive_timeout: Option, pub(super) max_idle_per_host: usize, } impl Pool { pub fn new(config: Config, __exec: &Exec) -> Pool { let inner = if config.enabled { Some(Arc::new(Mutex::new(PoolInner { connecting: HashSet::new(), idle: HashMap::new(), #[cfg(feature = "runtime")] idle_interval_ref: None, max_idle_per_host: config.max_idle_per_host, waiters: HashMap::new(), #[cfg(feature = "runtime")] exec: __exec.clone(), timeout: config.keep_alive_timeout, }))) } else { None }; Pool { inner, } } fn is_enabled(&self) -> bool { self.inner.is_some() } #[cfg(test)] pub(super) fn no_timer(&self) { // Prevent an actual interval from being created for this pool... #[cfg(feature = "runtime")] { let mut inner = self.inner.as_ref().unwrap().lock().unwrap(); assert!(inner.idle_interval_ref.is_none(), "timer already spawned"); let (tx, _) = oneshot::channel(); inner.idle_interval_ref = Some(tx); } } } impl Pool { /// Returns a `Checkout` which is a future that resolves if an idle /// connection becomes available. pub fn checkout(&self, key: Key) -> Checkout { Checkout { key, pool: self.clone(), waiter: None, } } /// Ensure that there is only ever 1 connecting task for HTTP/2 /// connections. This does nothing for HTTP/1. pub(super) fn connecting(&self, key: &Key, ver: Ver) -> Option> { if ver == Ver::Http2 { if let Some(ref enabled) = self.inner { let mut inner = enabled.lock().unwrap(); return if inner.connecting.insert(key.clone()) { let connecting = Connecting { key: key.clone(), pool: WeakOpt::downgrade(enabled), }; Some(connecting) } else { trace!("HTTP/2 connecting already in progress for {:?}", key); None }; } } // else Some(Connecting { key: key.clone(), // in HTTP/1's case, there is never a lock, so we don't // need to do anything in Drop. pool: WeakOpt::none(), }) } #[cfg(test)] fn locked(&self) -> ::std::sync::MutexGuard> { self .inner .as_ref() .expect("enabled") .lock() .expect("lock") } #[cfg(feature = "runtime")] #[cfg(test)] pub(super) fn h1_key(&self, s: &str) -> Key { Arc::new(s.to_string()) } #[cfg(feature = "runtime")] #[cfg(test)] pub(super) fn idle_count(&self, key: &Key) -> usize { self .locked() .idle .get(key) .map(|list| list.len()) .unwrap_or(0) } pub(super) fn pooled(&self, mut connecting: Connecting, value: T) -> Pooled { let (value, pool_ref) = if let Some(ref enabled) = self.inner { match value.reserve() { Reservation::Shared(to_insert, to_return) => { let mut inner = enabled.lock().unwrap(); inner.put(connecting.key.clone(), to_insert, enabled); // Do this here instead of Drop for Connecting because we // already have a lock, no need to lock the mutex twice. inner.connected(&connecting.key); // prevent the Drop of Connecting from repeating inner.connected() connecting.pool = WeakOpt::none(); // Shared reservations don't need a reference to the pool, // since the pool always keeps a copy. (to_return, WeakOpt::none()) }, Reservation::Unique(value) => { // Unique reservations must take a reference to the pool // since they hope to reinsert once the reservation is // completed (value, WeakOpt::downgrade(enabled)) }, } } else { // If pool is not enabled, skip all the things... // The Connecting should have had no pool ref debug_assert!(connecting.pool.upgrade().is_none()); (value, WeakOpt::none()) }; Pooled { key: connecting.key.clone(), is_reused: false, pool: pool_ref, value: Some(value) } } fn reuse(&self, key: &Key, value: T) -> Pooled { debug!("reuse idle connection for {:?}", key); // TODO: unhack this // In Pool::pooled(), which is used for inserting brand new connections, // there's some code that adjusts the pool reference taken depending // on if the Reservation can be shared or is unique. By the time // reuse() is called, the reservation has already been made, and // we just have the final value, without knowledge of if this is // unique or shared. So, the hack is to just assume Ver::Http2 means // shared... :( let mut pool_ref = WeakOpt::none(); if !value.can_share() { if let Some(ref enabled) = self.inner { pool_ref = WeakOpt::downgrade(enabled); } } Pooled { is_reused: true, key: key.clone(), pool: pool_ref, value: Some(value), } } } /// Pop off this list, looking for a usable connection that hasn't expired. struct IdlePopper<'a, T: 'a> { key: &'a Key, list: &'a mut Vec>, } impl<'a, T: Poolable + 'a> IdlePopper<'a, T> { fn pop(self, expiration: &Expiration) -> Option> { while let Some(entry) = self.list.pop() { // If the connection has been closed, or is older than our idle // timeout, simply drop it and keep looking... if !entry.value.is_open() { trace!("removing closed connection for {:?}", self.key); continue; } // TODO: Actually, since the `idle` list is pushed to the end always, // that would imply that if *this* entry is expired, then anything // "earlier" in the list would *have* to be expired also... Right? // // In that case, we could just break out of the loop and drop the // whole list... if expiration.expires(entry.idle_at) { trace!("removing expired connection for {:?}", self.key); continue; } let value = match entry.value.reserve() { Reservation::Shared(to_reinsert, to_checkout) => { self.list.push(Idle { idle_at: Instant::now(), value: to_reinsert, }); to_checkout }, Reservation::Unique(unique) => { unique } }; return Some(Idle { idle_at: entry.idle_at, value, }); } None } } impl PoolInner { fn put(&mut self, key: Key, value: T, __pool_ref: &Arc>>) { if value.can_share() && self.idle.contains_key(&key) { trace!("put; existing idle HTTP/2 connection for {:?}", key); return; } trace!("put; add idle connection for {:?}", key); let mut remove_waiters = false; let mut value = Some(value); if let Some(waiters) = self.waiters.get_mut(&key) { while let Some(tx) = waiters.pop_front() { if !tx.is_canceled() { let reserved = value.take().expect("value already sent"); let reserved = match reserved.reserve() { Reservation::Shared(to_keep, to_send) => { value = Some(to_keep); to_send }, Reservation::Unique(uniq) => uniq, }; match tx.send(reserved) { Ok(()) => { if value.is_none() { break; } else { continue; } }, Err(e) => { value = Some(e); } } } trace!("put; removing canceled waiter for {:?}", key); } remove_waiters = waiters.is_empty(); } if remove_waiters { self.waiters.remove(&key); } match value { Some(value) => { // borrow-check scope... { let idle_list = self .idle .entry(key.clone()) .or_insert(Vec::new()); if self.max_idle_per_host <= idle_list.len() { trace!("max idle per host for {:?}, dropping connection", key); return; } debug!("pooling idle connection for {:?}", key); idle_list.push(Idle { value: value, idle_at: Instant::now(), }); } #[cfg(feature = "runtime")] { self.spawn_idle_interval(__pool_ref); } } None => trace!("put; found waiter for {:?}", key), } } /// A `Connecting` task is complete. Not necessarily successfully, /// but the lock is going away, so clean up. fn connected(&mut self, key: &Key) { let existed = self.connecting.remove(key); debug_assert!( existed, "Connecting dropped, key not in pool.connecting" ); // cancel any waiters. if there are any, it's because // this Connecting task didn't complete successfully. // those waiters would never receive a connection. self.waiters.remove(key); } #[cfg(feature = "runtime")] fn spawn_idle_interval(&mut self, pool_ref: &Arc>>) { let (dur, rx) = { if self.idle_interval_ref.is_some() { return; } if let Some(dur) = self.timeout { let (tx, rx) = oneshot::channel(); self.idle_interval_ref = Some(tx); (dur, rx) } else { return } }; let start = Instant::now() + dur; let interval = IdleInterval { interval: Interval::new(start, dur), pool: WeakOpt::downgrade(pool_ref), pool_drop_notifier: rx, }; if let Err(err) = self.exec.execute(interval) { // This task isn't critical, so simply log and ignore. warn!("error spawning connection pool idle interval: {}", err); } } } impl PoolInner { /// Any `FutureResponse`s that were created will have made a `Checkout`, /// and possibly inserted into the pool that it is waiting for an idle /// connection. If a user ever dropped that future, we need to clean out /// those parked senders. fn clean_waiters(&mut self, key: &Key) { let mut remove_waiters = false; if let Some(waiters) = self.waiters.get_mut(key) { waiters.retain(|tx| { !tx.is_canceled() }); remove_waiters = waiters.is_empty(); } if remove_waiters { self.waiters.remove(key); } } } #[cfg(feature = "runtime")] impl PoolInner { /// This should *only* be called by the IdleInterval. fn clear_expired(&mut self) { let dur = self.timeout.expect("interval assumes timeout"); let now = Instant::now(); //self.last_idle_check_at = now; self.idle.retain(|key, values| { values.retain(|entry| { if !entry.value.is_open() { trace!("idle interval evicting closed for {:?}", key); return false; } if now - entry.idle_at > dur { trace!("idle interval evicting expired for {:?}", key); return false; } // Otherwise, keep this value... true }); // returning false evicts this key/val !values.is_empty() }); } } impl Clone for Pool { fn clone(&self) -> Pool { Pool { inner: self.inner.clone(), } } } /// A wrapped poolable value that tries to reinsert to the Pool on Drop. // Note: The bounds `T: Poolable` is needed for the Drop impl. pub(super) struct Pooled { value: Option, is_reused: bool, key: Key, pool: WeakOpt>>, } impl Pooled { pub fn is_reused(&self) -> bool { self.is_reused } pub fn is_pool_enabled(&self) -> bool { self.pool.0.is_some() } fn as_ref(&self) -> &T { self.value.as_ref().expect("not dropped") } fn as_mut(&mut self) -> &mut T { self.value.as_mut().expect("not dropped") } } impl Deref for Pooled { type Target = T; fn deref(&self) -> &T { self.as_ref() } } impl DerefMut for Pooled { fn deref_mut(&mut self) -> &mut T { self.as_mut() } } impl Drop for Pooled { fn drop(&mut self) { if let Some(value) = self.value.take() { if !value.is_open() { // If we *already* know the connection is done here, // it shouldn't be re-inserted back into the pool. return; } if let Some(pool) = self.pool.upgrade() { if let Ok(mut inner) = pool.lock() { inner.put(self.key.clone(), value, &pool); } } else if !value.can_share() { trace!("pool dropped, dropping pooled ({:?})", self.key); } // Ver::Http2 is already in the Pool (or dead), so we wouldn't // have an actual reference to the Pool. } } } impl fmt::Debug for Pooled { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Pooled") .field("key", &self.key) .finish() } } struct Idle { idle_at: Instant, value: T, } // FIXME: allow() required due to `impl Trait` leaking types to this lint #[allow(missing_debug_implementations)] pub(super) struct Checkout { key: Key, pool: Pool, waiter: Option>, } impl Checkout { fn poll_waiter(&mut self) -> Poll>, ::Error> { static CANCELED: &str = "pool checkout failed"; if let Some(mut rx) = self.waiter.take() { match rx.poll() { Ok(Async::Ready(value)) => { if value.is_open() { Ok(Async::Ready(Some(self.pool.reuse(&self.key, value)))) } else { Err(::Error::new_canceled().with(CANCELED)) } }, Ok(Async::NotReady) => { self.waiter = Some(rx); Ok(Async::NotReady) }, Err(_canceled) => Err(::Error::new_canceled().with(CANCELED)), } } else { Ok(Async::Ready(None)) } } fn checkout(&mut self) -> Option> { let entry = { let mut inner = self.pool.inner.as_ref()?.lock().unwrap(); let expiration = Expiration::new(inner.timeout); let maybe_entry = inner.idle.get_mut(&self.key) .and_then(|list| { trace!("take? {:?}: expiration = {:?}", self.key, expiration.0); // A block to end the mutable borrow on list, // so the map below can check is_empty() { let popper = IdlePopper { key: &self.key, list, }; popper.pop(&expiration) } .map(|e| (e, list.is_empty())) }); let (entry, empty) = if let Some((e, empty)) = maybe_entry { (Some(e), empty) } else { // No entry found means nuke the list for sure. (None, true) }; if empty { //TODO: This could be done with the HashMap::entry API instead. inner.idle.remove(&self.key); } if entry.is_none() && self.waiter.is_none() { let (tx, mut rx) = oneshot::channel(); let _ = rx.poll(); // park this task trace!("checkout waiting for idle connection: {:?}", self.key); inner .waiters .entry(self.key.clone()) .or_insert(VecDeque::new()) .push_back(tx); self.waiter = Some(rx); } entry }; entry.map(|e| self.pool.reuse(&self.key, e.value)) } } impl Future for Checkout { type Item = Pooled; type Error = ::Error; fn poll(&mut self) -> Poll { if let Some(pooled) = try_ready!(self.poll_waiter()) { return Ok(Async::Ready(pooled)); } if let Some(pooled) = self.checkout() { Ok(Async::Ready(pooled)) } else if !self.pool.is_enabled() { Err(::Error::new_canceled().with("pool is disabled")) } else { Ok(Async::NotReady) } } } impl Drop for Checkout { fn drop(&mut self) { if self.waiter.take().is_some() { trace!("checkout dropped for {:?}", self.key); if let Some(Ok(mut inner)) = self.pool.inner.as_ref().map(|i| i.lock()) { inner.clean_waiters(&self.key); } } } } // FIXME: allow() required due to `impl Trait` leaking types to this lint #[allow(missing_debug_implementations)] pub(super) struct Connecting { key: Key, pool: WeakOpt>>, } impl Connecting { pub(super) fn alpn_h2(self, pool: &Pool) -> Option { debug_assert!( self.pool.0.is_none(), "Connecting::alpn_h2 but already Http2" ); pool.connecting(&self.key, Ver::Http2) } } impl Drop for Connecting { fn drop(&mut self) { if let Some(pool) = self.pool.upgrade() { // No need to panic on drop, that could abort! if let Ok(mut inner) = pool.lock() { inner.connected(&self.key); } } } } struct Expiration(Option); impl Expiration { fn new(dur: Option) -> Expiration { Expiration(dur) } fn expires(&self, instant: Instant) -> bool { match self.0 { Some(timeout) => instant.elapsed() > timeout, None => false, } } } #[cfg(feature = "runtime")] struct IdleInterval { interval: Interval, pool: WeakOpt>>, // This allows the IdleInterval to be notified as soon as the entire // Pool is fully dropped, and shutdown. This channel is never sent on, // but Err(Canceled) will be received when the Pool is dropped. pool_drop_notifier: oneshot::Receiver<::common::Never>, } #[cfg(feature = "runtime")] impl Future for IdleInterval { type Item = (); type Error = (); fn poll(&mut self) -> Poll { // Interval is a Stream use futures::Stream; loop { match self.pool_drop_notifier.poll() { Ok(Async::Ready(n)) => match n {}, Ok(Async::NotReady) => (), Err(_canceled) => { trace!("pool closed, canceling idle interval"); return Ok(Async::Ready(())); } } try_ready!(self.interval.poll().map_err(|err| { error!("idle interval timer error: {}", err); })); if let Some(inner) = self.pool.upgrade() { if let Ok(mut inner) = inner.lock() { trace!("idle interval checking for expired"); inner.clear_expired(); continue; } } return Ok(Async::Ready(())); } } } impl WeakOpt { fn none() -> Self { WeakOpt(None) } fn downgrade(arc: &Arc) -> Self { WeakOpt(Some(Arc::downgrade(arc))) } fn upgrade(&self) -> Option> { self.0 .as_ref() .and_then(Weak::upgrade) } } #[cfg(test)] mod tests { use std::sync::Arc; use std::time::Duration; use futures::{Async, Future}; use futures::future; use common::Exec; use super::{Connecting, Key, Poolable, Pool, Reservation, WeakOpt}; /// Test unique reservations. #[derive(Debug, PartialEq, Eq)] struct Uniq(T); impl Poolable for Uniq { fn is_open(&self) -> bool { true } fn reserve(self) -> Reservation { Reservation::Unique(self) } fn can_share(&self) -> bool { false } } fn c(key: Key) -> Connecting { Connecting { key, pool: WeakOpt::none(), } } fn pool_no_timer() -> Pool { pool_max_idle_no_timer(::std::usize::MAX) } fn pool_max_idle_no_timer(max_idle: usize) -> Pool { let pool = Pool::new(super::Config { enabled: true, keep_alive_timeout: Some(Duration::from_millis(100)), max_idle_per_host: max_idle, }, &Exec::Default, ); pool.no_timer(); pool } #[test] fn test_pool_checkout_smoke() { let pool = pool_no_timer(); let key = Arc::new("foo".to_string()); let pooled = pool.pooled(c(key.clone()), Uniq(41)); drop(pooled); match pool.checkout(key).poll().unwrap() { Async::Ready(pooled) => assert_eq!(*pooled, Uniq(41)), _ => panic!("not ready"), } } #[test] fn test_pool_checkout_returns_none_if_expired() { future::lazy(|| { let pool = pool_no_timer(); let key = Arc::new("foo".to_string()); let pooled = pool.pooled(c(key.clone()), Uniq(41)); drop(pooled); ::std::thread::sleep(pool.locked().timeout.unwrap()); assert!(pool.checkout(key).poll().unwrap().is_not_ready()); ::futures::future::ok::<(), ()>(()) }).wait().unwrap(); } #[test] fn test_pool_checkout_removes_expired() { future::lazy(|| { let pool = pool_no_timer(); let key = Arc::new("foo".to_string()); pool.pooled(c(key.clone()), Uniq(41)); pool.pooled(c(key.clone()), Uniq(5)); pool.pooled(c(key.clone()), Uniq(99)); assert_eq!(pool.locked().idle.get(&key).map(|entries| entries.len()), Some(3)); ::std::thread::sleep(pool.locked().timeout.unwrap()); // checkout.poll() should clean out the expired pool.checkout(key.clone()).poll().unwrap(); assert!(pool.locked().idle.get(&key).is_none()); Ok::<(), ()>(()) }).wait().unwrap(); } #[test] fn test_pool_max_idle_per_host() { future::lazy(|| { let pool = pool_max_idle_no_timer(2); let key = Arc::new("foo".to_string()); pool.pooled(c(key.clone()), Uniq(41)); pool.pooled(c(key.clone()), Uniq(5)); pool.pooled(c(key.clone()), Uniq(99)); // pooled and dropped 3, max_idle should only allow 2 assert_eq!(pool.locked().idle.get(&key).map(|entries| entries.len()), Some(2)); Ok::<(), ()>(()) }).wait().unwrap(); } #[cfg(feature = "runtime")] #[test] fn test_pool_timer_removes_expired() { use std::time::Instant; use tokio_timer::Delay; let mut rt = ::tokio::runtime::current_thread::Runtime::new().unwrap(); let pool = Pool::new(super::Config { enabled: true, keep_alive_timeout: Some(Duration::from_millis(100)), max_idle_per_host: ::std::usize::MAX, }, &Exec::Default, ); let key = Arc::new("foo".to_string()); // Since pool.pooled() will be calling spawn on drop, need to be sure // those drops are called while `rt` is the current executor. To do so, // call those inside a future. rt.block_on(::futures::future::lazy(|| { pool.pooled(c(key.clone()), Uniq(41)); pool.pooled(c(key.clone()), Uniq(5)); pool.pooled(c(key.clone()), Uniq(99)); Ok::<_, ()>(()) })).unwrap(); assert_eq!(pool.locked().idle.get(&key).map(|entries| entries.len()), Some(3)); // Let the timer tick passed the expiration... rt .block_on(Delay::new(Instant::now() + Duration::from_millis(200))) .expect("rt block_on 200ms"); assert!(pool.locked().idle.get(&key).is_none()); } #[test] fn test_pool_checkout_task_unparked() { let pool = pool_no_timer(); let key = Arc::new("foo".to_string()); let pooled = pool.pooled(c(key.clone()), Uniq(41)); let checkout = pool.checkout(key).join(future::lazy(move || { // the checkout future will park first, // and then this lazy future will be polled, which will insert // the pooled back into the pool // // this test makes sure that doing so will unpark the checkout drop(pooled); Ok(()) })).map(|(entry, _)| entry); assert_eq!(*checkout.wait().unwrap(), Uniq(41)); } #[test] fn test_pool_checkout_drop_cleans_up_waiters() { future::lazy(|| { let pool = pool_no_timer::>(); let key = Arc::new("localhost:12345".to_string()); let mut checkout1 = pool.checkout(key.clone()); let mut checkout2 = pool.checkout(key.clone()); // first poll needed to get into Pool's parked checkout1.poll().unwrap(); assert_eq!(pool.locked().waiters.get(&key).unwrap().len(), 1); checkout2.poll().unwrap(); assert_eq!(pool.locked().waiters.get(&key).unwrap().len(), 2); // on drop, clean up Pool drop(checkout1); assert_eq!(pool.locked().waiters.get(&key).unwrap().len(), 1); drop(checkout2); assert!(pool.locked().waiters.get(&key).is_none()); ::futures::future::ok::<(), ()>(()) }).wait().unwrap(); } #[derive(Debug)] struct CanClose { val: i32, closed: bool, } impl Poolable for CanClose { fn is_open(&self) -> bool { !self.closed } fn reserve(self) -> Reservation { Reservation::Unique(self) } fn can_share(&self) -> bool { false } } #[test] fn pooled_drop_if_closed_doesnt_reinsert() { let pool = pool_no_timer(); let key = Arc::new("localhost:12345".to_string()); pool.pooled(c(key.clone()), CanClose { val: 57, closed: true, }); assert!(!pool.locked().idle.contains_key(&key)); } } hyper-0.12.35/src/client/tests.rs010066400017500001750000000212741353675567300150430ustar0000000000000000#![cfg(feature = "runtime")] extern crate pretty_env_logger; use futures::{Async, Future, Stream}; use futures::future::poll_fn; use futures::sync::oneshot; use tokio::runtime::current_thread::Runtime; use mock::MockConnector; use super::*; #[test] fn retryable_request() { let _ = pretty_env_logger::try_init(); let mut rt = Runtime::new().expect("new rt"); let mut connector = MockConnector::new(); let sock1 = connector.mock("http://mock.local"); let sock2 = connector.mock("http://mock.local"); let client = Client::builder() .build::<_, ::Body>(connector); client.pool.no_timer(); { let req = Request::builder() .uri("http://mock.local/a") .body(Default::default()) .unwrap(); let res1 = client.request(req); let srv1 = poll_fn(|| { try_ready!(sock1.read(&mut [0u8; 512])); try_ready!(sock1.write(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n")); Ok(Async::Ready(())) }).map_err(|e: ::std::io::Error| panic!("srv1 poll_fn error: {}", e)); rt.block_on(res1.join(srv1)).expect("res1"); } drop(sock1); let req = Request::builder() .uri("http://mock.local/b") .body(Default::default()) .unwrap(); let res2 = client.request(req) .map(|res| { assert_eq!(res.status().as_u16(), 222); }); let srv2 = poll_fn(|| { try_ready!(sock2.read(&mut [0u8; 512])); try_ready!(sock2.write(b"HTTP/1.1 222 OK\r\nContent-Length: 0\r\n\r\n")); Ok(Async::Ready(())) }).map_err(|e: ::std::io::Error| panic!("srv2 poll_fn error: {}", e)); rt.block_on(res2.join(srv2)).expect("res2"); } #[test] fn conn_reset_after_write() { let _ = pretty_env_logger::try_init(); let mut rt = Runtime::new().expect("new rt"); let mut connector = MockConnector::new(); let sock1 = connector.mock("http://mock.local"); let client = Client::builder() .build::<_, ::Body>(connector); client.pool.no_timer(); { let req = Request::builder() .uri("http://mock.local/a") .body(Default::default()) .unwrap(); let res1 = client.request(req); let srv1 = poll_fn(|| { try_ready!(sock1.read(&mut [0u8; 512])); try_ready!(sock1.write(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n")); Ok(Async::Ready(())) }).map_err(|e: ::std::io::Error| panic!("srv1 poll_fn error: {}", e)); rt.block_on(res1.join(srv1)).expect("res1"); } let req = Request::builder() .uri("http://mock.local/a") .body(Default::default()) .unwrap(); let res2 = client.request(req); let mut sock1 = Some(sock1); let srv2 = poll_fn(|| { // We purposefully keep the socket open until the client // has written the second request, and THEN disconnect. // // Not because we expect servers to be jerks, but to trigger // state where we write on an assumedly good connetion, and // only reset the close AFTER we wrote bytes. try_ready!(sock1.as_mut().unwrap().read(&mut [0u8; 512])); sock1.take(); Ok(Async::Ready(())) }).map_err(|e: ::std::io::Error| panic!("srv2 poll_fn error: {}", e)); let err = rt.block_on(res2.join(srv2)).expect_err("res2"); assert!(err.is_incomplete_message(), "{:?}", err); } #[test] fn checkout_win_allows_connect_future_to_be_pooled() { let _ = pretty_env_logger::try_init(); let mut rt = Runtime::new().expect("new rt"); let mut connector = MockConnector::new(); let (tx, rx) = oneshot::channel::<()>(); let sock1 = connector.mock("http://mock.local"); let sock2 = connector.mock_fut("http://mock.local", rx); let client = Client::builder() .build::<_, ::Body>(connector); client.pool.no_timer(); let uri = "http://mock.local/a".parse::<::Uri>().expect("uri parse"); // First request just sets us up to have a connection able to be put // back in the pool. *However*, it doesn't insert immediately. The // body has 1 pending byte, and we will only drain in request 2, once // the connect future has been started. let mut body = { let res1 = client.get(uri.clone()) .map(|res| res.into_body().concat2()); let srv1 = poll_fn(|| { try_ready!(sock1.read(&mut [0u8; 512])); // Chunked is used so as to force 2 body reads. try_ready!(sock1.write(b"\ HTTP/1.1 200 OK\r\n\ transfer-encoding: chunked\r\n\ \r\n\ 1\r\nx\r\n\ 0\r\n\r\n\ ")); Ok(Async::Ready(())) }).map_err(|e: ::std::io::Error| panic!("srv1 poll_fn error: {}", e)); rt.block_on(res1.join(srv1)).expect("res1").0 }; // The second request triggers the only mocked connect future, but then // the drained body allows the first socket to go back to the pool, // "winning" the checkout race. { let res2 = client.get(uri.clone()); let drain = poll_fn(move || { body.poll() }); let srv2 = poll_fn(|| { try_ready!(sock1.read(&mut [0u8; 512])); try_ready!(sock1.write(b"HTTP/1.1 200 OK\r\nConnection: close\r\n\r\nx")); Ok(Async::Ready(())) }).map_err(|e: ::std::io::Error| panic!("srv2 poll_fn error: {}", e)); rt.block_on(res2.join(drain).join(srv2)).expect("res2"); } // "Release" the mocked connect future, and let the runtime spin once so // it's all setup... { let mut tx = Some(tx); let client = &client; let key = client.pool.h1_key("http://mock.local"); let mut tick_cnt = 0; let fut = poll_fn(move || { tx.take(); if client.pool.idle_count(&key) == 0 { tick_cnt += 1; assert!(tick_cnt < 10, "ticked too many times waiting for idle"); trace!("no idle yet; tick count: {}", tick_cnt); ::futures::task::current().notify(); Ok(Async::NotReady) } else { Ok::<_, ()>(Async::Ready(())) } }); rt.block_on(fut).unwrap(); } // Third request just tests out that the "loser" connection was pooled. If // it isn't, this will panic since the MockConnector doesn't have any more // mocks to give out. { let res3 = client.get(uri); let srv3 = poll_fn(|| { try_ready!(sock2.read(&mut [0u8; 512])); try_ready!(sock2.write(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n")); Ok(Async::Ready(())) }).map_err(|e: ::std::io::Error| panic!("srv3 poll_fn error: {}", e)); rt.block_on(res3.join(srv3)).expect("res3"); } } #[cfg(feature = "nightly")] #[bench] fn bench_http1_get_0b(b: &mut test::Bencher) { let _ = pretty_env_logger::try_init(); let mut rt = Runtime::new().expect("new rt"); let mut connector = MockConnector::new(); let client = Client::builder() .build::<_, ::Body>(connector.clone()); client.pool.no_timer(); let uri = Uri::from_static("http://mock.local/a"); b.iter(move || { let sock1 = connector.mock("http://mock.local"); let res1 = client .get(uri.clone()) .and_then(|res| { res.into_body().for_each(|_| Ok(())) }); let srv1 = poll_fn(|| { try_ready!(sock1.read(&mut [0u8; 512])); try_ready!(sock1.write(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n")); Ok(Async::Ready(())) }).map_err(|e: ::std::io::Error| panic!("srv1 poll_fn error: {}", e)); rt.block_on(res1.join(srv1)).expect("res1"); }); } #[cfg(feature = "nightly")] #[bench] fn bench_http1_get_10b(b: &mut test::Bencher) { let _ = pretty_env_logger::try_init(); let mut rt = Runtime::new().expect("new rt"); let mut connector = MockConnector::new(); let client = Client::builder() .build::<_, ::Body>(connector.clone()); client.pool.no_timer(); let uri = Uri::from_static("http://mock.local/a"); b.iter(move || { let sock1 = connector.mock("http://mock.local"); let res1 = client .get(uri.clone()) .and_then(|res| { res.into_body().for_each(|_| Ok(())) }); let srv1 = poll_fn(|| { try_ready!(sock1.read(&mut [0u8; 512])); try_ready!(sock1.write(b"HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\n0123456789")); Ok(Async::Ready(())) }).map_err(|e: ::std::io::Error| panic!("srv1 poll_fn error: {}", e)); rt.block_on(res1.join(srv1)).expect("res1"); }); } hyper-0.12.35/src/common/buf.rs010066400017500001750000000012011346064762000144370ustar0000000000000000use bytes::Buf; use iovec::IoVec; /// A `Buf` wrapping a static byte slice. #[derive(Debug)] pub(crate) struct StaticBuf(pub(crate) &'static [u8]); impl Buf for StaticBuf { #[inline] fn remaining(&self) -> usize { self.0.len() } #[inline] fn bytes(&self) -> &[u8] { self.0 } #[inline] fn advance(&mut self, cnt: usize) { self.0 = &self.0[cnt..]; } #[inline] fn bytes_vec<'t>(&'t self, dst: &mut [&'t IoVec]) -> usize { if dst.is_empty() || self.0.is_empty() { 0 } else { dst[0] = self.0.into(); 1 } } } hyper-0.12.35/src/common/drain.rs010066400017500001750000000133101353675567300150000ustar0000000000000000use std::mem; use futures::{Async, Future, Poll, Stream}; use futures::future::Shared; use futures::sync::{mpsc, oneshot}; use super::Never; pub fn channel() -> (Signal, Watch) { let (tx, rx) = oneshot::channel(); let (drained_tx, drained_rx) = mpsc::channel(0); ( Signal { drained_rx, tx, }, Watch { drained_tx, rx: rx.shared(), }, ) } pub struct Signal { drained_rx: mpsc::Receiver, tx: oneshot::Sender<()>, } pub struct Draining { drained_rx: mpsc::Receiver, } #[derive(Clone)] pub struct Watch { drained_tx: mpsc::Sender, rx: Shared>, } #[allow(missing_debug_implementations)] pub struct Watching { future: F, state: State, watch: Watch, } enum State { Watch(F), Draining, } impl Signal { pub fn drain(self) -> Draining { let _ = self.tx.send(()); Draining { drained_rx: self.drained_rx, } } } impl Future for Draining { type Item = (); type Error = (); fn poll(&mut self) -> Poll { match try_ready!(self.drained_rx.poll()) { Some(never) => match never {}, None => Ok(Async::Ready(())), } } } impl Watch { pub fn watch(self, future: F, on_drain: FN) -> Watching where F: Future, FN: FnOnce(&mut F), { Watching { future, state: State::Watch(on_drain), watch: self, } } } impl Future for Watching where F: Future, FN: FnOnce(&mut F), { type Item = F::Item; type Error = F::Error; fn poll(&mut self) -> Poll { loop { match mem::replace(&mut self.state, State::Draining) { State::Watch(on_drain) => { match self.watch.rx.poll() { Ok(Async::Ready(_)) | Err(_) => { // Drain has been triggered! on_drain(&mut self.future); }, Ok(Async::NotReady) => { self.state = State::Watch(on_drain); return self.future.poll(); }, } }, State::Draining => { return self.future.poll(); }, } } } } #[cfg(test)] mod tests { use futures::{future, Async, Future, Poll}; use super::*; struct TestMe { draining: bool, finished: bool, poll_cnt: usize, } impl Future for TestMe { type Item = (); type Error = (); fn poll(&mut self) -> Poll { self.poll_cnt += 1; if self.finished { Ok(Async::Ready(())) } else { Ok(Async::NotReady) } } } #[test] fn watch() { future::lazy(|| { let (tx, rx) = channel(); let fut = TestMe { draining: false, finished: false, poll_cnt: 0, }; let mut watch = rx.watch(fut, |fut| { fut.draining = true; }); assert_eq!(watch.future.poll_cnt, 0); // First poll should poll the inner future assert!(watch.poll().unwrap().is_not_ready()); assert_eq!(watch.future.poll_cnt, 1); // Second poll should poll the inner future again assert!(watch.poll().unwrap().is_not_ready()); assert_eq!(watch.future.poll_cnt, 2); let mut draining = tx.drain(); // Drain signaled, but needs another poll to be noticed. assert!(!watch.future.draining); assert_eq!(watch.future.poll_cnt, 2); // Now, poll after drain has been signaled. assert!(watch.poll().unwrap().is_not_ready()); assert_eq!(watch.future.poll_cnt, 3); assert!(watch.future.draining); // Draining is not ready until watcher completes assert!(draining.poll().unwrap().is_not_ready()); // Finishing up the watch future watch.future.finished = true; assert!(watch.poll().unwrap().is_ready()); assert_eq!(watch.future.poll_cnt, 4); drop(watch); assert!(draining.poll().unwrap().is_ready()); Ok::<_, ()>(()) }).wait().unwrap(); } #[test] fn watch_clones() { future::lazy(|| { let (tx, rx) = channel(); let fut1 = TestMe { draining: false, finished: false, poll_cnt: 0, }; let fut2 = TestMe { draining: false, finished: false, poll_cnt: 0, }; let watch1 = rx.clone().watch(fut1, |fut| { fut.draining = true; }); let watch2 = rx.watch(fut2, |fut| { fut.draining = true; }); let mut draining = tx.drain(); // Still 2 outstanding watchers assert!(draining.poll().unwrap().is_not_ready()); // drop 1 for whatever reason drop(watch1); // Still not ready, 1 other watcher still pending assert!(draining.poll().unwrap().is_not_ready()); drop(watch2); // Now all watchers are gone, draining is complete assert!(draining.poll().unwrap().is_ready()); Ok::<_, ()>(()) }).wait().unwrap(); } } hyper-0.12.35/src/common/exec.rs010066400017500001750000000105231353675567300146320ustar0000000000000000use std::fmt; use std::sync::Arc; use futures::future::{Executor, Future}; use body::Payload; use proto::h2::server::H2Stream; use server::conn::spawn_all::{NewSvcTask, Watcher}; use service::Service; pub trait H2Exec: Clone { fn execute_h2stream(&self, fut: H2Stream) -> ::Result<()>; } pub trait NewSvcExec>: Clone { fn execute_new_svc(&self, fut: NewSvcTask) -> ::Result<()>; } // Either the user provides an executor for background tasks, or we use // `tokio::spawn`. #[derive(Clone)] pub enum Exec { Default, Executor(Arc + Send>> + Send + Sync>), } // ===== impl Exec ===== impl Exec { pub(crate) fn execute(&self, fut: F) -> ::Result<()> where F: Future + Send + 'static, { match *self { Exec::Default => { #[cfg(feature = "runtime")] { use std::error::Error as StdError; use ::tokio_executor::Executor; struct TokioSpawnError; impl fmt::Debug for TokioSpawnError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt("tokio::spawn failed (is a tokio runtime running this future?)", f) } } impl fmt::Display for TokioSpawnError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt("tokio::spawn failed (is a tokio runtime running this future?)", f) } } impl StdError for TokioSpawnError { fn description(&self) -> &str { "tokio::spawn failed" } } ::tokio_executor::DefaultExecutor::current() .spawn(Box::new(fut)) .map_err(|err| { warn!("executor error: {:?}", err); ::Error::new_execute(TokioSpawnError) }) } #[cfg(not(feature = "runtime"))] { // If no runtime, we need an executor! panic!("executor must be set") } }, Exec::Executor(ref e) => { e.execute(Box::new(fut)) .map_err(|err| { warn!("executor error: {:?}", err.kind()); ::Error::new_execute("custom executor failed") }) }, } } } impl fmt::Debug for Exec { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Exec") .finish() } } impl H2Exec for Exec where H2Stream: Future + Send + 'static, B: Payload, { fn execute_h2stream(&self, fut: H2Stream) -> ::Result<()> { self.execute(fut) } } impl NewSvcExec for Exec where NewSvcTask: Future + Send + 'static, S: Service, W: Watcher, { fn execute_new_svc(&self, fut: NewSvcTask) -> ::Result<()> { self.execute(fut) } } // ==== impl Executor ===== impl H2Exec for E where E: Executor> + Clone, H2Stream: Future, B: Payload, { fn execute_h2stream(&self, fut: H2Stream) -> ::Result<()> { self.execute(fut) .map_err(|err| { warn!("executor error: {:?}", err.kind()); ::Error::new_execute("custom executor failed") }) } } impl NewSvcExec for E where E: Executor> + Clone, NewSvcTask: Future, S: Service, W: Watcher, { fn execute_new_svc(&self, fut: NewSvcTask) -> ::Result<()> { self.execute(fut) .map_err(|err| { warn!("executor error: {:?}", err.kind()); ::Error::new_execute("custom executor failed") }) } } // ===== StdError impls ===== hyper-0.12.35/src/common/io/mod.rs010066400017500001750000000000621346064762000150550ustar0000000000000000mod rewind; pub(crate) use self::rewind::Rewind; hyper-0.12.35/src/common/io/rewind.rs010066400017500001750000000141611353675567300156070ustar0000000000000000use std::cmp; use std::io::{self, Read, Write}; use bytes::{Buf, BufMut, Bytes, IntoBuf}; use futures::{Async, Poll}; use tokio_io::{AsyncRead, AsyncWrite}; /// Combine a buffer with an IO, rewinding reads to use the buffer. #[derive(Debug)] pub(crate) struct Rewind { pre: Option, inner: T, } impl Rewind { pub(crate) fn new(io: T) -> Self { Rewind { pre: None, inner: io, } } pub(crate) fn new_buffered(io: T, buf: Bytes) -> Self { Rewind { pre: Some(buf), inner: io, } } pub(crate) fn rewind(&mut self, bs: Bytes) { debug_assert!(self.pre.is_none()); self.pre = Some(bs); } pub(crate) fn into_inner(self) -> (T, Bytes) { (self.inner, self.pre.unwrap_or_else(Bytes::new)) } } impl Read for Rewind where T: Read, { #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { if let Some(pre_bs) = self.pre.take() { // If there are no remaining bytes, let the bytes get dropped. if pre_bs.len() > 0 { let mut pre_reader = pre_bs.into_buf().reader(); let read_cnt = pre_reader.read(buf)?; let mut new_pre = pre_reader.into_inner().into_inner(); new_pre.advance(read_cnt); // Put back whats left if new_pre.len() > 0 { self.pre = Some(new_pre); } return Ok(read_cnt); } } self.inner.read(buf) } } impl Write for Rewind where T: Write, { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { self.inner.write(buf) } #[inline] fn flush(&mut self) -> io::Result<()> { self.inner.flush() } } impl AsyncRead for Rewind where T: AsyncRead, { #[inline] unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { self.inner.prepare_uninitialized_buffer(buf) } #[inline] fn read_buf(&mut self, buf: &mut B) -> Poll { if let Some(bs) = self.pre.take() { let pre_len = bs.len(); // If there are no remaining bytes, let the bytes get dropped. if pre_len > 0 { let cnt = cmp::min(buf.remaining_mut(), pre_len); let pre_buf = bs.into_buf(); let mut xfer = Buf::take(pre_buf, cnt); buf.put(&mut xfer); let mut new_pre = xfer.into_inner().into_inner(); new_pre.advance(cnt); // Put back whats left if new_pre.len() > 0 { self.pre = Some(new_pre); } return Ok(Async::Ready(cnt)); } } self.inner.read_buf(buf) } } impl AsyncWrite for Rewind where T: AsyncWrite, { #[inline] fn shutdown(&mut self) -> Poll<(), io::Error> { AsyncWrite::shutdown(&mut self.inner) } #[inline] fn write_buf(&mut self, buf: &mut B) -> Poll { self.inner.write_buf(buf) } } #[cfg(test)] mod tests { use super::*; extern crate tokio_mockstream; use self::tokio_mockstream::MockStream; use std::io::Cursor; // Test a partial rewind #[test] fn async_partial_rewind() { let bs = &mut [104, 101, 108, 108, 111]; let o1 = &mut [0, 0]; let o2 = &mut [0, 0, 0, 0, 0]; let mut stream = Rewind::new(MockStream::new(bs)); let mut o1_cursor = Cursor::new(o1); // Read off some bytes, ensure we filled o1 match stream.read_buf(&mut o1_cursor).unwrap() { Async::NotReady => panic!("should be ready"), Async::Ready(cnt) => assert_eq!(2, cnt), } // Rewind the stream so that it is as if we never read in the first place. let read_buf = Bytes::from(&o1_cursor.into_inner()[..]); stream.rewind(read_buf); // We poll 2x here since the first time we'll only get what is in the // prefix (the rewinded part) of the Rewind.\ let mut o2_cursor = Cursor::new(o2); stream.read_buf(&mut o2_cursor).unwrap(); stream.read_buf(&mut o2_cursor).unwrap(); let o2_final = o2_cursor.into_inner(); // At this point we should have read everything that was in the MockStream assert_eq!(&o2_final, &bs); } // Test a full rewind #[test] fn async_full_rewind() { let bs = &mut [104, 101, 108, 108, 111]; let o1 = &mut [0, 0, 0, 0, 0]; let o2 = &mut [0, 0, 0, 0, 0]; let mut stream = Rewind::new(MockStream::new(bs)); let mut o1_cursor = Cursor::new(o1); match stream.read_buf(&mut o1_cursor).unwrap() { Async::NotReady => panic!("should be ready"), Async::Ready(cnt) => assert_eq!(5, cnt), } let read_buf = Bytes::from(&o1_cursor.into_inner()[..]); stream.rewind(read_buf); let mut o2_cursor = Cursor::new(o2); stream.read_buf(&mut o2_cursor).unwrap(); stream.read_buf(&mut o2_cursor).unwrap(); let o2_final = o2_cursor.into_inner(); assert_eq!(&o2_final, &bs); } #[test] fn partial_rewind() { let bs = &mut [104, 101, 108, 108, 111]; let o1 = &mut [0, 0]; let o2 = &mut [0, 0, 0, 0, 0]; let mut stream = Rewind::new(MockStream::new(bs)); stream.read(o1).unwrap(); let read_buf = Bytes::from(&o1[..]); stream.rewind(read_buf); let cnt = stream.read(o2).unwrap(); stream.read(&mut o2[cnt..]).unwrap(); assert_eq!(&o2, &bs); } #[test] fn full_rewind() { let bs = &mut [104, 101, 108, 108, 111]; let o1 = &mut [0, 0, 0, 0, 0]; let o2 = &mut [0, 0, 0, 0, 0]; let mut stream = Rewind::new(MockStream::new(bs)); stream.read(o1).unwrap(); let read_buf = Bytes::from(&o1[..]); stream.rewind(read_buf); let cnt = stream.read(o2).unwrap(); stream.read(&mut o2[cnt..]).unwrap(); assert_eq!(&o2, &bs); } } hyper-0.12.35/src/common/lazy.rs010066400017500001750000000026241353675567300146700ustar0000000000000000use std::mem; use futures::{Future, IntoFuture, Poll}; pub(crate) trait Started: Future { fn started(&self) -> bool; } pub(crate) fn lazy(func: F) -> Lazy where F: FnOnce() -> R, R: IntoFuture, { Lazy { inner: Inner::Init(func), } } // FIXME: allow() required due to `impl Trait` leaking types to this lint #[allow(missing_debug_implementations)] pub(crate) struct Lazy { inner: Inner } enum Inner { Init(F), Fut(R), Empty, } impl Started for Lazy where F: FnOnce() -> R, R: IntoFuture, { fn started(&self) -> bool { match self.inner { Inner::Init(_) => false, Inner::Fut(_) | Inner::Empty => true, } } } impl Future for Lazy where F: FnOnce() -> R, R: IntoFuture, { type Item = R::Item; type Error = R::Error; fn poll(&mut self) -> Poll { match self.inner { Inner::Fut(ref mut f) => return f.poll(), _ => (), } match mem::replace(&mut self.inner, Inner::Empty) { Inner::Init(func) => { let mut fut = func().into_future(); let ret = fut.poll(); self.inner = Inner::Fut(fut); ret }, _ => unreachable!("lazy state wrong"), } } } hyper-0.12.35/src/common/mod.rs010066400017500001750000000004551353675567300144700ustar0000000000000000mod buf; pub(crate) mod drain; pub(crate) mod exec; pub(crate) mod io; mod lazy; mod never; pub(crate) mod task; pub(crate) use self::buf::StaticBuf; pub(crate) use self::exec::Exec; pub(crate) use self::lazy::{lazy, Started as Lazy}; pub use self::never::Never; pub(crate) use self::task::YieldNow; hyper-0.12.35/src/common/never.rs010066400017500001750000000006111353675567300150220ustar0000000000000000//! An uninhabitable type meaning it can never happen. //! //! To be replaced with `!` once it is stable. use std::error::Error; use std::fmt; #[derive(Debug)] pub enum Never {} impl fmt::Display for Never { fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { match *self {} } } impl Error for Never { fn description(&self) -> &str { match *self {} } } hyper-0.12.35/src/common/task.rs010066400017500001750000000021651353675567300146530ustar0000000000000000use futures::{Async, Poll, task::Task}; use super::Never; /// A type to help "yield" a future, such that it is re-scheduled immediately. /// /// Useful for spin counts, so a future doesn't hog too much time. #[derive(Debug)] pub(crate) struct YieldNow { cached_task: Option, } impl YieldNow { pub(crate) fn new() -> YieldNow { YieldNow { cached_task: None, } } /// Returns `Ok(Async::NotReady)` always, while also notifying the /// current task so that it is rescheduled immediately. /// /// Since it never returns `Async::Ready` or `Err`, those types are /// set to `Never`. pub(crate) fn poll_yield(&mut self) -> Poll { // Check for a cached `Task` first... if let Some(ref t) = self.cached_task { if t.will_notify_current() { t.notify(); return Ok(Async::NotReady); } } // No cached task, or not current, so get a new one... let t = ::futures::task::current(); t.notify(); self.cached_task = Some(t); Ok(Async::NotReady) } } hyper-0.12.35/src/error.rs010066400017500001750000000344611353675572100135500ustar0000000000000000//! Error and Result module. use std::error::Error as StdError; use std::fmt; use std::io; use httparse; use http; use h2; /// Result type often returned from methods that can have hyper `Error`s. pub type Result = ::std::result::Result; type Cause = Box; /// Represents errors that can occur handling HTTP streams. pub struct Error { inner: Box, } struct ErrorImpl { kind: Kind, cause: Option, } #[derive(Debug, PartialEq)] pub(crate) enum Kind { Parse(Parse), User(User), /// A message reached EOF, but is not complete. IncompleteMessage, /// A connection received a message (or bytes) when not waiting for one. UnexpectedMessage, /// A pending item was dropped before ever being processed. Canceled, /// Indicates a channel (client or body sender) is closed. ChannelClosed, /// An `io::Error` that occurred while trying to read or write to a network stream. Io, /// Error occurred while connecting. Connect, /// Error creating a TcpListener. #[cfg(feature = "runtime")] Listen, /// Error accepting on an Incoming stream. Accept, /// Error while reading a body from connection. Body, /// Error while writing a body to connection. BodyWrite, /// The body write was aborted. BodyWriteAborted, /// Error calling AsyncWrite::shutdown() Shutdown, /// A general error from h2. Http2, } #[derive(Debug, PartialEq)] pub(crate) enum Parse { Method, Version, VersionH2, Uri, Header, TooLarge, Status, } #[derive(Debug, PartialEq)] pub(crate) enum User { /// Error calling user's Payload::poll_data(). Body, /// Error calling user's MakeService. MakeService, /// Error from future of user's Service. Service, /// User tried to send a certain header in an unexpected context. /// /// For example, sending both `content-length` and `transfer-encoding`. UnexpectedHeader, /// User tried to create a Request with bad version. UnsupportedVersion, /// User tried to create a CONNECT Request with the Client. UnsupportedRequestMethod, /// User tried to respond with a 1xx (not 101) response code. UnsupportedStatusCode, /// User tried to send a Request with Client with non-absolute URI. AbsoluteUriRequired, /// User tried polling for an upgrade that doesn't exist. NoUpgrade, /// User polled for an upgrade, but low-level API is not using upgrades. ManualUpgrade, /// Error trying to call `Executor::execute`. Execute, } impl Error { /// Returns true if this was an HTTP parse error. pub fn is_parse(&self) -> bool { match self.inner.kind { Kind::Parse(_) => true, _ => false, } } /// Returns true if this error was caused by user code. pub fn is_user(&self) -> bool { match self.inner.kind { Kind::User(_) => true, _ => false, } } /// Returns true if this was about a `Request` that was canceled. pub fn is_canceled(&self) -> bool { self.inner.kind == Kind::Canceled } /// Returns true if a sender's channel is closed. pub fn is_closed(&self) -> bool { self.inner.kind == Kind::ChannelClosed } /// Returns true if this was an error from `Connect`. pub fn is_connect(&self) -> bool { self.inner.kind == Kind::Connect } /// Returns true if the connection closed before a message could complete. pub fn is_incomplete_message(&self) -> bool { self.inner.kind == Kind::IncompleteMessage } /// Returns true if the body write was aborted. pub fn is_body_write_aborted(&self) -> bool { self.inner.kind == Kind::BodyWriteAborted } #[doc(hidden)] #[cfg_attr(error_source, deprecated(note = "use Error::source instead"))] pub fn cause2(&self) -> Option<&(dyn StdError + 'static + Sync + Send)> { self.inner.cause.as_ref().map(|e| &**e) } /// Consumes the error, returning its cause. pub fn into_cause(self) -> Option> { self.inner.cause } pub(crate) fn new(kind: Kind) -> Error { Error { inner: Box::new(ErrorImpl { kind, cause: None, }), } } pub(crate) fn with>(mut self, cause: C) -> Error { self.inner.cause = Some(cause.into()); self } pub(crate) fn kind(&self) -> &Kind { &self.inner.kind } #[cfg(not(error_source))] pub(crate) fn h2_reason(&self) -> h2::Reason { // Since we don't have access to `Error::source`, we can only // look so far... let mut cause = self.cause2(); while let Some(err) = cause { if let Some(h2_err) = err.downcast_ref::() { return h2_err .reason() .unwrap_or(h2::Reason::INTERNAL_ERROR); } cause = err .downcast_ref::() .and_then(Error::cause2); } // else h2::Reason::INTERNAL_ERROR } #[cfg(error_source)] pub(crate) fn h2_reason(&self) -> h2::Reason { // Find an h2::Reason somewhere in the cause stack, if it exists, // otherwise assume an INTERNAL_ERROR. let mut cause = self.source(); while let Some(err) = cause { if let Some(h2_err) = err.downcast_ref::() { return h2_err .reason() .unwrap_or(h2::Reason::INTERNAL_ERROR); } cause = err.source(); } // else h2::Reason::INTERNAL_ERROR } pub(crate) fn new_canceled() -> Error { Error::new(Kind::Canceled) } pub(crate) fn new_incomplete() -> Error { Error::new(Kind::IncompleteMessage) } pub(crate) fn new_too_large() -> Error { Error::new(Kind::Parse(Parse::TooLarge)) } pub(crate) fn new_version_h2() -> Error { Error::new(Kind::Parse(Parse::VersionH2)) } pub(crate) fn new_unexpected_message() -> Error { Error::new(Kind::UnexpectedMessage) } pub(crate) fn new_io(cause: io::Error) -> Error { Error::new(Kind::Io).with(cause) } #[cfg(feature = "runtime")] pub(crate) fn new_listen>(cause: E) -> Error { Error::new(Kind::Listen).with(cause) } pub(crate) fn new_accept>(cause: E) -> Error { Error::new(Kind::Accept).with(cause) } pub(crate) fn new_connect>(cause: E) -> Error { Error::new(Kind::Connect).with(cause) } pub(crate) fn new_closed() -> Error { Error::new(Kind::ChannelClosed) } pub(crate) fn new_body>(cause: E) -> Error { Error::new(Kind::Body).with(cause) } pub(crate) fn new_body_write>(cause: E) -> Error { Error::new(Kind::BodyWrite).with(cause) } pub(crate) fn new_body_write_aborted() -> Error { Error::new(Kind::BodyWriteAborted) } fn new_user(user: User) -> Error { Error::new(Kind::User(user)) } pub(crate) fn new_user_header() -> Error { Error::new_user(User::UnexpectedHeader) } pub(crate) fn new_user_unsupported_version() -> Error { Error::new_user(User::UnsupportedVersion) } pub(crate) fn new_user_unsupported_request_method() -> Error { Error::new_user(User::UnsupportedRequestMethod) } pub(crate) fn new_user_unsupported_status_code() -> Error { Error::new_user(User::UnsupportedStatusCode) } pub(crate) fn new_user_absolute_uri_required() -> Error { Error::new_user(User::AbsoluteUriRequired) } pub(crate) fn new_user_no_upgrade() -> Error { Error::new_user(User::NoUpgrade) } pub(crate) fn new_user_manual_upgrade() -> Error { Error::new_user(User::ManualUpgrade) } pub(crate) fn new_user_make_service>(cause: E) -> Error { Error::new_user(User::MakeService).with(cause) } pub(crate) fn new_user_service>(cause: E) -> Error { Error::new_user(User::Service).with(cause) } pub(crate) fn new_user_body>(cause: E) -> Error { Error::new_user(User::Body).with(cause) } pub(crate) fn new_shutdown(cause: io::Error) -> Error { Error::new(Kind::Shutdown).with(cause) } pub(crate) fn new_execute>(cause: E) -> Error { Error::new_user(User::Execute).with(cause) } pub(crate) fn new_h2(cause: ::h2::Error) -> Error { if cause.is_io() { Error::new_io(cause.into_io().expect("h2::Error::is_io")) } else { Error::new(Kind::Http2).with(cause) } } } impl fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut f = f.debug_tuple("Error"); f.field(&self.inner.kind); if let Some(ref cause) = self.inner.cause { f.field(cause); } f.finish() } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if let Some(ref cause) = self.inner.cause { write!(f, "{}: {}", self.description(), cause) } else { f.write_str(self.description()) } } } impl StdError for Error { fn description(&self) -> &str { match self.inner.kind { Kind::Parse(Parse::Method) => "invalid HTTP method parsed", Kind::Parse(Parse::Version) => "invalid HTTP version parsed", Kind::Parse(Parse::VersionH2) => "invalid HTTP version parsed (found HTTP2 preface)", Kind::Parse(Parse::Uri) => "invalid URI", Kind::Parse(Parse::Header) => "invalid HTTP header parsed", Kind::Parse(Parse::TooLarge) => "message head is too large", Kind::Parse(Parse::Status) => "invalid HTTP status-code parsed", Kind::IncompleteMessage => "connection closed before message completed", Kind::UnexpectedMessage => "received unexpected message from connection", Kind::ChannelClosed => "channel closed", Kind::Connect => "error trying to connect", Kind::Canceled => "operation was canceled", #[cfg(feature = "runtime")] Kind::Listen => "error creating server listener", Kind::Accept => "error accepting connection", Kind::Body => "error reading a body from connection", Kind::BodyWrite => "error writing a body to connection", Kind::BodyWriteAborted => "body write aborted", Kind::Shutdown => "error shutting down connection", Kind::Http2 => "http2 error", Kind::Io => "connection error", Kind::User(User::Body) => "error from user's Payload stream", Kind::User(User::MakeService) => "error from user's MakeService", Kind::User(User::Service) => "error from user's Service", Kind::User(User::UnexpectedHeader) => "user sent unexpected header", Kind::User(User::UnsupportedVersion) => "request has unsupported HTTP version", Kind::User(User::UnsupportedRequestMethod) => "request has unsupported HTTP method", Kind::User(User::UnsupportedStatusCode) => "response has 1xx status code, not supported by server", Kind::User(User::AbsoluteUriRequired) => "client requires absolute-form URIs", Kind::User(User::NoUpgrade) => "no upgrade available", Kind::User(User::ManualUpgrade) => "upgrade expected but low level API in use", Kind::User(User::Execute) => "executor failed to spawn task", } } #[cfg(not(error_source))] fn cause(&self) -> Option<&StdError> { self .inner .cause .as_ref() .map(|cause| &**cause as &StdError) } #[cfg(error_source)] fn source(&self) -> Option<&(dyn StdError + 'static)> { self .inner .cause .as_ref() .map(|cause| &**cause as &(dyn StdError + 'static)) } } #[doc(hidden)] impl From for Error { fn from(err: Parse) -> Error { Error::new(Kind::Parse(err)) } } impl From for Parse { fn from(err: httparse::Error) -> Parse { match err { httparse::Error::HeaderName | httparse::Error::HeaderValue | httparse::Error::NewLine | httparse::Error::Token => Parse::Header, httparse::Error::Status => Parse::Status, httparse::Error::TooManyHeaders => Parse::TooLarge, httparse::Error::Version => Parse::Version, } } } impl From for Parse { fn from(_: http::method::InvalidMethod) -> Parse { Parse::Method } } impl From for Parse { fn from(_: http::status::InvalidStatusCode) -> Parse { Parse::Status } } impl From for Parse { fn from(_: http::uri::InvalidUri) -> Parse { Parse::Uri } } impl From for Parse { fn from(_: http::uri::InvalidUriBytes) -> Parse { Parse::Uri } } impl From for Parse { fn from(_: http::uri::InvalidUriParts) -> Parse { Parse::Uri } } #[doc(hidden)] trait AssertSendSync: Send + Sync + 'static {} #[doc(hidden)] impl AssertSendSync for Error {} #[cfg(test)] mod tests { use std::mem; use super::*; #[test] fn error_size_of() { assert_eq!(mem::size_of::(), mem::size_of::()); } #[test] fn h2_reason_unknown() { let closed = Error::new_closed(); assert_eq!(closed.h2_reason(), h2::Reason::INTERNAL_ERROR); } #[test] fn h2_reason_one_level() { let body_err = Error::new_user_body(h2::Error::from(h2::Reason::ENHANCE_YOUR_CALM)); assert_eq!(body_err.h2_reason(), h2::Reason::ENHANCE_YOUR_CALM); } #[test] fn h2_reason_nested() { let recvd = Error::new_h2(h2::Error::from(h2::Reason::HTTP_1_1_REQUIRED)); // Suppose a user were proxying the received error let svc_err = Error::new_user_service(recvd); assert_eq!(svc_err.h2_reason(), h2::Reason::HTTP_1_1_REQUIRED); } } hyper-0.12.35/src/headers.rs010066400017500001750000000064621353675567300140400ustar0000000000000000use bytes::BytesMut; use http::HeaderMap; use http::header::{CONTENT_LENGTH, TRANSFER_ENCODING}; use http::header::{HeaderValue, OccupiedEntry, ValueIter}; pub fn connection_keep_alive(value: &HeaderValue) -> bool { connection_has(value, "keep-alive") } pub fn connection_close(value: &HeaderValue) -> bool { connection_has(value, "close") } fn connection_has(value: &HeaderValue, needle: &str) -> bool { if let Ok(s) = value.to_str() { for val in s.split(',') { if val.trim().eq_ignore_ascii_case(needle) { return true; } } } false } pub fn content_length_parse(value: &HeaderValue) -> Option { value .to_str() .ok() .and_then(|s| s.parse().ok()) } pub fn content_length_parse_all(headers: &HeaderMap) -> Option { content_length_parse_all_values(headers.get_all(CONTENT_LENGTH).into_iter()) } pub fn content_length_parse_all_values(values: ValueIter) -> Option { // If multiple Content-Length headers were sent, everything can still // be alright if they all contain the same value, and all parse // correctly. If not, then it's an error. let folded = values .fold(None, |prev, line| match prev { Some(Ok(prev)) => { Some(line .to_str() .map_err(|_| ()) .and_then(|s| s.parse().map_err(|_| ())) .and_then(|n| if prev == n { Ok(n) } else { Err(()) })) }, None => { Some(line .to_str() .map_err(|_| ()) .and_then(|s| s.parse().map_err(|_| ()))) }, Some(Err(())) => Some(Err(())), }); if let Some(Ok(n)) = folded { Some(n) } else { None } } pub fn set_content_length_if_missing(headers: &mut HeaderMap, len: u64) { headers .entry(CONTENT_LENGTH) .unwrap() .or_insert_with(|| HeaderValue::from(len)); } pub fn transfer_encoding_is_chunked(headers: &HeaderMap) -> bool { is_chunked(headers.get_all(TRANSFER_ENCODING).into_iter()) } pub fn is_chunked(mut encodings: ValueIter) -> bool { // chunked must always be the last encoding, according to spec if let Some(line) = encodings.next_back() { return is_chunked_(line); } false } pub fn is_chunked_(value: &HeaderValue) -> bool { // chunked must always be the last encoding, according to spec if let Ok(s) = value.to_str() { if let Some(encoding) = s.rsplit(',').next() { return encoding.trim().eq_ignore_ascii_case("chunked"); } } false } pub fn add_chunked(mut entry: OccupiedEntry) { const CHUNKED: &'static str = "chunked"; if let Some(line) = entry.iter_mut().next_back() { // + 2 for ", " let new_cap = line.as_bytes().len() + CHUNKED.len() + 2; let mut buf = BytesMut::with_capacity(new_cap); buf.copy_from_slice(line.as_bytes()); buf.copy_from_slice(b", "); buf.copy_from_slice(CHUNKED.as_bytes()); *line = HeaderValue::from_shared(buf.freeze()) .expect("original header value plus ascii is valid"); return; } entry.insert(HeaderValue::from_static(CHUNKED)); } hyper-0.12.35/src/lib.rs010066400017500001750000000035371353675576700131770ustar0000000000000000#![doc(html_root_url = "https://docs.rs/hyper/0.12.35")] #![deny(missing_docs)] #![deny(missing_debug_implementations)] #![cfg_attr(test, deny(warnings))] #![cfg_attr(all(test, feature = "nightly"), feature(test))] //! # hyper //! //! hyper is a **fast** and **correct** HTTP implementation written in and for Rust. //! //! hyper provides both a [Client](client/index.html) and a //! [Server](server/index.html). //! //! If just starting out, **check out the [Guides](https://hyper.rs/guides) //! first.** //! //! If looking for just a convenient HTTP client, consider the //! [reqwest](https://crates.io/crates/reqwest) crate. extern crate bytes; #[macro_use] extern crate futures; #[cfg(feature = "runtime")] extern crate futures_cpupool; extern crate h2; #[doc(hidden)] pub extern crate http; extern crate http_body; extern crate httparse; extern crate iovec; extern crate itoa; #[macro_use] extern crate log; #[cfg(feature = "runtime")] extern crate net2; extern crate time; #[cfg(feature = "runtime")] extern crate tokio; extern crate tokio_buf; #[cfg(feature = "runtime")] extern crate tokio_executor; #[macro_use] extern crate tokio_io; #[cfg(feature = "runtime")] extern crate tokio_reactor; #[cfg(feature = "runtime")] extern crate tokio_tcp; #[cfg(feature = "runtime")] extern crate tokio_threadpool; #[cfg(feature = "runtime")] extern crate tokio_timer; extern crate want; #[cfg(all(test, feature = "nightly"))] extern crate test; pub use http::{ header, HeaderMap, Method, Request, Response, StatusCode, Uri, Version, }; pub use client::Client; pub use error::{Result, Error}; pub use body::{Body, Chunk}; pub use server::Server; #[macro_use] mod common; #[cfg(test)] mod mock; pub mod body; pub mod client; pub mod error; mod headers; mod proto; pub mod server; pub mod service; #[cfg(feature = "runtime")] pub mod rt; pub mod upgrade; hyper-0.12.35/src/mock.rs010066400017500001750000000324611353675567300133540ustar0000000000000000#[cfg(feature = "runtime")] use std::collections::HashMap; use std::cmp; use std::io::{self, Read, Write}; #[cfg(feature = "runtime")] use std::sync::{Arc, Mutex}; use bytes::Buf; use futures::{Async, Poll}; #[cfg(feature = "runtime")] use futures::Future; use futures::task::{self, Task}; use tokio_io::{AsyncRead, AsyncWrite}; #[cfg(feature = "runtime")] use ::client::connect::{Connect, Connected, Destination}; #[derive(Debug)] pub struct MockCursor { vec: Vec, pos: usize, } impl MockCursor { pub fn wrap(vec: Vec) -> MockCursor { MockCursor { vec: vec, pos: 0, } } } impl ::std::ops::Deref for MockCursor { type Target = [u8]; fn deref(&self) -> &[u8] { &self.vec } } impl AsRef<[u8]> for MockCursor { fn as_ref(&self) -> &[u8] { &self.vec } } impl> PartialEq for MockCursor { fn eq(&self, other: &S) -> bool { self.vec == other.as_ref() } } impl Write for MockCursor { fn write(&mut self, data: &[u8]) -> io::Result { trace!("MockCursor::write; len={}", data.len()); self.vec.extend(data); Ok(data.len()) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } impl Read for MockCursor { fn read(&mut self, buf: &mut [u8]) -> io::Result { (&self.vec[self.pos..]).read(buf).map(|n| { trace!("MockCursor::read; len={}", n); self.pos += n; if self.pos == self.vec.len() { trace!("MockCursor::read to end, clearing"); self.pos = 0; self.vec.clear(); } n }) } } const READ_VECS_CNT: usize = 64; #[derive(Debug)] pub struct AsyncIo { blocked: bool, bytes_until_block: usize, error: Option, flushed: bool, inner: T, max_read_vecs: usize, num_writes: usize, panic: bool, park_tasks: bool, task: Option, } impl AsyncIo { pub fn new(inner: T, bytes: usize) -> AsyncIo { AsyncIo { blocked: false, bytes_until_block: bytes, error: None, flushed: false, inner: inner, max_read_vecs: READ_VECS_CNT, num_writes: 0, panic: false, park_tasks: false, task: None, } } pub fn block_in(&mut self, bytes: usize) { self.bytes_until_block = bytes; if let Some(task) = self.task.take() { task.notify(); } } pub fn error(&mut self, err: io::Error) { self.error = Some(err); } #[cfg(feature = "nightly")] pub fn panic(&mut self) { self.panic = true; } pub fn max_read_vecs(&mut self, cnt: usize) { assert!(cnt <= READ_VECS_CNT); self.max_read_vecs = cnt; } #[cfg(feature = "runtime")] pub fn park_tasks(&mut self, enabled: bool) { self.park_tasks = enabled; } /* pub fn flushed(&self) -> bool { self.flushed } */ pub fn blocked(&self) -> bool { self.blocked } pub fn num_writes(&self) -> usize { self.num_writes } fn would_block(&mut self) -> io::Error { self.blocked = true; if self.park_tasks { self.task = Some(task::current()); } io::ErrorKind::WouldBlock.into() } } impl AsyncIo { pub fn new_buf>>(buf: T, bytes: usize) -> AsyncIo { AsyncIo::new(MockCursor::wrap(buf.into()), bytes) } /* pub fn new_eof() -> AsyncIo { AsyncIo::new(Buf::wrap(Vec::new().into()), 1) } */ #[cfg(feature = "runtime")] fn close(&mut self) { self.block_in(1); assert_eq!( self.inner.vec.len(), self.inner.pos, "AsyncIo::close(), but cursor not consumed", ); self.inner.vec.truncate(0); self.inner.pos = 0; } } impl AsyncIo { fn write_no_vecs(&mut self, buf: &mut B) -> Poll { if !buf.has_remaining() { return Ok(Async::Ready(0)); } let n = try_nb!(self.write(buf.bytes())); buf.advance(n); Ok(Async::Ready(n)) } } impl, T: AsRef<[u8]>> PartialEq for AsyncIo { fn eq(&self, other: &S) -> bool { self.inner.as_ref() == other.as_ref() } } impl Read for AsyncIo { fn read(&mut self, buf: &mut [u8]) -> io::Result { assert!(!self.panic, "AsyncIo::read panic"); self.blocked = false; if let Some(err) = self.error.take() { Err(err) } else if self.bytes_until_block == 0 { Err(self.would_block()) } else { let n = cmp::min(self.bytes_until_block, buf.len()); let n = self.inner.read(&mut buf[..n])?; self.bytes_until_block -= n; Ok(n) } } } impl Write for AsyncIo { fn write(&mut self, data: &[u8]) -> io::Result { assert!(!self.panic, "AsyncIo::write panic"); self.num_writes += 1; if let Some(err) = self.error.take() { trace!("AsyncIo::write error"); Err(err) } else if self.bytes_until_block == 0 { trace!("AsyncIo::write would block"); Err(self.would_block()) } else { trace!("AsyncIo::write; {} bytes", data.len()); self.flushed = false; let n = cmp::min(self.bytes_until_block, data.len()); let n = self.inner.write(&data[..n])?; self.bytes_until_block -= n; Ok(n) } } fn flush(&mut self) -> io::Result<()> { self.flushed = true; self.inner.flush() } } impl AsyncRead for AsyncIo { } impl AsyncWrite for AsyncIo { fn shutdown(&mut self) -> Poll<(), io::Error> { Ok(().into()) } fn write_buf(&mut self, buf: &mut B) -> Poll { assert!(!self.panic, "AsyncIo::write_buf panic"); if self.max_read_vecs == 0 { return self.write_no_vecs(buf); } let r = { static DUMMY: &[u8] = &[0]; let mut bufs = [From::from(DUMMY); READ_VECS_CNT]; let i = Buf::bytes_vec(&buf, &mut bufs[..self.max_read_vecs]); let mut n = 0; let mut ret = Ok(0); // each call to write() will increase our count, but we assume // that if iovecs are used, its really only 1 write call. let num_writes = self.num_writes; for iovec in &bufs[..i] { match self.write(iovec) { Ok(num) => { n += num; ret = Ok(n); }, Err(e) => { if e.kind() == io::ErrorKind::WouldBlock { if let Ok(0) = ret { ret = Err(e); } } else { ret = Err(e); } break; } } } self.num_writes = num_writes + 1; ret }; match r { Ok(n) => { Buf::advance(buf, n); Ok(Async::Ready(n)) } Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { Ok(Async::NotReady) } Err(e) => Err(e), } } } impl ::std::ops::Deref for AsyncIo { type Target = [u8]; fn deref(&self) -> &[u8] { &self.inner } } #[cfg(feature = "runtime")] pub struct Duplex { inner: Arc>, } #[cfg(feature = "runtime")] struct DuplexInner { handle_read_task: Option, read: AsyncIo, write: AsyncIo, } #[cfg(feature = "runtime")] impl Duplex { pub(crate) fn channel() -> (Duplex, DuplexHandle) { let mut inner = DuplexInner { handle_read_task: None, read: AsyncIo::new_buf(Vec::new(), 0), write: AsyncIo::new_buf(Vec::new(), ::std::usize::MAX), }; inner.read.park_tasks(true); inner.write.park_tasks(true); let inner = Arc::new(Mutex::new(inner)); let duplex = Duplex { inner: inner.clone(), }; let handle = DuplexHandle { inner: inner, }; (duplex, handle) } } #[cfg(feature = "runtime")] impl Read for Duplex { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.lock().unwrap().read.read(buf) } } #[cfg(feature = "runtime")] impl Write for Duplex { fn write(&mut self, buf: &[u8]) -> io::Result { let mut inner = self.inner.lock().unwrap(); let ret = inner.write.write(buf); if let Some(task) = inner.handle_read_task.take() { trace!("waking DuplexHandle read"); task.notify(); } ret } fn flush(&mut self) -> io::Result<()> { self.inner.lock().unwrap().write.flush() } } #[cfg(feature = "runtime")] impl AsyncRead for Duplex { } #[cfg(feature = "runtime")] impl AsyncWrite for Duplex { fn shutdown(&mut self) -> Poll<(), io::Error> { Ok(().into()) } fn write_buf(&mut self, buf: &mut B) -> Poll { let mut inner = self.inner.lock().unwrap(); if let Some(task) = inner.handle_read_task.take() { task.notify(); } inner.write.write_buf(buf) } } #[cfg(feature = "runtime")] pub struct DuplexHandle { inner: Arc>, } #[cfg(feature = "runtime")] impl DuplexHandle { pub fn read(&self, buf: &mut [u8]) -> Poll { let mut inner = self.inner.lock().unwrap(); assert!(buf.len() >= inner.write.inner.len()); if inner.write.inner.is_empty() { trace!("DuplexHandle read parking"); inner.handle_read_task = Some(task::current()); return Ok(Async::NotReady); } inner.write.read(buf).map(Async::Ready) } pub fn write(&self, bytes: &[u8]) -> Poll { let mut inner = self.inner.lock().unwrap(); assert_eq!(inner.read.inner.pos, 0); assert_eq!(inner.read.inner.vec.len(), 0, "write but read isn't empty"); inner .read .inner .vec .extend(bytes); inner.read.block_in(bytes.len()); Ok(Async::Ready(bytes.len())) } } #[cfg(feature = "runtime")] impl Drop for DuplexHandle { fn drop(&mut self) { trace!("mock duplex handle drop"); if !::std::thread::panicking() { let mut inner = self.inner.lock().unwrap(); inner.read.close(); inner.write.close(); } } } #[cfg(feature = "runtime")] type BoxedConnectFut = Box + Send>; #[cfg(feature = "runtime")] #[derive(Clone)] pub struct MockConnector { mocks: Arc>, } #[cfg(feature = "runtime")] struct MockedConnections(HashMap>); #[cfg(feature = "runtime")] impl MockConnector { pub fn new() -> MockConnector { MockConnector { mocks: Arc::new(Mutex::new(MockedConnections(HashMap::new()))), } } pub fn mock(&mut self, key: &str) -> DuplexHandle { use futures::future; self.mock_fut(key, future::ok::<_, ()>(())) } pub fn mock_fut(&mut self, key: &str, fut: F) -> DuplexHandle where F: Future + Send + 'static, { self.mock_opts(key, Connected::new(), fut) } pub fn mock_opts(&mut self, key: &str, connected: Connected, fut: F) -> DuplexHandle where F: Future + Send + 'static, { let key = key.to_owned(); let (duplex, handle) = Duplex::channel(); let fut = Box::new(fut.then(move |_| { trace!("MockConnector mocked fut ready"); Ok((duplex, connected)) })); self.mocks.lock().unwrap().0.entry(key) .or_insert(Vec::new()) .push(fut); handle } } #[cfg(feature = "runtime")] impl Connect for MockConnector { type Transport = Duplex; type Error = io::Error; type Future = BoxedConnectFut; fn connect(&self, dst: Destination) -> Self::Future { trace!("mock connect: {:?}", dst); let key = format!("{}://{}{}", dst.scheme(), dst.host(), if let Some(port) = dst.port() { format!(":{}", port) } else { "".to_owned() }); let mut mocks = self.mocks.lock().unwrap(); let mocks = mocks.0.get_mut(&key) .expect(&format!("unknown mocks uri: {}", key)); assert!(!mocks.is_empty(), "no additional mocks for {}", key); mocks.remove(0) } } #[cfg(feature = "runtime")] impl Drop for MockedConnections { fn drop(&mut self) { if !::std::thread::panicking() { for (key, mocks) in self.0.iter() { assert_eq!( mocks.len(), 0, "not all mocked connects for {:?} were used", key, ); } } } } hyper-0.12.35/src/proto/h1/conn.rs010066400017500001750000001200321353675567300150230ustar0000000000000000use std::fmt; use std::io::{self}; use std::marker::PhantomData; use bytes::{Buf, Bytes}; use futures::{Async, Poll}; use http::{HeaderMap, Method, Version}; use http::header::{HeaderValue, CONNECTION}; use tokio_io::{AsyncRead, AsyncWrite}; use ::Chunk; use proto::{BodyLength, DecodedLength, MessageHead}; use headers::connection_keep_alive; use super::io::{Buffered}; use super::{EncodedBuf, Encode, Encoder, /*Decode,*/ Decoder, Http1Transaction, ParseContext}; const H2_PREFACE: &'static [u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"; /// This handles a connection, which will have been established over an /// `AsyncRead + AsyncWrite` (like a socket), and will likely include multiple /// `Transaction`s over HTTP. /// /// The connection will determine when a message begins and ends as well as /// determine if this connection can be kept alive after the message, /// or if it is complete. pub(crate) struct Conn { io: Buffered>, state: State, _marker: PhantomData } impl Conn where I: AsyncRead + AsyncWrite, B: Buf, T: Http1Transaction, { pub fn new(io: I) -> Conn { Conn { io: Buffered::new(io), state: State { allow_half_close: true, cached_headers: None, error: None, keep_alive: KA::Busy, method: None, title_case_headers: false, notify_read: false, reading: Reading::Init, writing: Writing::Init, upgrade: None, // We assume a modern world where the remote speaks HTTP/1.1. // If they tell us otherwise, we'll downgrade in `read_head`. version: Version::HTTP_11, }, _marker: PhantomData, } } pub fn set_flush_pipeline(&mut self, enabled: bool) { self.io.set_flush_pipeline(enabled); } pub fn set_max_buf_size(&mut self, max: usize) { self.io.set_max_buf_size(max); } pub fn set_read_buf_exact_size(&mut self, sz: usize) { self.io.set_read_buf_exact_size(sz); } pub fn set_write_strategy_flatten(&mut self) { self.io.set_write_strategy_flatten(); } pub fn set_title_case_headers(&mut self) { self.state.title_case_headers = true; } pub(crate) fn set_disable_half_close(&mut self) { self.state.allow_half_close = false; } pub fn into_inner(self) -> (I, Bytes) { self.io.into_inner() } pub fn pending_upgrade(&mut self) -> Option<::upgrade::Pending> { self.state.upgrade.take() } pub fn is_read_closed(&self) -> bool { self.state.is_read_closed() } pub fn is_write_closed(&self) -> bool { self.state.is_write_closed() } pub fn can_read_head(&self) -> bool { match self.state.reading { Reading::Init => { if T::should_read_first() { true } else { match self.state.writing { Writing::Init => false, _ => true, } } }, _ => false, } } pub fn can_read_body(&self) -> bool { match self.state.reading { Reading::Body(..) => true, _ => false, } } fn should_error_on_eof(&self) -> bool { // If we're idle, it's probably just the connection closing gracefully. T::should_error_on_parse_eof() && !self.state.is_idle() } fn has_h2_prefix(&self) -> bool { let read_buf = self.io.read_buf(); read_buf.len() >= 24 && read_buf[..24] == *H2_PREFACE } pub fn read_head(&mut self) -> Poll, DecodedLength, bool)>, ::Error> { debug_assert!(self.can_read_head()); trace!("Conn::read_head"); let msg = match self.io.parse::(ParseContext { cached_headers: &mut self.state.cached_headers, req_method: &mut self.state.method, }) { Ok(Async::Ready(msg)) => msg, Ok(Async::NotReady) => return Ok(Async::NotReady), Err(e) => return self.on_read_head_error(e), }; // Note: don't deconstruct `msg` into local variables, it appears // the optimizer doesn't remove the extra copies. debug!("incoming body is {}", msg.decode); self.state.busy(); self.state.keep_alive &= msg.keep_alive; self.state.version = msg.head.version; if msg.decode == DecodedLength::ZERO { debug_assert!(!msg.expect_continue, "expect-continue needs a body"); self.state.reading = Reading::KeepAlive; if !T::should_read_first() { self.try_keep_alive(); } } else { if msg.expect_continue { let cont = b"HTTP/1.1 100 Continue\r\n\r\n"; self.io.headers_buf().extend_from_slice(cont); } self.state.reading = Reading::Body(Decoder::new(msg.decode)); }; Ok(Async::Ready(Some((msg.head, msg.decode, msg.wants_upgrade)))) } fn on_read_head_error(&mut self, e: ::Error) -> Poll, ::Error> { // If we are currently waiting on a message, then an empty // message should be reported as an error. If not, it is just // the connection closing gracefully. let must_error = self.should_error_on_eof(); self.state.close_read(); self.io.consume_leading_lines(); let was_mid_parse = e.is_parse() || !self.io.read_buf().is_empty(); if was_mid_parse || must_error { // We check if the buf contains the h2 Preface debug!("parse error ({}) with {} bytes", e, self.io.read_buf().len()); self.on_parse_error(e) .map(|()| Async::NotReady) } else { debug!("read eof"); Ok(Async::Ready(None)) } } pub fn read_body(&mut self) -> Poll, io::Error> { debug_assert!(self.can_read_body()); let (reading, ret) = match self.state.reading { Reading::Body(ref mut decoder) => { match decoder.decode(&mut self.io) { Ok(Async::Ready(slice)) => { let (reading, chunk) = if decoder.is_eof() { debug!("incoming body completed"); (Reading::KeepAlive, if !slice.is_empty() { Some(Chunk::from(slice)) } else { None }) } else if slice.is_empty() { error!("decode stream unexpectedly ended"); // This should be unreachable, since all 3 decoders // either set eof=true or return an Err when reading // an empty slice... (Reading::Closed, None) } else { return Ok(Async::Ready(Some(Chunk::from(slice)))); }; (reading, Ok(Async::Ready(chunk))) }, Ok(Async::NotReady) => return Ok(Async::NotReady), Err(e) => { debug!("decode stream error: {}", e); (Reading::Closed, Err(e)) }, } }, _ => unreachable!("read_body invalid state: {:?}", self.state.reading), }; self.state.reading = reading; self.try_keep_alive(); ret } pub fn wants_read_again(&mut self) -> bool { let ret = self.state.notify_read; self.state.notify_read = false; ret } pub fn read_keep_alive(&mut self) -> Poll<(), ::Error> { debug_assert!(!self.can_read_head() && !self.can_read_body()); if self.is_mid_message() { self.mid_message_detect_eof() } else { self.require_empty_read() } } fn is_mid_message(&self) -> bool { match (&self.state.reading, &self.state.writing) { (&Reading::Init, &Writing::Init) => false, _ => true, } } // This will check to make sure the io object read is empty. // // This should only be called for Clients wanting to enter the idle // state. fn require_empty_read(&mut self) -> Poll<(), ::Error> { debug_assert!(!self.can_read_head() && !self.can_read_body()); debug_assert!(!self.is_mid_message()); debug_assert!(T::is_client()); if !self.io.read_buf().is_empty() { debug!("received an unexpected {} bytes", self.io.read_buf().len()); return Err(::Error::new_unexpected_message()); } let num_read = try_ready!(self.force_io_read().map_err(::Error::new_io)); if num_read == 0 { let ret = if self.should_error_on_eof() { trace!("found unexpected EOF on busy connection: {:?}", self.state); Err(::Error::new_incomplete()) } else { trace!("found EOF on idle connection, closing"); Ok(Async::Ready(())) }; // order is important: should_error needs state BEFORE close_read self.state.close_read(); return ret; } debug!("received unexpected {} bytes on an idle connection", num_read); Err(::Error::new_unexpected_message()) } fn mid_message_detect_eof(&mut self) -> Poll<(), ::Error> { debug_assert!(!self.can_read_head() && !self.can_read_body()); debug_assert!(self.is_mid_message()); if self.state.allow_half_close || !self.io.read_buf().is_empty() { return Ok(Async::NotReady); } let num_read = try_ready!(self.force_io_read().map_err(::Error::new_io)); if num_read == 0 { trace!("found unexpected EOF on busy connection: {:?}", self.state); self.state.close_read(); Err(::Error::new_incomplete()) } else { Ok(Async::Ready(())) } } fn force_io_read(&mut self) -> Poll { self.io.read_from_io().map_err(|e| { trace!("force_io_read; io error = {:?}", e); self.state.close(); e }) } fn maybe_notify(&mut self) { // its possible that we returned NotReady from poll() without having // exhausted the underlying Io. We would have done this when we // determined we couldn't keep reading until we knew how writing // would finish. match self.state.reading { Reading::Body(..) | Reading::KeepAlive | Reading::Closed => return, Reading::Init => (), }; match self.state.writing { Writing::Body(..) => return, Writing::Init | Writing::KeepAlive | Writing::Closed => (), } if !self.io.is_read_blocked() { if self.io.read_buf().is_empty() { match self.io.read_from_io() { Ok(Async::Ready(_)) => (), Ok(Async::NotReady) => { trace!("maybe_notify; read_from_io blocked"); return }, Err(e) => { trace!("maybe_notify; read_from_io error: {}", e); self.state.close(); } } } self.state.notify_read = true; } } fn try_keep_alive(&mut self) { self.state.try_keep_alive::(); self.maybe_notify(); } pub fn can_write_head(&self) -> bool { if !T::should_read_first() { match self.state.reading { Reading::Closed => return false, _ => {}, } } match self.state.writing { Writing::Init => true, _ => false } } pub fn can_write_body(&self) -> bool { match self.state.writing { Writing::Body(..) => true, Writing::Init | Writing::KeepAlive | Writing::Closed => false, } } pub fn can_buffer_body(&self) -> bool { self.io.can_buffer() } pub fn write_head(&mut self, head: MessageHead, body: Option) { if let Some(encoder) = self.encode_head(head, body) { self.state.writing = if !encoder.is_eof() { Writing::Body(encoder) } else if encoder.is_last() { Writing::Closed } else { Writing::KeepAlive }; } } pub fn write_full_msg(&mut self, head: MessageHead, body: B) { if let Some(encoder) = self.encode_head(head, Some(BodyLength::Known(body.remaining() as u64))) { let is_last = encoder.is_last(); // Make sure we don't write a body if we weren't actually allowed // to do so, like because its a HEAD request. if !encoder.is_eof() { encoder.danger_full_buf(body, self.io.write_buf()); } self.state.writing = if is_last { Writing::Closed } else { Writing::KeepAlive } } } fn encode_head(&mut self, mut head: MessageHead, body: Option) -> Option { debug_assert!(self.can_write_head()); if !T::should_read_first() { self.state.busy(); } self.enforce_version(&mut head); let buf = self.io.headers_buf(); match T::encode(Encode { head: &mut head, body, keep_alive: self.state.wants_keep_alive(), req_method: &mut self.state.method, title_case_headers: self.state.title_case_headers, }, buf) { Ok(encoder) => { debug_assert!(self.state.cached_headers.is_none()); debug_assert!(head.headers.is_empty()); self.state.cached_headers = Some(head.headers); Some(encoder) }, Err(err) => { self.state.error = Some(err); self.state.writing = Writing::Closed; None }, } } // Fix keep-alives when Connection: keep-alive header is not present fn fix_keep_alive(&mut self, head: &mut MessageHead) { let outgoing_is_keep_alive = head .headers .get(CONNECTION) .and_then(|value| Some(connection_keep_alive(value))) .unwrap_or(false); if !outgoing_is_keep_alive { match head.version { // If response is version 1.0 and keep-alive is not present in the response, // disable keep-alive so the server closes the connection Version::HTTP_10 => self.state.disable_keep_alive(), // If response is version 1.1 and keep-alive is wanted, add // Connection: keep-alive header when not present Version::HTTP_11 => if self.state.wants_keep_alive() { head.headers .insert(CONNECTION, HeaderValue::from_static("keep-alive")); }, _ => (), } } } // If we know the remote speaks an older version, we try to fix up any messages // to work with our older peer. fn enforce_version(&mut self, head: &mut MessageHead) { match self.state.version { Version::HTTP_10 => { // Fixes response or connection when keep-alive header is not present self.fix_keep_alive(head); // If the remote only knows HTTP/1.0, we should force ourselves // to do only speak HTTP/1.0 as well. head.version = Version::HTTP_10; }, _ => { // If the remote speaks HTTP/1.1, then it *should* be fine with // both HTTP/1.0 and HTTP/1.1 from us. So again, we just let // the user's headers be. } } } pub fn write_body(&mut self, chunk: B) { debug_assert!(self.can_write_body() && self.can_buffer_body()); // empty chunks should be discarded at Dispatcher level debug_assert!(chunk.remaining() != 0); let state = match self.state.writing { Writing::Body(ref mut encoder) => { self.io.buffer(encoder.encode(chunk)); if encoder.is_eof() { if encoder.is_last() { Writing::Closed } else { Writing::KeepAlive } } else { return; } }, _ => unreachable!("write_body invalid state: {:?}", self.state.writing), }; self.state.writing = state; } pub fn write_body_and_end(&mut self, chunk: B) { debug_assert!(self.can_write_body() && self.can_buffer_body()); // empty chunks should be discarded at Dispatcher level debug_assert!(chunk.remaining() != 0); let state = match self.state.writing { Writing::Body(ref encoder) => { let can_keep_alive = encoder.encode_and_end(chunk, self.io.write_buf()); if can_keep_alive { Writing::KeepAlive } else { Writing::Closed } }, _ => unreachable!("write_body invalid state: {:?}", self.state.writing), }; self.state.writing = state; } pub fn end_body(&mut self) { debug_assert!(self.can_write_body()); let state = match self.state.writing { Writing::Body(ref mut encoder) => { // end of stream, that means we should try to eof match encoder.end() { Ok(end) => { if let Some(end) = end { self.io.buffer(end); } if encoder.is_last() { Writing::Closed } else { Writing::KeepAlive } }, Err(_not_eof) => Writing::Closed, } }, _ => return, }; self.state.writing = state; } // When we get a parse error, depending on what side we are, we might be able // to write a response before closing the connection. // // - Client: there is nothing we can do // - Server: if Response hasn't been written yet, we can send a 4xx response fn on_parse_error(&mut self, err: ::Error) -> ::Result<()> { match self.state.writing { Writing::Init => { if self.has_h2_prefix() { return Err(::Error::new_version_h2()) } if let Some(msg) = T::on_error(&err) { // Drop the cached headers so as to not trigger a debug // assert in `write_head`... self.state.cached_headers.take(); self.write_head(msg, None); self.state.error = Some(err); return Ok(()); } } _ => (), } // fallback is pass the error back up Err(err) } pub fn flush(&mut self) -> Poll<(), io::Error> { try_ready!(self.io.flush()); self.try_keep_alive(); trace!("flushed({}): {:?}", T::LOG, self.state); Ok(Async::Ready(())) } pub fn shutdown(&mut self) -> Poll<(), io::Error> { match self.io.io_mut().shutdown() { Ok(Async::NotReady) => Ok(Async::NotReady), Ok(Async::Ready(())) => { trace!("shut down IO complete"); Ok(Async::Ready(())) } Err(e) => { debug!("error shutting down IO: {}", e); Err(e) } } } pub fn close_read(&mut self) { self.state.close_read(); } pub fn close_write(&mut self) { self.state.close_write(); } pub fn disable_keep_alive(&mut self) { if self.state.is_idle() { self.state.close_read(); } else { self.state.disable_keep_alive(); } } pub fn take_error(&mut self) -> ::Result<()> { if let Some(err) = self.state.error.take() { Err(err) } else { Ok(()) } } pub(super) fn on_upgrade(&mut self) -> ::upgrade::OnUpgrade { trace!("{}: prepare possible HTTP upgrade", T::LOG); self.state.prepare_upgrade() } // Used in h1::dispatch tests #[cfg(test)] pub(super) fn io_mut(&mut self) -> &mut I { self.io.io_mut() } } impl fmt::Debug for Conn { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Conn") .field("state", &self.state) .field("io", &self.io) .finish() } } struct State { allow_half_close: bool, /// Re-usable HeaderMap to reduce allocating new ones. cached_headers: Option, /// If an error occurs when there wasn't a direct way to return it /// back to the user, this is set. error: Option<::Error>, /// Current keep-alive status. keep_alive: KA, /// If mid-message, the HTTP Method that started it. /// /// This is used to know things such as if the message can include /// a body or not. method: Option, title_case_headers: bool, /// Set to true when the Dispatcher should poll read operations /// again. See the `maybe_notify` method for more. notify_read: bool, /// State of allowed reads reading: Reading, /// State of allowed writes writing: Writing, /// An expected pending HTTP upgrade. upgrade: Option<::upgrade::Pending>, /// Either HTTP/1.0 or 1.1 connection version: Version, } #[derive(Debug)] enum Reading { Init, Body(Decoder), KeepAlive, Closed, } enum Writing { Init, Body(Encoder), KeepAlive, Closed, } impl fmt::Debug for State { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut builder = f.debug_struct("State"); builder .field("reading", &self.reading) .field("writing", &self.writing) .field("keep_alive", &self.keep_alive); // Only show error field if it's interesting... if let Some(ref error) = self.error { builder.field("error", error); } // Purposefully leaving off other fields.. builder.finish() } } impl fmt::Debug for Writing { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Writing::Init => f.write_str("Init"), Writing::Body(ref enc) => f.debug_tuple("Body") .field(enc) .finish(), Writing::KeepAlive => f.write_str("KeepAlive"), Writing::Closed => f.write_str("Closed"), } } } impl ::std::ops::BitAndAssign for KA { fn bitand_assign(&mut self, enabled: bool) { if !enabled { trace!("remote disabling keep-alive"); *self = KA::Disabled; } } } #[derive(Clone, Copy, Debug)] enum KA { Idle, Busy, Disabled, } impl Default for KA { fn default() -> KA { KA::Busy } } impl KA { fn idle(&mut self) { *self = KA::Idle; } fn busy(&mut self) { *self = KA::Busy; } fn disable(&mut self) { *self = KA::Disabled; } fn status(&self) -> KA { *self } } impl State { fn close(&mut self) { trace!("State::close()"); self.reading = Reading::Closed; self.writing = Writing::Closed; self.keep_alive.disable(); } fn close_read(&mut self) { trace!("State::close_read()"); self.reading = Reading::Closed; self.keep_alive.disable(); } fn close_write(&mut self) { trace!("State::close_write()"); self.writing = Writing::Closed; self.keep_alive.disable(); } fn wants_keep_alive(&self) -> bool { if let KA::Disabled = self.keep_alive.status() { false } else { true } } fn try_keep_alive(&mut self) { match (&self.reading, &self.writing) { (&Reading::KeepAlive, &Writing::KeepAlive) => { if let KA::Busy = self.keep_alive.status() { self.idle::(); } else { trace!("try_keep_alive({}): could keep-alive, but status = {:?}", T::LOG, self.keep_alive); self.close(); } }, (&Reading::Closed, &Writing::KeepAlive) | (&Reading::KeepAlive, &Writing::Closed) => { self.close() } _ => () } } fn disable_keep_alive(&mut self) { self.keep_alive.disable() } fn busy(&mut self) { if let KA::Disabled = self.keep_alive.status() { return; } self.keep_alive.busy(); } fn idle(&mut self) { debug_assert!(!self.is_idle(), "State::idle() called while idle"); self.method = None; self.keep_alive.idle(); if self.is_idle() { self.reading = Reading::Init; self.writing = Writing::Init; // !T::should_read_first() means Client. // // If Client connection has just gone idle, the Dispatcher // should try the poll loop one more time, so as to poll the // pending requests stream. if !T::should_read_first() { self.notify_read = true; } } else { self.close(); } } fn is_idle(&self) -> bool { if let KA::Idle = self.keep_alive.status() { true } else { false } } fn is_read_closed(&self) -> bool { match self.reading { Reading::Closed => true, _ => false } } fn is_write_closed(&self) -> bool { match self.writing { Writing::Closed => true, _ => false } } fn prepare_upgrade(&mut self) -> ::upgrade::OnUpgrade { debug_assert!(self.upgrade.is_none()); let (tx, rx) = ::upgrade::pending(); self.upgrade = Some(tx); rx } } #[cfg(test)] //TODO: rewrite these using dispatch mod tests { #[cfg(feature = "nightly")] #[bench] fn bench_read_head_short(b: &mut ::test::Bencher) { use super::*; let s = b"GET / HTTP/1.1\r\nHost: localhost:8080\r\n\r\n"; let len = s.len(); b.bytes = len as u64; let mut io = ::mock::AsyncIo::new_buf(Vec::new(), 0); io.panic(); let mut conn = Conn::<_, ::Chunk, ::proto::h1::ServerTransaction>::new(io); *conn.io.read_buf_mut() = ::bytes::BytesMut::from(&s[..]); conn.state.cached_headers = Some(HeaderMap::with_capacity(2)); b.iter(|| { match conn.read_head().unwrap() { Async::Ready(Some(x)) => { ::test::black_box(&x); let mut headers = x.0.headers; headers.clear(); conn.state.cached_headers = Some(headers); }, f => panic!("expected Ready(Some(..)): {:?}", f) } conn.io.read_buf_mut().reserve(1); unsafe { conn.io.read_buf_mut().set_len(len); } conn.state.reading = Reading::Init; }); } /* use futures::{Async, Future, Stream, Sink}; use futures::future; use proto::{self, ClientTransaction, MessageHead, ServerTransaction}; use super::super::Encoder; use mock::AsyncIo; use super::{Conn, Decoder, Reading, Writing}; use ::uri::Uri; use std::str::FromStr; #[test] fn test_conn_init_read() { let good_message = b"GET / HTTP/1.1\r\n\r\n".to_vec(); let len = good_message.len(); let io = AsyncIo::new_buf(good_message, len); let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); match conn.poll().unwrap() { Async::Ready(Some(Frame::Message { message, body: false })) => { assert_eq!(message, MessageHead { subject: ::proto::RequestLine(::Get, Uri::from_str("/").unwrap()), .. MessageHead::default() }) }, f => panic!("frame is not Frame::Message: {:?}", f) } } #[test] fn test_conn_parse_partial() { let _: Result<(), ()> = future::lazy(|| { let good_message = b"GET / HTTP/1.1\r\nHost: foo.bar\r\n\r\n".to_vec(); let io = AsyncIo::new_buf(good_message, 10); let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); assert!(conn.poll().unwrap().is_not_ready()); conn.io.io_mut().block_in(50); let async = conn.poll().unwrap(); assert!(async.is_ready()); match async { Async::Ready(Some(Frame::Message { .. })) => (), f => panic!("frame is not Message: {:?}", f), } Ok(()) }).wait(); } #[test] fn test_conn_init_read_eof_idle() { let io = AsyncIo::new_buf(vec![], 1); let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); conn.state.idle(); match conn.poll().unwrap() { Async::Ready(None) => {}, other => panic!("frame is not None: {:?}", other) } } #[test] fn test_conn_init_read_eof_idle_partial_parse() { let io = AsyncIo::new_buf(b"GET / HTTP/1.1".to_vec(), 100); let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); conn.state.idle(); match conn.poll() { Err(ref err) if err.kind() == ::std::io::ErrorKind::UnexpectedEof => {}, other => panic!("unexpected frame: {:?}", other) } } #[test] fn test_conn_init_read_eof_busy() { let _: Result<(), ()> = future::lazy(|| { // server ignores let io = AsyncIo::new_eof(); let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); conn.state.busy(); match conn.poll().unwrap() { Async::Ready(None) => {}, other => panic!("unexpected frame: {:?}", other) } // client let io = AsyncIo::new_eof(); let mut conn = Conn::<_, proto::Chunk, ClientTransaction>::new(io); conn.state.busy(); match conn.poll() { Err(ref err) if err.kind() == ::std::io::ErrorKind::UnexpectedEof => {}, other => panic!("unexpected frame: {:?}", other) } Ok(()) }).wait(); } #[test] fn test_conn_body_finish_read_eof() { let _: Result<(), ()> = future::lazy(|| { let io = AsyncIo::new_eof(); let mut conn = Conn::<_, proto::Chunk, ClientTransaction>::new(io); conn.state.busy(); conn.state.writing = Writing::KeepAlive; conn.state.reading = Reading::Body(Decoder::length(0)); match conn.poll() { Ok(Async::Ready(Some(Frame::Body { chunk: None }))) => (), other => panic!("unexpected frame: {:?}", other) } // conn eofs, but tokio-proto will call poll() again, before calling flush() // the conn eof in this case is perfectly fine match conn.poll() { Ok(Async::Ready(None)) => (), other => panic!("unexpected frame: {:?}", other) } Ok(()) }).wait(); } #[test] fn test_conn_message_empty_body_read_eof() { let _: Result<(), ()> = future::lazy(|| { let io = AsyncIo::new_buf(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".to_vec(), 1024); let mut conn = Conn::<_, proto::Chunk, ClientTransaction>::new(io); conn.state.busy(); conn.state.writing = Writing::KeepAlive; match conn.poll() { Ok(Async::Ready(Some(Frame::Message { body: false, .. }))) => (), other => panic!("unexpected frame: {:?}", other) } // conn eofs, but tokio-proto will call poll() again, before calling flush() // the conn eof in this case is perfectly fine match conn.poll() { Ok(Async::Ready(None)) => (), other => panic!("unexpected frame: {:?}", other) } Ok(()) }).wait(); } #[test] fn test_conn_read_body_end() { let _: Result<(), ()> = future::lazy(|| { let io = AsyncIo::new_buf(b"POST / HTTP/1.1\r\nContent-Length: 5\r\n\r\n12345".to_vec(), 1024); let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); conn.state.busy(); match conn.poll() { Ok(Async::Ready(Some(Frame::Message { body: true, .. }))) => (), other => panic!("unexpected frame: {:?}", other) } match conn.poll() { Ok(Async::Ready(Some(Frame::Body { chunk: Some(_) }))) => (), other => panic!("unexpected frame: {:?}", other) } // When the body is done, `poll` MUST return a `Body` frame with chunk set to `None` match conn.poll() { Ok(Async::Ready(Some(Frame::Body { chunk: None }))) => (), other => panic!("unexpected frame: {:?}", other) } match conn.poll() { Ok(Async::NotReady) => (), other => panic!("unexpected frame: {:?}", other) } Ok(()) }).wait(); } #[test] fn test_conn_closed_read() { let io = AsyncIo::new_buf(vec![], 0); let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); conn.state.close(); match conn.poll().unwrap() { Async::Ready(None) => {}, other => panic!("frame is not None: {:?}", other) } } #[test] fn test_conn_body_write_length() { extern crate pretty_env_logger; let _ = pretty_env_logger::try_init(); let _: Result<(), ()> = future::lazy(|| { let io = AsyncIo::new_buf(vec![], 0); let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); let max = super::super::io::DEFAULT_MAX_BUFFER_SIZE + 4096; conn.state.writing = Writing::Body(Encoder::length((max * 2) as u64)); assert!(conn.start_send(Frame::Body { chunk: Some(vec![b'a'; max].into()) }).unwrap().is_ready()); assert!(!conn.can_buffer_body()); assert!(conn.start_send(Frame::Body { chunk: Some(vec![b'b'; 1024 * 8].into()) }).unwrap().is_not_ready()); conn.io.io_mut().block_in(1024 * 3); assert!(conn.poll_complete().unwrap().is_not_ready()); conn.io.io_mut().block_in(1024 * 3); assert!(conn.poll_complete().unwrap().is_not_ready()); conn.io.io_mut().block_in(max * 2); assert!(conn.poll_complete().unwrap().is_ready()); assert!(conn.start_send(Frame::Body { chunk: Some(vec![b'c'; 1024 * 8].into()) }).unwrap().is_ready()); Ok(()) }).wait(); } #[test] fn test_conn_body_write_chunked() { let _: Result<(), ()> = future::lazy(|| { let io = AsyncIo::new_buf(vec![], 4096); let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); conn.state.writing = Writing::Body(Encoder::chunked()); assert!(conn.start_send(Frame::Body { chunk: Some("headers".into()) }).unwrap().is_ready()); assert!(conn.start_send(Frame::Body { chunk: Some(vec![b'x'; 8192].into()) }).unwrap().is_ready()); Ok(()) }).wait(); } #[test] fn test_conn_body_flush() { let _: Result<(), ()> = future::lazy(|| { let io = AsyncIo::new_buf(vec![], 1024 * 1024 * 5); let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); conn.state.writing = Writing::Body(Encoder::length(1024 * 1024)); assert!(conn.start_send(Frame::Body { chunk: Some(vec![b'a'; 1024 * 1024].into()) }).unwrap().is_ready()); assert!(!conn.can_buffer_body()); conn.io.io_mut().block_in(1024 * 1024 * 5); assert!(conn.poll_complete().unwrap().is_ready()); assert!(conn.can_buffer_body()); assert!(conn.io.io_mut().flushed()); Ok(()) }).wait(); } #[test] fn test_conn_parking() { use std::sync::Arc; use futures::executor::Notify; use futures::executor::NotifyHandle; struct Car { permit: bool, } impl Notify for Car { fn notify(&self, _id: usize) { assert!(self.permit, "unparked without permit"); } } fn car(permit: bool) -> NotifyHandle { Arc::new(Car { permit: permit, }).into() } // test that once writing is done, unparks let f = future::lazy(|| { let io = AsyncIo::new_buf(vec![], 4096); let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); conn.state.reading = Reading::KeepAlive; assert!(conn.poll().unwrap().is_not_ready()); conn.state.writing = Writing::KeepAlive; assert!(conn.poll_complete().unwrap().is_ready()); Ok::<(), ()>(()) }); ::futures::executor::spawn(f).poll_future_notify(&car(true), 0).unwrap(); // test that flushing when not waiting on read doesn't unpark let f = future::lazy(|| { let io = AsyncIo::new_buf(vec![], 4096); let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); conn.state.writing = Writing::KeepAlive; assert!(conn.poll_complete().unwrap().is_ready()); Ok::<(), ()>(()) }); ::futures::executor::spawn(f).poll_future_notify(&car(false), 0).unwrap(); // test that flushing and writing isn't done doesn't unpark let f = future::lazy(|| { let io = AsyncIo::new_buf(vec![], 4096); let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); conn.state.reading = Reading::KeepAlive; assert!(conn.poll().unwrap().is_not_ready()); conn.state.writing = Writing::Body(Encoder::length(5_000)); assert!(conn.poll_complete().unwrap().is_ready()); Ok::<(), ()>(()) }); ::futures::executor::spawn(f).poll_future_notify(&car(false), 0).unwrap(); } #[test] fn test_conn_closed_write() { let io = AsyncIo::new_buf(vec![], 0); let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); conn.state.close(); match conn.start_send(Frame::Body { chunk: Some(b"foobar".to_vec().into()) }) { Err(_e) => {}, other => panic!("did not return Err: {:?}", other) } assert!(conn.state.is_write_closed()); } #[test] fn test_conn_write_empty_chunk() { let io = AsyncIo::new_buf(vec![], 0); let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); conn.state.writing = Writing::KeepAlive; assert!(conn.start_send(Frame::Body { chunk: None }).unwrap().is_ready()); assert!(conn.start_send(Frame::Body { chunk: Some(Vec::new().into()) }).unwrap().is_ready()); conn.start_send(Frame::Body { chunk: Some(vec![b'a'].into()) }).unwrap_err(); } */ } hyper-0.12.35/src/proto/h1/date.rs010066400017500001750000000037151346064762000147770ustar0000000000000000use std::cell::RefCell; use std::fmt::{self, Write}; use std::str; use http::header::HeaderValue; use time::{self, Duration}; // "Sun, 06 Nov 1994 08:49:37 GMT".len() pub const DATE_VALUE_LENGTH: usize = 29; pub fn extend(dst: &mut Vec) { CACHED.with(|cache| { dst.extend_from_slice(cache.borrow().buffer()); }) } pub fn update() { CACHED.with(|cache| { cache.borrow_mut().check(); }) } pub(crate) fn update_and_header_value() -> HeaderValue { CACHED.with(|cache| { let mut cache = cache.borrow_mut(); cache.check(); HeaderValue::from_bytes(cache.buffer()) .expect("Date format should be valid HeaderValue") }) } struct CachedDate { bytes: [u8; DATE_VALUE_LENGTH], pos: usize, next_update: time::Timespec, } thread_local!(static CACHED: RefCell = RefCell::new(CachedDate::new())); impl CachedDate { fn new() -> Self { let mut cache = CachedDate { bytes: [0; DATE_VALUE_LENGTH], pos: 0, next_update: time::Timespec::new(0, 0), }; cache.update(time::get_time()); cache } fn buffer(&self) -> &[u8] { &self.bytes[..] } fn check(&mut self) { let now = time::get_time(); if now > self.next_update { self.update(now); } } fn update(&mut self, now: time::Timespec) { self.pos = 0; let _ = write!(self, "{}", time::at_utc(now).rfc822()); debug_assert!(self.pos == DATE_VALUE_LENGTH); self.next_update = now + Duration::seconds(1); self.next_update.nsec = 0; } } impl fmt::Write for CachedDate { fn write_str(&mut self, s: &str) -> fmt::Result { let len = s.len(); self.bytes[self.pos..self.pos + len].copy_from_slice(s.as_bytes()); self.pos += len; Ok(()) } } #[test] fn test_date_len() { assert_eq!(DATE_VALUE_LENGTH, "Sun, 06 Nov 1994 08:49:37 GMT".len()); } hyper-0.12.35/src/proto/h1/decode.rs010066400017500001750000000443231353675567300153210ustar0000000000000000use std::error::Error as StdError; use std::fmt; use std::usize; use std::io; use futures::{Async, Poll}; use bytes::Bytes; use super::io::MemRead; use super::{DecodedLength}; use self::Kind::{Length, Chunked, Eof}; /// Decoders to handle different Transfer-Encodings. /// /// If a message body does not include a Transfer-Encoding, it *should* /// include a Content-Length header. #[derive(Clone, PartialEq)] pub struct Decoder { kind: Kind, } #[derive(Debug, Clone, Copy, PartialEq)] enum Kind { /// A Reader used when a Content-Length header is passed with a positive integer. Length(u64), /// A Reader used when Transfer-Encoding is `chunked`. Chunked(ChunkedState, u64), /// A Reader used for responses that don't indicate a length or chunked. /// /// The bool tracks when EOF is seen on the transport. /// /// Note: This should only used for `Response`s. It is illegal for a /// `Request` to be made with both `Content-Length` and /// `Transfer-Encoding: chunked` missing, as explained from the spec: /// /// > If a Transfer-Encoding header field is present in a response and /// > the chunked transfer coding is not the final encoding, the /// > message body length is determined by reading the connection until /// > it is closed by the server. If a Transfer-Encoding header field /// > is present in a request and the chunked transfer coding is not /// > the final encoding, the message body length cannot be determined /// > reliably; the server MUST respond with the 400 (Bad Request) /// > status code and then close the connection. Eof(bool), } #[derive(Debug, PartialEq, Clone, Copy)] enum ChunkedState { Size, SizeLws, Extension, SizeLf, Body, BodyCr, BodyLf, EndCr, EndLf, End, } impl Decoder { // constructors pub fn length(x: u64) -> Decoder { Decoder { kind: Kind::Length(x) } } pub fn chunked() -> Decoder { Decoder { kind: Kind::Chunked(ChunkedState::Size, 0) } } pub fn eof() -> Decoder { Decoder { kind: Kind::Eof(false) } } pub(super) fn new(len: DecodedLength) -> Self { match len { DecodedLength::CHUNKED => Decoder::chunked(), DecodedLength::CLOSE_DELIMITED => Decoder::eof(), length => Decoder::length(length.danger_len()), } } // methods pub fn is_eof(&self) -> bool { match self.kind { Length(0) | Chunked(ChunkedState::End, _) | Eof(true) => true, _ => false, } } pub fn decode(&mut self, body: &mut R) -> Poll { trace!("decode; state={:?}", self.kind); match self.kind { Length(ref mut remaining) => { if *remaining == 0 { Ok(Async::Ready(Bytes::new())) } else { let to_read = *remaining as usize; let buf = try_ready!(body.read_mem(to_read)); let num = buf.as_ref().len() as u64; if num > *remaining { *remaining = 0; } else if num == 0 { return Err(io::Error::new(io::ErrorKind::UnexpectedEof, IncompleteBody)); } else { *remaining -= num; } Ok(Async::Ready(buf)) } } Chunked(ref mut state, ref mut size) => { loop { let mut buf = None; // advances the chunked state *state = try_ready!(state.step(body, size, &mut buf)); if *state == ChunkedState::End { trace!("end of chunked"); return Ok(Async::Ready(Bytes::new())); } if let Some(buf) = buf { return Ok(Async::Ready(buf)); } } } Eof(ref mut is_eof) => { if *is_eof { Ok(Async::Ready(Bytes::new())) } else { // 8192 chosen because its about 2 packets, there probably // won't be that much available, so don't have MemReaders // allocate buffers to big let slice = try_ready!(body.read_mem(8192)); *is_eof = slice.is_empty(); Ok(Async::Ready(slice)) } } } } } impl fmt::Debug for Decoder { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.kind, f) } } macro_rules! byte ( ($rdr:ident) => ({ let buf = try_ready!($rdr.read_mem(1)); if !buf.is_empty() { buf[0] } else { return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "Unexpected eof during chunk size line")); } }) ); impl ChunkedState { fn step(&self, body: &mut R, size: &mut u64, buf: &mut Option) -> Poll { use self::ChunkedState::*; match *self { Size => ChunkedState::read_size(body, size), SizeLws => ChunkedState::read_size_lws(body), Extension => ChunkedState::read_extension(body), SizeLf => ChunkedState::read_size_lf(body, *size), Body => ChunkedState::read_body(body, size, buf), BodyCr => ChunkedState::read_body_cr(body), BodyLf => ChunkedState::read_body_lf(body), EndCr => ChunkedState::read_end_cr(body), EndLf => ChunkedState::read_end_lf(body), End => Ok(Async::Ready(ChunkedState::End)), } } fn read_size(rdr: &mut R, size: &mut u64) -> Poll { trace!("Read chunk hex size"); let radix = 16; match byte!(rdr) { b @ b'0'..=b'9' => { *size *= radix; *size += (b - b'0') as u64; } b @ b'a'..=b'f' => { *size *= radix; *size += (b + 10 - b'a') as u64; } b @ b'A'..=b'F' => { *size *= radix; *size += (b + 10 - b'A') as u64; } b'\t' | b' ' => return Ok(Async::Ready(ChunkedState::SizeLws)), b';' => return Ok(Async::Ready(ChunkedState::Extension)), b'\r' => return Ok(Async::Ready(ChunkedState::SizeLf)), _ => { return Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk size line: Invalid Size")); } } Ok(Async::Ready(ChunkedState::Size)) } fn read_size_lws(rdr: &mut R) -> Poll { trace!("read_size_lws"); match byte!(rdr) { // LWS can follow the chunk size, but no more digits can come b'\t' | b' ' => Ok(Async::Ready(ChunkedState::SizeLws)), b';' => Ok(Async::Ready(ChunkedState::Extension)), b'\r' => Ok(Async::Ready(ChunkedState::SizeLf)), _ => { Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk size linear white space")) } } } fn read_extension(rdr: &mut R) -> Poll { trace!("read_extension"); match byte!(rdr) { b'\r' => Ok(Async::Ready(ChunkedState::SizeLf)), _ => Ok(Async::Ready(ChunkedState::Extension)), // no supported extensions } } fn read_size_lf(rdr: &mut R, size: u64) -> Poll { trace!("Chunk size is {:?}", size); match byte!(rdr) { b'\n' => { if size == 0 { Ok(Async::Ready(ChunkedState::EndCr)) } else { debug!("incoming chunked header: {0:#X} ({0} bytes)", size); Ok(Async::Ready(ChunkedState::Body)) } }, _ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk size LF")), } } fn read_body(rdr: &mut R, rem: &mut u64, buf: &mut Option) -> Poll { trace!("Chunked read, remaining={:?}", rem); // cap remaining bytes at the max capacity of usize let rem_cap = match *rem { r if r > usize::MAX as u64 => usize::MAX, r => r as usize, }; let to_read = rem_cap; let slice = try_ready!(rdr.read_mem(to_read)); let count = slice.len(); if count == 0 { *rem = 0; return Err(io::Error::new(io::ErrorKind::UnexpectedEof, IncompleteBody)); } *buf = Some(slice); *rem -= count as u64; if *rem > 0 { Ok(Async::Ready(ChunkedState::Body)) } else { Ok(Async::Ready(ChunkedState::BodyCr)) } } fn read_body_cr(rdr: &mut R) -> Poll { match byte!(rdr) { b'\r' => Ok(Async::Ready(ChunkedState::BodyLf)), _ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk body CR")), } } fn read_body_lf(rdr: &mut R) -> Poll { match byte!(rdr) { b'\n' => Ok(Async::Ready(ChunkedState::Size)), _ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk body LF")), } } fn read_end_cr(rdr: &mut R) -> Poll { match byte!(rdr) { b'\r' => Ok(Async::Ready(ChunkedState::EndLf)), _ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk end CR")), } } fn read_end_lf(rdr: &mut R) -> Poll { match byte!(rdr) { b'\n' => Ok(Async::Ready(ChunkedState::End)), _ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk end LF")), } } } #[derive(Debug)] struct IncompleteBody; impl fmt::Display for IncompleteBody { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.description()) } } impl StdError for IncompleteBody { fn description(&self) -> &str { "end of file before message length reached" } } #[cfg(test)] mod tests { use std::io; use std::io::Write; use super::Decoder; use super::ChunkedState; use super::super::io::MemRead; use futures::{Async, Poll}; use bytes::{BytesMut, Bytes}; use mock::AsyncIo; impl<'a> MemRead for &'a [u8] { fn read_mem(&mut self, len: usize) -> Poll { let n = ::std::cmp::min(len, self.len()); if n > 0 { let (a, b) = self.split_at(n); let mut buf = BytesMut::from(a); *self = b; Ok(Async::Ready(buf.split_to(n).freeze())) } else { Ok(Async::Ready(Bytes::new())) } } } trait HelpUnwrap { fn unwrap(self) -> T; } impl HelpUnwrap for Async { fn unwrap(self) -> Bytes { match self { Async::Ready(bytes) => bytes, Async::NotReady => panic!(), } } } impl HelpUnwrap for Async { fn unwrap(self) -> ChunkedState { match self { Async::Ready(state) => state, Async::NotReady => panic!(), } } } #[test] fn test_read_chunk_size() { use std::io::ErrorKind::{UnexpectedEof, InvalidInput}; fn read(s: &str) -> u64 { let mut state = ChunkedState::Size; let rdr = &mut s.as_bytes(); let mut size = 0; loop { let result = state.step(rdr, &mut size, &mut None); let desc = format!("read_size failed for {:?}", s); state = result.expect(desc.as_str()).unwrap(); if state == ChunkedState::Body || state == ChunkedState::EndCr { break; } } size } fn read_err(s: &str, expected_err: io::ErrorKind) { let mut state = ChunkedState::Size; let rdr = &mut s.as_bytes(); let mut size = 0; loop { let result = state.step(rdr, &mut size, &mut None); state = match result { Ok(s) => s.unwrap(), Err(e) => { assert!(expected_err == e.kind(), "Reading {:?}, expected {:?}, but got {:?}", s, expected_err, e.kind()); return; } }; if state == ChunkedState::Body || state == ChunkedState::End { panic!(format!("Was Ok. Expected Err for {:?}", s)); } } } assert_eq!(1, read("1\r\n")); assert_eq!(1, read("01\r\n")); assert_eq!(0, read("0\r\n")); assert_eq!(0, read("00\r\n")); assert_eq!(10, read("A\r\n")); assert_eq!(10, read("a\r\n")); assert_eq!(255, read("Ff\r\n")); assert_eq!(255, read("Ff \r\n")); // Missing LF or CRLF read_err("F\rF", InvalidInput); read_err("F", UnexpectedEof); // Invalid hex digit read_err("X\r\n", InvalidInput); read_err("1X\r\n", InvalidInput); read_err("-\r\n", InvalidInput); read_err("-1\r\n", InvalidInput); // Acceptable (if not fully valid) extensions do not influence the size assert_eq!(1, read("1;extension\r\n")); assert_eq!(10, read("a;ext name=value\r\n")); assert_eq!(1, read("1;extension;extension2\r\n")); assert_eq!(1, read("1;;; ;\r\n")); assert_eq!(2, read("2; extension...\r\n")); assert_eq!(3, read("3 ; extension=123\r\n")); assert_eq!(3, read("3 ;\r\n")); assert_eq!(3, read("3 ; \r\n")); // Invalid extensions cause an error read_err("1 invalid extension\r\n", InvalidInput); read_err("1 A\r\n", InvalidInput); read_err("1;no CRLF", UnexpectedEof); } #[test] fn test_read_sized_early_eof() { let mut bytes = &b"foo bar"[..]; let mut decoder = Decoder::length(10); assert_eq!(decoder.decode(&mut bytes).unwrap().unwrap().len(), 7); let e = decoder.decode(&mut bytes).unwrap_err(); assert_eq!(e.kind(), io::ErrorKind::UnexpectedEof); } #[test] fn test_read_chunked_early_eof() { let mut bytes = &b"\ 9\r\n\ foo bar\ "[..]; let mut decoder = Decoder::chunked(); assert_eq!(decoder.decode(&mut bytes).unwrap().unwrap().len(), 7); let e = decoder.decode(&mut bytes).unwrap_err(); assert_eq!(e.kind(), io::ErrorKind::UnexpectedEof); } #[test] fn test_read_chunked_single_read() { let mut mock_buf = &b"10\r\n1234567890abcdef\r\n0\r\n"[..]; let buf = Decoder::chunked().decode(&mut mock_buf).expect("decode").unwrap(); assert_eq!(16, buf.len()); let result = String::from_utf8(buf.as_ref().to_vec()).expect("decode String"); assert_eq!("1234567890abcdef", &result); } #[test] fn test_read_chunked_after_eof() { let mut mock_buf = &b"10\r\n1234567890abcdef\r\n0\r\n\r\n"[..]; let mut decoder = Decoder::chunked(); // normal read let buf = decoder.decode(&mut mock_buf).expect("decode").unwrap(); assert_eq!(16, buf.len()); let result = String::from_utf8(buf.as_ref().to_vec()).expect("decode String"); assert_eq!("1234567890abcdef", &result); // eof read let buf = decoder.decode(&mut mock_buf).expect("decode").unwrap(); assert_eq!(0, buf.len()); // ensure read after eof also returns eof let buf = decoder.decode(&mut mock_buf).expect("decode").unwrap(); assert_eq!(0, buf.len()); } // perform an async read using a custom buffer size and causing a blocking // read at the specified byte fn read_async(mut decoder: Decoder, content: &[u8], block_at: usize) -> String { let content_len = content.len(); let mut ins = AsyncIo::new(content, block_at); let mut outs = Vec::new(); loop { match decoder.decode(&mut ins).expect("unexpected decode error: {}") { Async::Ready(buf) => { if buf.is_empty() { break; // eof } outs.write(buf.as_ref()).expect("write buffer"); }, Async::NotReady => { ins.block_in(content_len); // we only block once } }; } String::from_utf8(outs).expect("decode String") } // iterate over the different ways that this async read could go. // tests blocking a read at each byte along the content - The shotgun approach fn all_async_cases(content: &str, expected: &str, decoder: Decoder) { let content_len = content.len(); for block_at in 0..content_len { let actual = read_async(decoder.clone(), content.as_bytes(), block_at); assert_eq!(expected, &actual) //, "Failed async. Blocking at {}", block_at); } } #[test] fn test_read_length_async() { let content = "foobar"; all_async_cases(content, content, Decoder::length(content.len() as u64)); } #[test] fn test_read_chunked_async() { let content = "3\r\nfoo\r\n3\r\nbar\r\n0\r\n\r\n"; let expected = "foobar"; all_async_cases(content, expected, Decoder::chunked()); } #[test] fn test_read_eof_async() { let content = "foobar"; all_async_cases(content, content, Decoder::eof()); } } hyper-0.12.35/src/proto/h1/dispatch.rs010066400017500001750000000537361353675567300157050ustar0000000000000000use std::error::Error as StdError; use bytes::{Buf, Bytes}; use futures::{Async, Future, Poll, Stream}; use http::{Request, Response, StatusCode}; use tokio_io::{AsyncRead, AsyncWrite}; use body::{Body, Payload}; use body::internal::FullDataArg; use common::{Never, YieldNow}; use proto::{BodyLength, DecodedLength, Conn, Dispatched, MessageHead, RequestHead, RequestLine, ResponseHead}; use super::Http1Transaction; use service::Service; pub(crate) struct Dispatcher { conn: Conn, dispatch: D, body_tx: Option<::body::Sender>, body_rx: Option, is_closing: bool, /// If the poll loop reaches its max spin count, it will yield by notifying /// the task immediately. This will cache that `Task`, since it usually is /// the same one. yield_now: YieldNow, } pub(crate) trait Dispatch { type PollItem; type PollBody; type PollError; type RecvItem; fn poll_msg(&mut self) -> Poll, Self::PollError>; fn recv_msg(&mut self, msg: ::Result<(Self::RecvItem, Body)>) -> ::Result<()>; fn poll_ready(&mut self) -> Poll<(), ()>; fn should_poll(&self) -> bool; } pub struct Server { in_flight: Option, pub(crate) service: S, } pub struct Client { callback: Option<::client::dispatch::Callback, Response>>, rx: ClientRx, } type ClientRx = ::client::dispatch::Receiver, Response>; impl Dispatcher where D: Dispatch, PollBody=Bs, RecvItem=MessageHead>, D::PollError: Into>, I: AsyncRead + AsyncWrite, T: Http1Transaction, Bs: Payload, { pub fn new(dispatch: D, conn: Conn) -> Self { Dispatcher { conn: conn, dispatch: dispatch, body_tx: None, body_rx: None, is_closing: false, yield_now: YieldNow::new(), } } pub fn disable_keep_alive(&mut self) { self.conn.disable_keep_alive() } pub fn into_inner(self) -> (I, Bytes, D) { let (io, buf) = self.conn.into_inner(); (io, buf, self.dispatch) } /// Run this dispatcher until HTTP says this connection is done, /// but don't call `AsyncWrite::shutdown` on the underlying IO. /// /// This is useful for old-style HTTP upgrades, but ignores /// newer-style upgrade API. pub fn poll_without_shutdown(&mut self) -> Poll<(), ::Error> { self.poll_catch(false) .map(|x| { x.map(|ds| if let Dispatched::Upgrade(pending) = ds { pending.manual(); }) }) } fn poll_catch(&mut self, should_shutdown: bool) -> Poll { self.poll_inner(should_shutdown).or_else(|e| { // An error means we're shutting down either way. // We just try to give the error to the user, // and close the connection with an Ok. If we // cannot give it to the user, then return the Err. self.dispatch.recv_msg(Err(e))?; Ok(Async::Ready(Dispatched::Shutdown)) }) } fn poll_inner(&mut self, should_shutdown: bool) -> Poll { T::update_date(); try_ready!(self.poll_loop()); if self.is_done() { if let Some(pending) = self.conn.pending_upgrade() { self.conn.take_error()?; return Ok(Async::Ready(Dispatched::Upgrade(pending))); } else if should_shutdown { try_ready!(self.conn.shutdown().map_err(::Error::new_shutdown)); } self.conn.take_error()?; Ok(Async::Ready(Dispatched::Shutdown)) } else { Ok(Async::NotReady) } } fn poll_loop(&mut self) -> Poll<(), ::Error> { // Limit the looping on this connection, in case it is ready far too // often, so that other futures don't starve. // // 16 was chosen arbitrarily, as that is number of pipelined requests // benchmarks often use. Perhaps it should be a config option instead. for _ in 0..16 { self.poll_read()?; self.poll_write()?; self.poll_flush()?; // This could happen if reading paused before blocking on IO, // such as getting to the end of a framed message, but then // writing/flushing set the state back to Init. In that case, // if the read buffer still had bytes, we'd want to try poll_read // again, or else we wouldn't ever be woken up again. // // Using this instead of task::current() and notify() inside // the Conn is noticeably faster in pipelined benchmarks. if !self.conn.wants_read_again() { //break; return Ok(Async::Ready(())); } } trace!("poll_loop yielding (self = {:p})", self); match self.yield_now.poll_yield() { Ok(Async::NotReady) => Ok(Async::NotReady), // maybe with `!` this can be cleaner... // but for now, just doing this to eliminate branches Ok(Async::Ready(never)) | Err(never) => match never {} } } fn poll_read(&mut self) -> Poll<(), ::Error> { loop { if self.is_closing { return Ok(Async::Ready(())); } else if self.conn.can_read_head() { try_ready!(self.poll_read_head()); } else if let Some(mut body) = self.body_tx.take() { if self.conn.can_read_body() { match body.poll_ready() { Ok(Async::Ready(())) => (), Ok(Async::NotReady) => { self.body_tx = Some(body); return Ok(Async::NotReady); }, Err(_canceled) => { // user doesn't care about the body // so we should stop reading trace!("body receiver dropped before eof, closing"); self.conn.close_read(); return Ok(Async::Ready(())); } } match self.conn.read_body() { Ok(Async::Ready(Some(chunk))) => { match body.send_data(chunk) { Ok(()) => { self.body_tx = Some(body); }, Err(_canceled) => { if self.conn.can_read_body() { trace!("body receiver dropped before eof, closing"); self.conn.close_read(); } } } }, Ok(Async::Ready(None)) => { // just drop, the body will close automatically }, Ok(Async::NotReady) => { self.body_tx = Some(body); return Ok(Async::NotReady); } Err(e) => { body.send_error(::Error::new_body(e)); } } } else { // just drop, the body will close automatically } } else { return self.conn.read_keep_alive(); } } } fn poll_read_head(&mut self) -> Poll<(), ::Error> { // can dispatch receive, or does it still care about, an incoming message? match self.dispatch.poll_ready() { Ok(Async::Ready(())) => (), Ok(Async::NotReady) => return Ok(Async::NotReady), // service might not be ready Err(()) => { trace!("dispatch no longer receiving messages"); self.close(); return Ok(Async::Ready(())); } } // dispatch is ready for a message, try to read one match self.conn.read_head() { Ok(Async::Ready(Some((head, body_len, wants_upgrade)))) => { let mut body = match body_len { DecodedLength::ZERO => Body::empty(), other => { let (tx, rx) = Body::new_channel(other.into_opt()); self.body_tx = Some(tx); rx }, }; if wants_upgrade { body.set_on_upgrade(self.conn.on_upgrade()); } self.dispatch.recv_msg(Ok((head, body)))?; Ok(Async::Ready(())) } Ok(Async::Ready(None)) => { // read eof, conn will start to shutdown automatically Ok(Async::Ready(())) } Ok(Async::NotReady) => Ok(Async::NotReady), Err(err) => { debug!("read_head error: {}", err); self.dispatch.recv_msg(Err(err))?; // if here, the dispatcher gave the user the error // somewhere else. we still need to shutdown, but // not as a second error. Ok(Async::Ready(())) } } } fn poll_write(&mut self) -> Poll<(), ::Error> { loop { if self.is_closing { return Ok(Async::Ready(())); } else if self.body_rx.is_none() && self.conn.can_write_head() && self.dispatch.should_poll() { if let Some((head, mut body)) = try_ready!(self.dispatch.poll_msg().map_err(::Error::new_user_service)) { // Check if the body knows its full data immediately. // // If so, we can skip a bit of bookkeeping that streaming // bodies need to do. if let Some(full) = body.__hyper_full_data(FullDataArg(())).0 { self.conn.write_full_msg(head, full); return Ok(Async::Ready(())); } let body_type = if body.is_end_stream() { self.body_rx = None; None } else { let btype = body.content_length() .map(BodyLength::Known) .or_else(|| Some(BodyLength::Unknown)); self.body_rx = Some(body); btype }; self.conn.write_head(head, body_type); } else { self.close(); return Ok(Async::Ready(())); } } else if !self.conn.can_buffer_body() { try_ready!(self.poll_flush()); } else if let Some(mut body) = self.body_rx.take() { if !self.conn.can_write_body() { trace!( "no more write body allowed, user body is_end_stream = {}", body.is_end_stream(), ); continue; } match body.poll_data().map_err(::Error::new_user_body)? { Async::Ready(Some(chunk)) => { let eos = body.is_end_stream(); if eos { if chunk.remaining() == 0 { trace!("discarding empty chunk"); self.conn.end_body(); } else { self.conn.write_body_and_end(chunk); } } else { self.body_rx = Some(body); if chunk.remaining() == 0 { trace!("discarding empty chunk"); continue; } self.conn.write_body(chunk); } }, Async::Ready(None) => { self.conn.end_body(); }, Async::NotReady => { self.body_rx = Some(body); return Ok(Async::NotReady); } } } else { return Ok(Async::NotReady); } } } fn poll_flush(&mut self) -> Poll<(), ::Error> { self.conn.flush().map_err(|err| { debug!("error writing: {}", err); ::Error::new_body_write(err) }) } fn close(&mut self) { self.is_closing = true; self.conn.close_read(); self.conn.close_write(); } fn is_done(&self) -> bool { if self.is_closing { return true; } let read_done = self.conn.is_read_closed(); if !T::should_read_first() && read_done { // a client that cannot read may was well be done. true } else { let write_done = self.conn.is_write_closed() || (!self.dispatch.should_poll() && self.body_rx.is_none()); read_done && write_done } } } impl Future for Dispatcher where D: Dispatch, PollBody=Bs, RecvItem=MessageHead>, D::PollError: Into>, I: AsyncRead + AsyncWrite, T: Http1Transaction, Bs: Payload, { type Item = Dispatched; type Error = ::Error; #[inline] fn poll(&mut self) -> Poll { self.poll_catch(true) } } // ===== impl Server ===== impl Server where S: Service { pub fn new(service: S) -> Server { Server { in_flight: None, service: service, } } pub fn into_service(self) -> S { self.service } } impl Dispatch for Server where S: Service, S::Error: Into>, Bs: Payload, { type PollItem = MessageHead; type PollBody = Bs; type PollError = S::Error; type RecvItem = RequestHead; fn poll_msg(&mut self) -> Poll, Self::PollError> { if let Some(mut fut) = self.in_flight.take() { let resp = match fut.poll()? { Async::Ready(res) => res, Async::NotReady => { self.in_flight = Some(fut); return Ok(Async::NotReady); } }; let (parts, body) = resp.into_parts(); let head = MessageHead { version: parts.version, subject: parts.status, headers: parts.headers, }; Ok(Async::Ready(Some((head, body)))) } else { unreachable!("poll_msg shouldn't be called if no inflight"); } } fn recv_msg(&mut self, msg: ::Result<(Self::RecvItem, Body)>) -> ::Result<()> { let (msg, body) = msg?; let mut req = Request::new(body); *req.method_mut() = msg.subject.0; *req.uri_mut() = msg.subject.1; *req.headers_mut() = msg.headers; *req.version_mut() = msg.version; self.in_flight = Some(self.service.call(req)); Ok(()) } fn poll_ready(&mut self) -> Poll<(), ()> { if self.in_flight.is_some() { Ok(Async::NotReady) } else { self.service.poll_ready() .map_err(|_e| { // FIXME: return error value. trace!("service closed"); }) } } fn should_poll(&self) -> bool { self.in_flight.is_some() } } // ===== impl Client ===== impl Client { pub fn new(rx: ClientRx) -> Client { Client { callback: None, rx: rx, } } } impl Dispatch for Client where B: Payload, { type PollItem = RequestHead; type PollBody = B; type PollError = Never; type RecvItem = ResponseHead; fn poll_msg(&mut self) -> Poll, Never> { match self.rx.poll() { Ok(Async::Ready(Some((req, mut cb)))) => { // check that future hasn't been canceled already match cb.poll_cancel().expect("poll_cancel cannot error") { Async::Ready(()) => { trace!("request canceled"); Ok(Async::Ready(None)) }, Async::NotReady => { let (parts, body) = req.into_parts(); let head = RequestHead { version: parts.version, subject: RequestLine(parts.method, parts.uri), headers: parts.headers, }; self.callback = Some(cb); Ok(Async::Ready(Some((head, body)))) } } }, Ok(Async::Ready(None)) => { trace!("client tx closed"); // user has dropped sender handle Ok(Async::Ready(None)) }, Ok(Async::NotReady) => Ok(Async::NotReady), Err(never) => match never {}, } } fn recv_msg(&mut self, msg: ::Result<(Self::RecvItem, Body)>) -> ::Result<()> { match msg { Ok((msg, body)) => { if let Some(cb) = self.callback.take() { let mut res = Response::new(body); *res.status_mut() = msg.subject; *res.headers_mut() = msg.headers; *res.version_mut() = msg.version; let _ = cb.send(Ok(res)); Ok(()) } else { // Getting here is likely a bug! An error should have happened // in Conn::require_empty_read() before ever parsing a // full message! Err(::Error::new_unexpected_message()) } }, Err(err) => { if let Some(cb) = self.callback.take() { let _ = cb.send(Err((err, None))); Ok(()) } else if let Ok(Async::Ready(Some((req, cb)))) = self.rx.poll() { trace!("canceling queued request with connection error: {}", err); // in this case, the message was never even started, so it's safe to tell // the user that the request was completely canceled let _ = cb.send(Err((::Error::new_canceled().with(err), Some(req)))); Ok(()) } else { Err(err) } } } } fn poll_ready(&mut self) -> Poll<(), ()> { match self.callback { Some(ref mut cb) => match cb.poll_cancel() { Ok(Async::Ready(())) => { trace!("callback receiver has dropped"); Err(()) }, Ok(Async::NotReady) => Ok(Async::Ready(())), Err(_) => unreachable!("oneshot poll_cancel cannot error"), }, None => Err(()), } } fn should_poll(&self) -> bool { self.callback.is_none() } } #[cfg(test)] mod tests { extern crate pretty_env_logger; use super::*; use mock::AsyncIo; use proto::h1::ClientTransaction; #[test] fn client_read_bytes_before_writing_request() { let _ = pretty_env_logger::try_init(); ::futures::lazy(|| { // Block at 0 for now, but we will release this response before // the request is ready to write later... let io = AsyncIo::new_buf(b"HTTP/1.1 200 OK\r\n\r\n".to_vec(), 0); let (mut tx, rx) = ::client::dispatch::channel(); let conn = Conn::<_, ::Chunk, ClientTransaction>::new(io); let mut dispatcher = Dispatcher::new(Client::new(rx), conn); // First poll is needed to allow tx to send... assert!(dispatcher.poll().expect("nothing is ready").is_not_ready()); // Unblock our IO, which has a response before we've sent request! dispatcher.conn.io_mut().block_in(100); let res_rx = tx.try_send(::Request::new(::Body::empty())).unwrap(); let a1 = dispatcher.poll().expect("error should be sent on channel"); assert!(a1.is_ready(), "dispatcher should be closed"); let err = res_rx.wait() .expect("callback poll") .expect_err("callback response"); match (err.0.kind(), err.1) { (&::error::Kind::Canceled, Some(_)) => (), other => panic!("expected Canceled, got {:?}", other), } Ok::<(), ()>(()) }).wait().unwrap(); } #[test] fn body_empty_chunks_ignored() { let _ = pretty_env_logger::try_init(); ::futures::lazy(|| { let io = AsyncIo::new_buf(vec![], 0); let (mut tx, rx) = ::client::dispatch::channel(); let conn = Conn::<_, ::Chunk, ClientTransaction>::new(io); let mut dispatcher = Dispatcher::new(Client::new(rx), conn); // First poll is needed to allow tx to send... assert!(dispatcher.poll().expect("nothing is ready").is_not_ready()); let body = ::Body::wrap_stream(::futures::stream::once(Ok::<_, ::Error>(""))); let _res_rx = tx.try_send(::Request::new(body)).unwrap(); dispatcher.poll().expect("empty body shouldn't panic"); Ok::<(), ()>(()) }).wait().unwrap(); } } hyper-0.12.35/src/proto/h1/encode.rs010066400017500001750000000261361353675567300153350ustar0000000000000000use std::fmt; use bytes::{Buf, IntoBuf}; use bytes::buf::{Chain, Take}; use iovec::IoVec; use common::StaticBuf; use super::io::WriteBuf; /// Encoders to handle different Transfer-Encodings. #[derive(Debug, Clone, PartialEq)] pub struct Encoder { kind: Kind, is_last: bool, } #[derive(Debug)] pub struct EncodedBuf { kind: BufKind, } #[derive(Debug)] pub struct NotEof; #[derive(Debug, PartialEq, Clone)] enum Kind { /// An Encoder for when Transfer-Encoding includes `chunked`. Chunked, /// An Encoder for when Content-Length is set. /// /// Enforces that the body is not longer than the Content-Length header. Length(u64), /// An Encoder for when neither Content-Length nore Chunked encoding is set. /// /// 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. CloseDelimited, } #[derive(Debug)] enum BufKind { Exact(B), Limited(Take), Chunked(Chain, StaticBuf>), ChunkedEnd(StaticBuf), } impl Encoder { fn new(kind: Kind) -> Encoder { Encoder { kind: kind, is_last: false, } } pub fn chunked() -> Encoder { Encoder::new(Kind::Chunked) } pub fn length(len: u64) -> Encoder { Encoder::new(Kind::Length(len)) } pub fn close_delimited() -> Encoder { Encoder::new(Kind::CloseDelimited) } pub fn is_eof(&self) -> bool { match self.kind { Kind::Length(0) => true, _ => false } } pub fn set_last(mut self, is_last: bool) -> Self { self.is_last = is_last; self } pub fn is_last(&self) -> bool { self.is_last } pub fn end(&self) -> Result>, NotEof> { match self.kind { Kind::Length(0) => Ok(None), Kind::Chunked => Ok(Some(EncodedBuf { kind: BufKind::ChunkedEnd(StaticBuf(b"0\r\n\r\n")), })), _ => Err(NotEof), } } pub fn encode(&mut self, msg: B) -> EncodedBuf where B: IntoBuf, { let msg = msg.into_buf(); let len = msg.remaining(); debug_assert!(len > 0, "encode() called with empty buf"); let kind = match self.kind { Kind::Chunked => { trace!("encoding chunked {}B", len); let buf = ChunkSize::new(len) .chain(msg) .chain(StaticBuf(b"\r\n")); BufKind::Chunked(buf) }, Kind::Length(ref mut remaining) => { trace!("sized write, len = {}", len); if len as u64 > *remaining { let limit = *remaining as usize; *remaining = 0; BufKind::Limited(msg.take(limit)) } else { *remaining -= len as u64; BufKind::Exact(msg) } }, Kind::CloseDelimited => { trace!("close delimited write {}B", len); BufKind::Exact(msg) } }; EncodedBuf { kind, } } pub(super) fn encode_and_end(&self, msg: B, dst: &mut WriteBuf>) -> bool where B: IntoBuf, { let msg = msg.into_buf(); let len = msg.remaining(); debug_assert!(len > 0, "encode() called with empty buf"); match self.kind { Kind::Chunked => { trace!("encoding chunked {}B", len); let buf = ChunkSize::new(len) .chain(msg) .chain(StaticBuf(b"\r\n0\r\n\r\n")); dst.buffer(buf); !self.is_last }, Kind::Length(remaining) => { use std::cmp::Ordering; trace!("sized write, len = {}", len); match (len as u64).cmp(&remaining) { Ordering::Equal => { dst.buffer(msg); !self.is_last }, Ordering::Greater => { dst.buffer(msg.take(remaining as usize)); !self.is_last }, Ordering::Less => { dst.buffer(msg); false } } }, Kind::CloseDelimited => { trace!("close delimited write {}B", len); dst.buffer(msg); false } } } /// Encodes the full body, without verifying the remaining length matches. /// /// This is used in conjunction with Payload::__hyper_full_data(), which /// means we can trust that the buf has the correct size (the buf itself /// was checked to make the headers). pub(super) fn danger_full_buf(self, msg: B, dst: &mut WriteBuf>) where B: IntoBuf, { let msg = msg.into_buf(); debug_assert!(msg.remaining() > 0, "encode() called with empty buf"); debug_assert!(match self.kind { Kind::Length(len) => len == msg.remaining() as u64, _ => true, }, "danger_full_buf length mismatches"); match self.kind { Kind::Chunked => { let len = msg.remaining(); trace!("encoding chunked {}B", len); let buf = ChunkSize::new(len) .chain(msg) .chain(StaticBuf(b"\r\n0\r\n\r\n")); dst.buffer(buf); }, _ => { dst.buffer(msg); }, } } } impl Buf for EncodedBuf where B: Buf, { #[inline] fn remaining(&self) -> usize { match self.kind { BufKind::Exact(ref b) => b.remaining(), BufKind::Limited(ref b) => b.remaining(), BufKind::Chunked(ref b) => b.remaining(), BufKind::ChunkedEnd(ref b) => b.remaining(), } } #[inline] fn bytes(&self) -> &[u8] { match self.kind { BufKind::Exact(ref b) => b.bytes(), BufKind::Limited(ref b) => b.bytes(), BufKind::Chunked(ref b) => b.bytes(), BufKind::ChunkedEnd(ref b) => b.bytes(), } } #[inline] fn advance(&mut self, cnt: usize) { match self.kind { BufKind::Exact(ref mut b) => b.advance(cnt), BufKind::Limited(ref mut b) => b.advance(cnt), BufKind::Chunked(ref mut b) => b.advance(cnt), BufKind::ChunkedEnd(ref mut b) => b.advance(cnt), } } #[inline] fn bytes_vec<'t>(&'t self, dst: &mut [&'t IoVec]) -> usize { match self.kind { BufKind::Exact(ref b) => b.bytes_vec(dst), BufKind::Limited(ref b) => b.bytes_vec(dst), BufKind::Chunked(ref b) => b.bytes_vec(dst), BufKind::ChunkedEnd(ref b) => b.bytes_vec(dst), } } } #[cfg(target_pointer_width = "32")] const USIZE_BYTES: usize = 4; #[cfg(target_pointer_width = "64")] const USIZE_BYTES: usize = 8; // each byte will become 2 hex const CHUNK_SIZE_MAX_BYTES: usize = USIZE_BYTES * 2; #[derive(Clone, Copy)] struct ChunkSize { bytes: [u8; CHUNK_SIZE_MAX_BYTES + 2], pos: u8, len: u8, } impl ChunkSize { fn new(len: usize) -> ChunkSize { use std::fmt::Write; let mut size = ChunkSize { bytes: [0; CHUNK_SIZE_MAX_BYTES + 2], pos: 0, len: 0, }; write!(&mut size, "{:X}\r\n", len) .expect("CHUNK_SIZE_MAX_BYTES should fit any usize"); size } } impl Buf for ChunkSize { #[inline] fn remaining(&self) -> usize { (self.len - self.pos).into() } #[inline] fn bytes(&self) -> &[u8] { &self.bytes[self.pos.into() .. self.len.into()] } #[inline] fn advance(&mut self, cnt: usize) { assert!(cnt <= self.remaining()); self.pos += cnt as u8; // just asserted cnt fits in u8 } } impl fmt::Debug for ChunkSize { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("ChunkSize") .field("bytes", &&self.bytes[..self.len.into()]) .field("pos", &self.pos) .finish() } } impl fmt::Write for ChunkSize { fn write_str(&mut self, num: &str) -> fmt::Result { use std::io::Write; (&mut self.bytes[self.len.into()..]).write(num.as_bytes()) .expect("&mut [u8].write() cannot error"); self.len += num.len() as u8; // safe because bytes is never bigger than 256 Ok(()) } } impl From for EncodedBuf { fn from(buf: B) -> Self { EncodedBuf { kind: BufKind::Exact(buf), } } } impl From> for EncodedBuf { fn from(buf: Take) -> Self { EncodedBuf { kind: BufKind::Limited(buf), } } } impl From, StaticBuf>> for EncodedBuf { fn from(buf: Chain, StaticBuf>) -> Self { EncodedBuf { kind: BufKind::Chunked(buf), } } } #[cfg(test)] mod tests { use bytes::{BufMut}; use super::super::io::Cursor; use super::Encoder; #[test] fn chunked() { let mut encoder = Encoder::chunked(); let mut dst = Vec::new(); let msg1 = b"foo bar".as_ref(); let buf1 = encoder.encode(msg1); dst.put(buf1); assert_eq!(dst, b"7\r\nfoo bar\r\n"); let msg2 = b"baz quux herp".as_ref(); let buf2 = encoder.encode(msg2); dst.put(buf2); assert_eq!(dst, b"7\r\nfoo bar\r\nD\r\nbaz quux herp\r\n"); let end = encoder.end::>>().unwrap().unwrap(); dst.put(end); assert_eq!(dst, b"7\r\nfoo bar\r\nD\r\nbaz quux herp\r\n0\r\n\r\n".as_ref()); } #[test] fn length() { let max_len = 8; let mut encoder = Encoder::length(max_len as u64); let mut dst = Vec::new(); let msg1 = b"foo bar".as_ref(); let buf1 = encoder.encode(msg1); dst.put(buf1); assert_eq!(dst, b"foo bar"); assert!(!encoder.is_eof()); encoder.end::<()>().unwrap_err(); let msg2 = b"baz".as_ref(); let buf2 = encoder.encode(msg2); dst.put(buf2); assert_eq!(dst.len(), max_len); assert_eq!(dst, b"foo barb"); assert!(encoder.is_eof()); assert!(encoder.end::<()>().unwrap().is_none()); } #[test] fn eof() { let mut encoder = Encoder::close_delimited(); let mut dst = Vec::new(); let msg1 = b"foo bar".as_ref(); let buf1 = encoder.encode(msg1); dst.put(buf1); assert_eq!(dst, b"foo bar"); assert!(!encoder.is_eof()); encoder.end::<()>().unwrap_err(); let msg2 = b"baz".as_ref(); let buf2 = encoder.encode(msg2); dst.put(buf2); assert_eq!(dst, b"foo barbaz"); assert!(!encoder.is_eof()); encoder.end::<()>().unwrap_err(); } } hyper-0.12.35/src/proto/h1/io.rs010066400017500001750000000642411353675567300145060ustar0000000000000000use std::cell::Cell; use std::cmp; use std::collections::VecDeque; use std::fmt; use std::io; use bytes::{Buf, BufMut, Bytes, BytesMut}; use futures::{Async, Poll}; use iovec::IoVec; use tokio_io::{AsyncRead, AsyncWrite}; use super::{Http1Transaction, ParseContext, ParsedMessage}; /// The initial buffer size allocated before trying to read from IO. pub(crate) const INIT_BUFFER_SIZE: usize = 8192; /// The minimum value that can be set to max buffer size. pub const MINIMUM_MAX_BUFFER_SIZE: usize = INIT_BUFFER_SIZE; /// The default maximum read buffer size. If the buffer gets this big and /// a message is still not complete, a `TooLarge` error is triggered. // Note: if this changes, update server::conn::Http::max_buf_size docs. pub(crate) const DEFAULT_MAX_BUFFER_SIZE: usize = 8192 + 4096 * 100; /// The maximum number of distinct `Buf`s to hold in a list before requiring /// a flush. Only affects when the buffer strategy is to queue buffers. /// /// Note that a flush can happen before reaching the maximum. This simply /// forces a flush if the queue gets this big. const MAX_BUF_LIST_BUFFERS: usize = 16; pub struct Buffered { flush_pipeline: bool, io: T, read_blocked: bool, read_buf: BytesMut, read_buf_strategy: ReadStrategy, write_buf: WriteBuf, } impl fmt::Debug for Buffered where B: Buf, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Buffered") .field("read_buf", &self.read_buf) .field("write_buf", &self.write_buf) .finish() } } impl Buffered where T: AsyncRead + AsyncWrite, B: Buf, { pub fn new(io: T) -> Buffered { Buffered { flush_pipeline: false, io: io, read_blocked: false, read_buf: BytesMut::with_capacity(0), read_buf_strategy: ReadStrategy::default(), write_buf: WriteBuf::new(), } } pub fn set_flush_pipeline(&mut self, enabled: bool) { debug_assert!(!self.write_buf.has_remaining()); self.flush_pipeline = enabled; if enabled { self.set_write_strategy_flatten(); } } pub fn set_max_buf_size(&mut self, max: usize) { assert!( max >= MINIMUM_MAX_BUFFER_SIZE, "The max_buf_size cannot be smaller than {}.", MINIMUM_MAX_BUFFER_SIZE, ); self.read_buf_strategy = ReadStrategy::with_max(max); self.write_buf.max_buf_size = max; } pub fn set_read_buf_exact_size(&mut self, sz: usize) { self.read_buf_strategy = ReadStrategy::Exact(sz); } pub fn set_write_strategy_flatten(&mut self) { // this should always be called only at construction time, // so this assert is here to catch myself debug_assert!(self.write_buf.queue.bufs.is_empty()); self.write_buf.set_strategy(WriteStrategy::Flatten); } pub fn read_buf(&self) -> &[u8] { self.read_buf.as_ref() } #[cfg(test)] #[cfg(feature = "nightly")] pub(super) fn read_buf_mut(&mut self) -> &mut BytesMut { &mut self.read_buf } pub fn headers_buf(&mut self) -> &mut Vec { let buf = self.write_buf.headers_mut(); &mut buf.bytes } pub(super) fn write_buf(&mut self) -> &mut WriteBuf { &mut self.write_buf } pub fn buffer>(&mut self, buf: BB) { self.write_buf.buffer(buf) } pub fn can_buffer(&self) -> bool { self.flush_pipeline || self.write_buf.can_buffer() } pub fn consume_leading_lines(&mut self) { if !self.read_buf.is_empty() { let mut i = 0; while i < self.read_buf.len() { match self.read_buf[i] { b'\r' | b'\n' => i += 1, _ => break, } } self.read_buf.split_to(i); } } pub(super) fn parse(&mut self, ctx: ParseContext) -> Poll, ::Error> where S: Http1Transaction, { loop { match S::parse(&mut self.read_buf, ParseContext { cached_headers: ctx.cached_headers, req_method: ctx.req_method, })? { Some(msg) => { debug!("parsed {} headers", msg.head.headers.len()); return Ok(Async::Ready(msg)) }, None => { let max = self.read_buf_strategy.max(); if self.read_buf.len() >= max { debug!("max_buf_size ({}) reached, closing", max); return Err(::Error::new_too_large()); } }, } match try_ready!(self.read_from_io().map_err(::Error::new_io)) { 0 => { trace!("parse eof"); return Err(::Error::new_incomplete()); } _ => {}, } } } pub fn read_from_io(&mut self) -> Poll { self.read_blocked = false; let next = self.read_buf_strategy.next(); if self.read_buf.remaining_mut() < next { self.read_buf.reserve(next); } self.io.read_buf(&mut self.read_buf).map(|ok| { match ok { Async::Ready(n) => { debug!("read {} bytes", n); self.read_buf_strategy.record(n); Async::Ready(n) }, Async::NotReady => { self.read_blocked = true; Async::NotReady } } }) } pub fn into_inner(self) -> (T, Bytes) { (self.io, self.read_buf.freeze()) } pub fn io_mut(&mut self) -> &mut T { &mut self.io } pub fn is_read_blocked(&self) -> bool { self.read_blocked } pub fn flush(&mut self) -> Poll<(), io::Error> { if self.flush_pipeline && !self.read_buf.is_empty() { //Ok(()) } else if self.write_buf.remaining() == 0 { try_nb!(self.io.flush()); } else { match self.write_buf.strategy { WriteStrategy::Flatten => return self.flush_flattened(), _ => (), } loop { let n = try_ready!(self.io.write_buf(&mut self.write_buf.auto())); debug!("flushed {} bytes", n); if self.write_buf.remaining() == 0 { break; } else if n == 0 { trace!("write returned zero, but {} bytes remaining", self.write_buf.remaining()); return Err(io::ErrorKind::WriteZero.into()) } } try_nb!(self.io.flush()) } Ok(Async::Ready(())) } /// Specialized version of `flush` when strategy is Flatten. /// /// Since all buffered bytes are flattened into the single headers buffer, /// that skips some bookkeeping around using multiple buffers. fn flush_flattened(&mut self) -> Poll<(), io::Error> { loop { let n = try_nb!(self.io.write(self.write_buf.headers.bytes())); debug!("flushed {} bytes", n); self.write_buf.headers.advance(n); if self.write_buf.headers.remaining() == 0 { self.write_buf.headers.reset(); break; } else if n == 0 { trace!("write returned zero, but {} bytes remaining", self.write_buf.remaining()); return Err(io::ErrorKind::WriteZero.into()) } } try_nb!(self.io.flush()); Ok(Async::Ready(())) } } pub trait MemRead { fn read_mem(&mut self, len: usize) -> Poll; } impl MemRead for Buffered where T: AsyncRead + AsyncWrite, B: Buf, { fn read_mem(&mut self, len: usize) -> Poll { if !self.read_buf.is_empty() { let n = ::std::cmp::min(len, self.read_buf.len()); Ok(Async::Ready(self.read_buf.split_to(n).freeze())) } else { let n = try_ready!(self.read_from_io()); Ok(Async::Ready(self.read_buf.split_to(::std::cmp::min(len, n)).freeze())) } } } #[derive(Clone, Copy, Debug)] enum ReadStrategy { Adaptive { decrease_now: bool, next: usize, max: usize }, Exact(usize), } impl ReadStrategy { fn with_max(max: usize) -> ReadStrategy { ReadStrategy::Adaptive { decrease_now: false, next: INIT_BUFFER_SIZE, max, } } fn next(&self) -> usize { match *self { ReadStrategy::Adaptive { next, .. } => next, ReadStrategy::Exact(exact) => exact, } } fn max(&self) -> usize { match *self { ReadStrategy::Adaptive { max, .. } => max, ReadStrategy::Exact(exact) => exact, } } fn record(&mut self, bytes_read: usize) { match *self { ReadStrategy::Adaptive { ref mut decrease_now, ref mut next, max, .. } => { if bytes_read >= *next { *next = cmp::min(incr_power_of_two(*next), max); *decrease_now = false; } else { let decr_to = prev_power_of_two(*next); if bytes_read < decr_to { if *decrease_now { *next = cmp::max(decr_to, INIT_BUFFER_SIZE); *decrease_now = false; } else { // Decreasing is a two "record" process. *decrease_now = true; } } else { // A read within the current range should cancel // a potential decrease, since we just saw proof // that we still need this size. *decrease_now = false; } } }, _ => (), } } } fn incr_power_of_two(n: usize) -> usize { n.saturating_mul(2) } fn prev_power_of_two(n: usize) -> usize { // Only way this shift can underflow is if n is less than 4. // (Which would means `usize::MAX >> 64` and underflowed!) debug_assert!(n >= 4); (::std::usize::MAX >> (n.leading_zeros() + 2)) + 1 } impl Default for ReadStrategy { fn default() -> ReadStrategy { ReadStrategy::with_max(DEFAULT_MAX_BUFFER_SIZE) } } #[derive(Clone)] pub struct Cursor { bytes: T, pos: usize, } impl> Cursor { #[inline] pub(crate) fn new(bytes: T) -> Cursor { Cursor { bytes: bytes, pos: 0, } } } impl Cursor> { fn reset(&mut self) { self.pos = 0; self.bytes.clear(); } } impl> fmt::Debug for Cursor { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Cursor") .field("pos", &self.pos) .field("len", &self.bytes.as_ref().len()) .finish() } } impl> Buf for Cursor { #[inline] fn remaining(&self) -> usize { self.bytes.as_ref().len() - self.pos } #[inline] fn bytes(&self) -> &[u8] { &self.bytes.as_ref()[self.pos..] } #[inline] fn advance(&mut self, cnt: usize) { debug_assert!(self.pos + cnt <= self.bytes.as_ref().len()); self.pos += cnt; } } // an internal buffer to collect writes before flushes pub(super) struct WriteBuf { /// Re-usable buffer that holds message headers headers: Cursor>, max_buf_size: usize, /// Deque of user buffers if strategy is Queue queue: BufDeque, strategy: WriteStrategy, } impl WriteBuf { fn new() -> WriteBuf { WriteBuf { headers: Cursor::new(Vec::with_capacity(INIT_BUFFER_SIZE)), max_buf_size: DEFAULT_MAX_BUFFER_SIZE, queue: BufDeque::new(), strategy: WriteStrategy::Auto, } } } impl WriteBuf where B: Buf, { fn set_strategy(&mut self, strategy: WriteStrategy) { self.strategy = strategy; } #[inline] fn auto(&mut self) -> WriteBufAuto { WriteBufAuto::new(self) } pub(super) fn buffer>(&mut self, mut buf: BB) { debug_assert!(buf.has_remaining()); match self.strategy { WriteStrategy::Flatten => { let head = self.headers_mut(); //perf: This is a little faster than >::put, //but accomplishes the same result. loop { let adv = { let slice = buf.bytes(); if slice.is_empty() { return; } head.bytes.extend_from_slice(slice); slice.len() }; buf.advance(adv); } }, WriteStrategy::Auto | WriteStrategy::Queue => { self.queue.bufs.push_back(buf.into()); }, } } fn can_buffer(&self) -> bool { match self.strategy { WriteStrategy::Flatten => { self.remaining() < self.max_buf_size }, WriteStrategy::Auto | WriteStrategy::Queue => { self.queue.bufs.len() < MAX_BUF_LIST_BUFFERS && self.remaining() < self.max_buf_size }, } } fn headers_mut(&mut self) -> &mut Cursor> { debug_assert!(!self.queue.has_remaining()); &mut self.headers } } impl fmt::Debug for WriteBuf { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("WriteBuf") .field("remaining", &self.remaining()) .field("strategy", &self.strategy) .finish() } } impl Buf for WriteBuf { #[inline] fn remaining(&self) -> usize { self.headers.remaining() + self.queue.remaining() } #[inline] fn bytes(&self) -> &[u8] { let headers = self.headers.bytes(); if !headers.is_empty() { headers } else { self.queue.bytes() } } #[inline] fn advance(&mut self, cnt: usize) { let hrem = self.headers.remaining(); if hrem == cnt { self.headers.reset(); } else if hrem > cnt { self.headers.advance(cnt); } else { let qcnt = cnt - hrem; self.headers.reset(); self.queue.advance(qcnt); } } #[inline] fn bytes_vec<'t>(&'t self, dst: &mut [&'t IoVec]) -> usize { let n = self.headers.bytes_vec(dst); self.queue.bytes_vec(&mut dst[n..]) + n } } /// Detects when wrapped `WriteBuf` is used for vectored IO, and /// adjusts the `WriteBuf` strategy if not. struct WriteBufAuto<'a, B: Buf + 'a> { bytes_called: Cell, bytes_vec_called: Cell, inner: &'a mut WriteBuf, } impl<'a, B: Buf> WriteBufAuto<'a, B> { fn new(inner: &'a mut WriteBuf) -> WriteBufAuto<'a, B> { WriteBufAuto { bytes_called: Cell::new(false), bytes_vec_called: Cell::new(false), inner: inner, } } } impl<'a, B: Buf> Buf for WriteBufAuto<'a, B> { #[inline] fn remaining(&self) -> usize { self.inner.remaining() } #[inline] fn bytes(&self) -> &[u8] { self.bytes_called.set(true); self.inner.bytes() } #[inline] fn advance(&mut self, cnt: usize) { self.inner.advance(cnt) } #[inline] fn bytes_vec<'t>(&'t self, dst: &mut [&'t IoVec]) -> usize { self.bytes_vec_called.set(true); self.inner.bytes_vec(dst) } } impl<'a, B: Buf + 'a> Drop for WriteBufAuto<'a, B> { fn drop(&mut self) { if let WriteStrategy::Auto = self.inner.strategy { if self.bytes_vec_called.get() { self.inner.strategy = WriteStrategy::Queue; } else if self.bytes_called.get() { trace!("detected no usage of vectored write, flattening"); self.inner.strategy = WriteStrategy::Flatten; self.inner.headers.bytes.put(&mut self.inner.queue); } } } } #[derive(Debug)] enum WriteStrategy { Auto, Flatten, Queue, } struct BufDeque { bufs: VecDeque, } impl BufDeque { fn new() -> BufDeque { BufDeque { bufs: VecDeque::new(), } } } impl Buf for BufDeque { #[inline] fn remaining(&self) -> usize { self.bufs.iter() .map(|buf| buf.remaining()) .sum() } #[inline] fn bytes(&self) -> &[u8] { for buf in &self.bufs { return buf.bytes(); } &[] } #[inline] fn advance(&mut self, mut cnt: usize) { while cnt > 0 { { let front = &mut self.bufs[0]; let rem = front.remaining(); if rem > cnt { front.advance(cnt); return; } else { front.advance(rem); cnt -= rem; } } self.bufs.pop_front(); } } #[inline] fn bytes_vec<'t>(&'t self, dst: &mut [&'t IoVec]) -> usize { if dst.is_empty() { return 0; } let mut vecs = 0; for buf in &self.bufs { vecs += buf.bytes_vec(&mut dst[vecs..]); if vecs == dst.len() { break; } } vecs } } #[cfg(test)] mod tests { use super::*; use std::io::Read; use mock::AsyncIo; #[cfg(feature = "nightly")] use test::Bencher; #[cfg(test)] impl MemRead for ::mock::AsyncIo { fn read_mem(&mut self, len: usize) -> Poll { let mut v = vec![0; len]; let n = try_nb!(self.read(v.as_mut_slice())); Ok(Async::Ready(BytesMut::from(&v[..n]).freeze())) } } #[test] fn iobuf_write_empty_slice() { let mut mock = AsyncIo::new_buf(vec![], 256); mock.error(io::Error::new(io::ErrorKind::Other, "logic error")); let mut io_buf = Buffered::<_, Cursor>>::new(mock); // underlying io will return the logic error upon write, // so we are testing that the io_buf does not trigger a write // when there is nothing to flush io_buf.flush().expect("should short-circuit flush"); } #[test] fn parse_reads_until_blocked() { // missing last line ending let raw = "HTTP/1.1 200 OK\r\n"; let mock = AsyncIo::new_buf(raw, raw.len()); let mut buffered = Buffered::<_, Cursor>>::new(mock); let ctx = ParseContext { cached_headers: &mut None, req_method: &mut None, }; assert!(buffered.parse::<::proto::h1::ClientTransaction>(ctx).unwrap().is_not_ready()); assert!(buffered.io.blocked()); } #[test] fn read_strategy_adaptive_increments() { let mut strategy = ReadStrategy::default(); assert_eq!(strategy.next(), 8192); // Grows if record == next strategy.record(8192); assert_eq!(strategy.next(), 16384); strategy.record(16384); assert_eq!(strategy.next(), 32768); // Enormous records still increment at same rate strategy.record(::std::usize::MAX); assert_eq!(strategy.next(), 65536); let max = strategy.max(); while strategy.next() < max { strategy.record(max); } assert_eq!(strategy.next(), max, "never goes over max"); strategy.record(max + 1); assert_eq!(strategy.next(), max, "never goes over max"); } #[test] fn read_strategy_adaptive_decrements() { let mut strategy = ReadStrategy::default(); strategy.record(8192); assert_eq!(strategy.next(), 16384); strategy.record(1); assert_eq!(strategy.next(), 16384, "first smaller record doesn't decrement yet"); strategy.record(8192); assert_eq!(strategy.next(), 16384, "record was with range"); strategy.record(1); assert_eq!(strategy.next(), 16384, "in-range record should make this the 'first' again"); strategy.record(1); assert_eq!(strategy.next(), 8192, "second smaller record decrements"); strategy.record(1); assert_eq!(strategy.next(), 8192, "first doesn't decrement"); strategy.record(1); assert_eq!(strategy.next(), 8192, "doesn't decrement under minimum"); } #[test] fn read_strategy_adaptive_stays_the_same() { let mut strategy = ReadStrategy::default(); strategy.record(8192); assert_eq!(strategy.next(), 16384); strategy.record(8193); assert_eq!(strategy.next(), 16384, "first smaller record doesn't decrement yet"); strategy.record(8193); assert_eq!(strategy.next(), 16384, "with current step does not decrement"); } #[test] fn read_strategy_adaptive_max_fuzz() { fn fuzz(max: usize) { let mut strategy = ReadStrategy::with_max(max); while strategy.next() < max { strategy.record(::std::usize::MAX); } let mut next = strategy.next(); while next > 8192 { strategy.record(1); strategy.record(1); next = strategy.next(); assert!( next.is_power_of_two(), "decrement should be powers of two: {} (max = {})", next, max, ); } } let mut max = 8192; while max < ::std::usize::MAX { fuzz(max); max = (max / 2).saturating_mul(3); } fuzz(::std::usize::MAX); } #[test] #[should_panic] fn write_buf_requires_non_empty_bufs() { let mock = AsyncIo::new_buf(vec![], 1024); let mut buffered = Buffered::<_, Cursor>>::new(mock); buffered.buffer(Cursor::new(Vec::new())); } #[test] fn write_buf_queue() { extern crate pretty_env_logger; let _ = pretty_env_logger::try_init(); let mock = AsyncIo::new_buf(vec![], 1024); let mut buffered = Buffered::<_, Cursor>>::new(mock); buffered.headers_buf().extend(b"hello "); buffered.buffer(Cursor::new(b"world, ".to_vec())); buffered.buffer(Cursor::new(b"it's ".to_vec())); buffered.buffer(Cursor::new(b"hyper!".to_vec())); assert_eq!(buffered.write_buf.queue.bufs.len(), 3); buffered.flush().unwrap(); assert_eq!(buffered.io, b"hello world, it's hyper!"); assert_eq!(buffered.io.num_writes(), 1); assert_eq!(buffered.write_buf.queue.bufs.len(), 0); } #[test] fn write_buf_flatten() { extern crate pretty_env_logger; let _ = pretty_env_logger::try_init(); let mock = AsyncIo::new_buf(vec![], 1024); let mut buffered = Buffered::<_, Cursor>>::new(mock); buffered.write_buf.set_strategy(WriteStrategy::Flatten); buffered.headers_buf().extend(b"hello "); buffered.buffer(Cursor::new(b"world, ".to_vec())); buffered.buffer(Cursor::new(b"it's ".to_vec())); buffered.buffer(Cursor::new(b"hyper!".to_vec())); assert_eq!(buffered.write_buf.queue.bufs.len(), 0); buffered.flush().unwrap(); assert_eq!(buffered.io, b"hello world, it's hyper!"); assert_eq!(buffered.io.num_writes(), 1); } #[test] fn write_buf_auto_flatten() { extern crate pretty_env_logger; let _ = pretty_env_logger::try_init(); let mut mock = AsyncIo::new_buf(vec![], 1024); mock.max_read_vecs(0); // disable vectored IO let mut buffered = Buffered::<_, Cursor>>::new(mock); // we have 4 buffers, but hope to detect that vectored IO isn't // being used, and switch to flattening automatically, // resulting in only 2 writes buffered.headers_buf().extend(b"hello "); buffered.buffer(Cursor::new(b"world, ".to_vec())); buffered.buffer(Cursor::new(b"it's ".to_vec())); buffered.buffer(Cursor::new(b"hyper!".to_vec())); assert_eq!(buffered.write_buf.queue.bufs.len(), 3); buffered.flush().unwrap(); assert_eq!(buffered.io, b"hello world, it's hyper!"); assert_eq!(buffered.io.num_writes(), 2); assert_eq!(buffered.write_buf.queue.bufs.len(), 0); } #[test] fn write_buf_queue_disable_auto() { extern crate pretty_env_logger; let _ = pretty_env_logger::try_init(); let mut mock = AsyncIo::new_buf(vec![], 1024); mock.max_read_vecs(0); // disable vectored IO let mut buffered = Buffered::<_, Cursor>>::new(mock); buffered.write_buf.set_strategy(WriteStrategy::Queue); // we have 4 buffers, and vec IO disabled, but explicitly said // don't try to auto detect (via setting strategy above) buffered.headers_buf().extend(b"hello "); buffered.buffer(Cursor::new(b"world, ".to_vec())); buffered.buffer(Cursor::new(b"it's ".to_vec())); buffered.buffer(Cursor::new(b"hyper!".to_vec())); assert_eq!(buffered.write_buf.queue.bufs.len(), 3); buffered.flush().unwrap(); assert_eq!(buffered.io, b"hello world, it's hyper!"); assert_eq!(buffered.io.num_writes(), 4); assert_eq!(buffered.write_buf.queue.bufs.len(), 0); } #[cfg(feature = "nightly")] #[bench] fn bench_write_buf_flatten_buffer_chunk(b: &mut Bencher) { let s = "Hello, World!"; b.bytes = s.len() as u64; let mut write_buf = WriteBuf::<::Chunk>::new(); write_buf.set_strategy(WriteStrategy::Flatten); b.iter(|| { let chunk = ::Chunk::from(s); write_buf.buffer(chunk); ::test::black_box(&write_buf); write_buf.headers.bytes.clear(); }) } } hyper-0.12.35/src/proto/h1/mod.rs010066400017500001750000000035441353675567300146550ustar0000000000000000use bytes::BytesMut; use http::{HeaderMap, Method}; use proto::{MessageHead, BodyLength, DecodedLength}; pub(crate) use self::conn::Conn; pub(crate) use self::dispatch::Dispatcher; pub use self::decode::Decoder; pub use self::encode::{EncodedBuf, Encoder}; pub use self::io::Cursor; //TODO: move out of h1::io pub use self::io::MINIMUM_MAX_BUFFER_SIZE; mod conn; pub(super) mod date; mod decode; pub(crate) mod dispatch; mod encode; mod io; mod role; pub(crate) type ServerTransaction = role::Server; pub(crate) type ClientTransaction = role::Client; pub(crate) trait Http1Transaction { type Incoming; type Outgoing: Default; const LOG: &'static str; fn parse(bytes: &mut BytesMut, ctx: ParseContext) -> ParseResult; fn encode(enc: Encode, dst: &mut Vec) -> ::Result; fn on_error(err: &::Error) -> Option>; fn is_client() -> bool { !Self::is_server() } fn is_server() -> bool { !Self::is_client() } fn should_error_on_parse_eof() -> bool { Self::is_client() } fn should_read_first() -> bool { Self::is_server() } fn update_date() {} } /// Result newtype for Http1Transaction::parse. pub(crate) type ParseResult = Result>, ::error::Parse>; #[derive(Debug)] pub(crate) struct ParsedMessage { head: MessageHead, decode: DecodedLength, expect_continue: bool, keep_alive: bool, wants_upgrade: bool, } pub(crate) struct ParseContext<'a> { cached_headers: &'a mut Option, req_method: &'a mut Option, } /// Passed to Http1Transaction::encode pub(crate) struct Encode<'a, T: 'a> { head: &'a mut MessageHead, body: Option, keep_alive: bool, req_method: &'a mut Option, title_case_headers: bool, } hyper-0.12.35/src/proto/h1/role.rs010066400017500001750000001626001353675567300150360ustar0000000000000000// `mem::uninitialized` replaced with `mem::MaybeUninit`, // can't upgrade yet #![allow(deprecated)] use std::fmt::{self, Write}; use std::mem; use bytes::{BytesMut}; use http::header::{self, Entry, HeaderName, HeaderValue}; use http::{HeaderMap, Method, StatusCode, Version}; use httparse; use error::Parse; use headers; use proto::{BodyLength, DecodedLength, MessageHead, RequestLine, RequestHead}; use proto::h1::{Encode, Encoder, Http1Transaction, ParseResult, ParseContext, ParsedMessage, date}; const MAX_HEADERS: usize = 100; const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific macro_rules! header_name { ($bytes:expr) => ({ #[cfg(debug_assertions)] { match HeaderName::from_bytes($bytes) { Ok(name) => name, Err(_) => panic!("illegal header name from httparse: {:?}", ::bytes::Bytes::from($bytes)), } } #[cfg(not(debug_assertions))] { HeaderName::from_bytes($bytes) .expect("header name validated by httparse") } }); } macro_rules! header_value { ($bytes:expr) => ({ #[cfg(debug_assertions)] { let __hvb: ::bytes::Bytes = $bytes; match HeaderValue::from_shared(__hvb.clone()) { Ok(name) => name, Err(_) => panic!("illegal header value from httparse: {:?}", __hvb), } } #[cfg(not(debug_assertions))] { // Unsafe: httparse already validated header value unsafe { HeaderValue::from_shared_unchecked($bytes) } } }); } // There are 2 main roles, Client and Server. pub(crate) enum Client {} pub(crate) enum Server {} impl Http1Transaction for Server { type Incoming = RequestLine; type Outgoing = StatusCode; const LOG: &'static str = "{role=server}"; fn parse(buf: &mut BytesMut, ctx: ParseContext) -> ParseResult { if buf.is_empty() { return Ok(None); } let mut keep_alive; let is_http_11; let subject; let version; let len; let headers_len; // Unsafe: both headers_indices and headers are using unitialized memory, // but we *never* read any of it until after httparse has assigned // values into it. By not zeroing out the stack memory, this saves // a good ~5% on pipeline benchmarks. let mut headers_indices: [HeaderIndices; MAX_HEADERS] = unsafe { mem::uninitialized() }; { let mut headers: [httparse::Header; MAX_HEADERS] = unsafe { mem::uninitialized() }; trace!("Request.parse([Header; {}], [u8; {}])", headers.len(), buf.len()); let mut req = httparse::Request::new(&mut headers); let bytes = buf.as_ref(); match req.parse(bytes) { Ok(httparse::Status::Complete(parsed_len)) => { trace!("Request.parse Complete({})", parsed_len); len = parsed_len; subject = RequestLine( Method::from_bytes(req.method.unwrap().as_bytes())?, req.path.unwrap().parse()? ); version = if req.version.unwrap() == 1 { keep_alive = true; is_http_11 = true; Version::HTTP_11 } else { keep_alive = false; is_http_11 = false; Version::HTTP_10 }; record_header_indices(bytes, &req.headers, &mut headers_indices)?; headers_len = req.headers.len(); } Ok(httparse::Status::Partial) => return Ok(None), Err(err) => return Err(match err { // if invalid Token, try to determine if for method or path httparse::Error::Token => { if req.method.is_none() { Parse::Method } else { debug_assert!(req.path.is_none()); Parse::Uri } }, other => other.into(), }), } }; let slice = buf.split_to(len).freeze(); // According to https://tools.ietf.org/html/rfc7230#section-3.3.3 // 1. (irrelevant to Request) // 2. (irrelevant to Request) // 3. Transfer-Encoding: chunked has a chunked body. // 4. If multiple differing Content-Length headers or invalid, close connection. // 5. Content-Length header has a sized body. // 6. Length 0. // 7. (irrelevant to Request) let mut decoder = DecodedLength::ZERO; let mut expect_continue = false; let mut con_len = None; let mut is_te = false; let mut is_te_chunked = false; let mut wants_upgrade = subject.0 == Method::CONNECT; let mut headers = ctx.cached_headers .take() .unwrap_or_else(HeaderMap::new); headers.reserve(headers_len); for header in &headers_indices[..headers_len] { let name = header_name!(&slice[header.name.0..header.name.1]); let value = header_value!(slice.slice(header.value.0, header.value.1)); match name { header::TRANSFER_ENCODING => { // https://tools.ietf.org/html/rfc7230#section-3.3.3 // If Transfer-Encoding header is present, and 'chunked' is // not the final encoding, and this is a Request, then it is // mal-formed. A server should respond with 400 Bad Request. if !is_http_11 { debug!("HTTP/1.0 cannot have Transfer-Encoding header"); return Err(Parse::Header); } is_te = true; if headers::is_chunked_(&value) { is_te_chunked = true; decoder = DecodedLength::CHUNKED; } }, header::CONTENT_LENGTH => { if is_te { continue; } let len = value.to_str() .map_err(|_| Parse::Header) .and_then(|s| s.parse().map_err(|_| Parse::Header))?; if let Some(prev) = con_len { if prev != len { debug!( "multiple Content-Length headers with different values: [{}, {}]", prev, len, ); return Err(Parse::Header); } // we don't need to append this secondary length continue; } decoder = DecodedLength::checked_new(len)?; con_len = Some(len); }, header::CONNECTION => { // keep_alive was previously set to default for Version if keep_alive { // HTTP/1.1 keep_alive = !headers::connection_close(&value); } else { // HTTP/1.0 keep_alive = headers::connection_keep_alive(&value); } }, header::EXPECT => { expect_continue = value.as_bytes() == b"100-continue"; }, header::UPGRADE => { // Upgrades are only allowed with HTTP/1.1 wants_upgrade = is_http_11; }, _ => (), } headers.append(name, value); } if is_te && !is_te_chunked { debug!("request with transfer-encoding header, but not chunked, bad request"); return Err(Parse::Header); } *ctx.req_method = Some(subject.0.clone()); Ok(Some(ParsedMessage { head: MessageHead { version, subject, headers, }, decode: decoder, expect_continue, keep_alive, wants_upgrade, })) } fn encode(mut msg: Encode, mut dst: &mut Vec) -> ::Result { trace!( "Server::encode status={:?}, body={:?}, req_method={:?}", msg.head.subject, msg.body, msg.req_method ); debug_assert!(!msg.title_case_headers, "no server config for title case headers"); let mut wrote_len = false; // hyper currently doesn't support returning 1xx status codes as a Response // This is because Service only allows returning a single Response, and // so if you try to reply with a e.g. 100 Continue, you have no way of // replying with the latter status code response. let (ret, mut is_last) = if msg.head.subject == StatusCode::SWITCHING_PROTOCOLS { (Ok(()), true) } else if msg.req_method == &Some(Method::CONNECT) && msg.head.subject.is_success() { // Sending content-length or transfer-encoding header on 2xx response // to CONNECT is forbidden in RFC 7231. wrote_len = true; (Ok(()), true) } else if msg.head.subject.is_informational() { warn!("response with 1xx status code not supported"); *msg.head = MessageHead::default(); msg.head.subject = StatusCode::INTERNAL_SERVER_ERROR; msg.body = None; (Err(::Error::new_user_unsupported_status_code()), true) } else { (Ok(()), !msg.keep_alive) }; // In some error cases, we don't know about the invalid message until already // pushing some bytes onto the `dst`. In those cases, we don't want to send // the half-pushed message, so rewind to before. let orig_len = dst.len(); let rewind = |dst: &mut Vec| { dst.truncate(orig_len); }; let init_cap = 30 + msg.head.headers.len() * AVERAGE_HEADER_SIZE; dst.reserve(init_cap); if msg.head.version == Version::HTTP_11 && msg.head.subject == StatusCode::OK { extend(dst, b"HTTP/1.1 200 OK\r\n"); } else { match msg.head.version { Version::HTTP_10 => extend(dst, b"HTTP/1.0 "), Version::HTTP_11 => extend(dst, b"HTTP/1.1 "), Version::HTTP_2 => { warn!("response with HTTP2 version coerced to HTTP/1.1"); extend(dst, b"HTTP/1.1 "); }, other => panic!("unexpected response version: {:?}", other), } extend(dst, msg.head.subject.as_str().as_bytes()); extend(dst, b" "); // a reason MUST be written, as many parsers will expect it. extend(dst, msg.head.subject.canonical_reason().unwrap_or("").as_bytes()); extend(dst, b"\r\n"); } let mut encoder = Encoder::length(0); let mut wrote_date = false; 'headers: for (name, mut values) in msg.head.headers.drain() { match name { header::CONTENT_LENGTH => { if wrote_len { warn!("unexpected content-length found, canceling"); rewind(dst); return Err(::Error::new_user_header()); } match msg.body { Some(BodyLength::Known(known_len)) => { // The Payload claims to know a length, and // the headers are already set. For performance // reasons, we are just going to trust that // the values match. // // In debug builds, we'll assert they are the // same to help developers find bugs. encoder = Encoder::length(known_len); #[cfg(debug_assertions)] { let mut folded = None::<(u64, HeaderValue)>; for value in values { if let Some(len) = headers::content_length_parse(&value) { if let Some(fold) = folded { if fold.0 != len { panic!("multiple Content-Length values found: [{}, {}]", fold.0, len); } folded = Some(fold); } else { folded = Some((len, value)); } } else { panic!("illegal Content-Length value: {:?}", value); } } if let Some((len, value)) = folded { assert!( len == known_len, "payload claims content-length of {}, custom content-length header claims {}", known_len, len, ); extend(dst, b"content-length: "); extend(dst, value.as_bytes()); extend(dst, b"\r\n"); wrote_len = true; continue 'headers; } else { // No values in content-length... ignore? continue 'headers; } } }, Some(BodyLength::Unknown) => { // The Payload impl didn't know how long the // body is, but a length header was included. // We have to parse the value to return our // Encoder... let mut folded = None::<(u64, HeaderValue)>; for value in values { if let Some(len) = headers::content_length_parse(&value) { if let Some(fold) = folded { if fold.0 != len { warn!("multiple Content-Length values found: [{}, {}]", fold.0, len); rewind(dst); return Err(::Error::new_user_header()); } folded = Some(fold); } else { folded = Some((len, value)); } } else { warn!("illegal Content-Length value: {:?}", value); rewind(dst); return Err(::Error::new_user_header()); } } if let Some((len, value)) = folded { encoder = Encoder::length(len); extend(dst, b"content-length: "); extend(dst, value.as_bytes()); extend(dst, b"\r\n"); wrote_len = true; continue 'headers; } else { // No values in content-length... ignore? continue 'headers; } }, None => { // We have no body to actually send, // but the headers claim a content-length. // There's only 2 ways this makes sense: // // - The header says the length is `0`. // - This is a response to a `HEAD` request. if msg.req_method == &Some(Method::HEAD) { debug_assert_eq!(encoder, Encoder::length(0)); } else { for value in values { if value.as_bytes() != b"0" { warn!("content-length value found, but empty body provided: {:?}", value); } } continue 'headers; } } } wrote_len = true; }, header::TRANSFER_ENCODING => { if wrote_len { warn!("unexpected transfer-encoding found, canceling"); rewind(dst); return Err(::Error::new_user_header()); } // check that we actually can send a chunked body... if msg.head.version == Version::HTTP_10 || !Server::can_chunked(msg.req_method, msg.head.subject) { continue; } wrote_len = true; encoder = Encoder::chunked(); extend(dst, b"transfer-encoding: "); let mut saw_chunked; if let Some(te) = values.next() { extend(dst, te.as_bytes()); saw_chunked = headers::is_chunked_(&te); for value in values { extend(dst, b", "); extend(dst, value.as_bytes()); saw_chunked = headers::is_chunked_(&value); } if !saw_chunked { extend(dst, b", chunked\r\n"); } else { extend(dst, b"\r\n"); } } else { // zero lines? add a chunked line then extend(dst, b"chunked\r\n"); } continue 'headers; }, header::CONNECTION => { if !is_last { for value in values { extend(dst, name.as_str().as_bytes()); extend(dst, b": "); extend(dst, value.as_bytes()); extend(dst, b"\r\n"); if headers::connection_close(&value) { is_last = true; } } continue 'headers; } }, header::DATE => { wrote_date = true; }, _ => (), } //TODO: this should perhaps instead combine them into //single lines, as RFC7230 suggests is preferable. for value in values { extend(dst, name.as_str().as_bytes()); extend(dst, b": "); extend(dst, value.as_bytes()); extend(dst, b"\r\n"); } } if !wrote_len { encoder = match msg.body { Some(BodyLength::Unknown) => { if msg.head.version == Version::HTTP_10 || !Server::can_chunked(msg.req_method, msg.head.subject) { Encoder::close_delimited() } else { extend(dst, b"transfer-encoding: chunked\r\n"); Encoder::chunked() } }, None | Some(BodyLength::Known(0)) => { if msg.head.subject != StatusCode::NOT_MODIFIED { extend(dst, b"content-length: 0\r\n"); } Encoder::length(0) }, Some(BodyLength::Known(len)) => { if msg.head.subject == StatusCode::NOT_MODIFIED { Encoder::length(0) } else { extend(dst, b"content-length: "); let _ = ::itoa::write(&mut dst, len); extend(dst, b"\r\n"); Encoder::length(len) } }, }; } if !Server::can_have_body(msg.req_method, msg.head.subject) { trace!( "server body forced to 0; method={:?}, status={:?}", msg.req_method, msg.head.subject ); encoder = Encoder::length(0); } // cached date is much faster than formatting every request if !wrote_date { dst.reserve(date::DATE_VALUE_LENGTH + 8); extend(dst, b"date: "); date::extend(dst); extend(dst, b"\r\n\r\n"); } else { extend(dst, b"\r\n"); } ret.map(|()| encoder.set_last(is_last)) } fn on_error(err: &::Error) -> Option> { use ::error::Kind; let status = match *err.kind() { Kind::Parse(Parse::Method) | Kind::Parse(Parse::Header) | Kind::Parse(Parse::Uri) | Kind::Parse(Parse::Version) => { StatusCode::BAD_REQUEST }, Kind::Parse(Parse::TooLarge) => { StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE }, _ => return None, }; debug!("sending automatic response ({}) for parse error", status); let mut msg = MessageHead::default(); msg.subject = status; Some(msg) } fn is_server() -> bool { true } fn update_date() { date::update(); } } impl Server { fn can_have_body(method: &Option, status: StatusCode) -> bool { Server::can_chunked(method, status) } fn can_chunked(method: &Option, status: StatusCode) -> bool { if method == &Some(Method::HEAD) { false } else if method == &Some(Method::CONNECT) && status.is_success() { false } else { match status { // TODO: support for 1xx codes needs improvement everywhere // would be 100...199 => false StatusCode::SWITCHING_PROTOCOLS | StatusCode::NO_CONTENT | StatusCode::NOT_MODIFIED => false, _ => true, } } } } impl Http1Transaction for Client { type Incoming = StatusCode; type Outgoing = RequestLine; const LOG: &'static str = "{role=client}"; fn parse(buf: &mut BytesMut, ctx: ParseContext) -> ParseResult { // Loop to skip information status code headers (100 Continue, etc). loop { if buf.is_empty() { return Ok(None); } // Unsafe: see comment in Server Http1Transaction, above. let mut headers_indices: [HeaderIndices; MAX_HEADERS] = unsafe { mem::uninitialized() }; let (len, status, version, headers_len) = { let mut headers: [httparse::Header; MAX_HEADERS] = unsafe { mem::uninitialized() }; trace!("Response.parse([Header; {}], [u8; {}])", headers.len(), buf.len()); let mut res = httparse::Response::new(&mut headers); let bytes = buf.as_ref(); match res.parse(bytes)? { httparse::Status::Complete(len) => { trace!("Response.parse Complete({})", len); let status = StatusCode::from_u16(res.code.unwrap())?; let version = if res.version.unwrap() == 1 { Version::HTTP_11 } else { Version::HTTP_10 }; record_header_indices(bytes, &res.headers, &mut headers_indices)?; let headers_len = res.headers.len(); (len, status, version, headers_len) }, httparse::Status::Partial => return Ok(None), } }; let slice = buf.split_to(len).freeze(); let mut headers = ctx.cached_headers .take() .unwrap_or_else(HeaderMap::new); let mut keep_alive = version == Version::HTTP_11; headers.reserve(headers_len); for header in &headers_indices[..headers_len] { let name = header_name!(&slice[header.name.0..header.name.1]); let value = header_value!(slice.slice(header.value.0, header.value.1)); if let header::CONNECTION = name { // keep_alive was previously set to default for Version if keep_alive { // HTTP/1.1 keep_alive = !headers::connection_close(&value); } else { // HTTP/1.0 keep_alive = headers::connection_keep_alive(&value); } } headers.append(name, value); } let head = MessageHead { version, subject: status, headers, }; if let Some((decode, is_upgrade)) = Client::decoder(&head, ctx.req_method)? { return Ok(Some(ParsedMessage { head, decode, expect_continue: false, // a client upgrade means the connection can't be used // again, as it is definitely upgrading. keep_alive: keep_alive && !is_upgrade, wants_upgrade: is_upgrade, })); } } } fn encode(msg: Encode, dst: &mut Vec) -> ::Result { trace!("Client::encode method={:?}, body={:?}", msg.head.subject.0, msg.body); *msg.req_method = Some(msg.head.subject.0.clone()); let body = Client::set_length(msg.head, msg.body); let init_cap = 30 + msg.head.headers.len() * AVERAGE_HEADER_SIZE; dst.reserve(init_cap); extend(dst, msg.head.subject.0.as_str().as_bytes()); extend(dst, b" "); //TODO: add API to http::Uri to encode without std::fmt let _ = write!(FastWrite(dst), "{} ", msg.head.subject.1); match msg.head.version { Version::HTTP_10 => extend(dst, b"HTTP/1.0"), Version::HTTP_11 => extend(dst, b"HTTP/1.1"), Version::HTTP_2 => { warn!("request with HTTP2 version coerced to HTTP/1.1"); extend(dst, b"HTTP/1.1"); }, other => panic!("unexpected request version: {:?}", other), } extend(dst, b"\r\n"); if msg.title_case_headers { write_headers_title_case(&msg.head.headers, dst); } else { write_headers(&msg.head.headers, dst); } extend(dst, b"\r\n"); msg.head.headers.clear(); //TODO: remove when switching to drain() Ok(body) } fn on_error(_err: &::Error) -> Option> { // we can't tell the server about any errors it creates None } fn is_client() -> bool { true } } impl Client { /// Returns Some(length, wants_upgrade) if successful. /// /// Returns None if this message head should be skipped (like a 100 status). fn decoder(inc: &MessageHead, method: &mut Option) -> Result, Parse> { // According to https://tools.ietf.org/html/rfc7230#section-3.3.3 // 1. HEAD responses, and Status 1xx, 204, and 304 cannot have a body. // 2. Status 2xx to a CONNECT cannot have a body. // 3. Transfer-Encoding: chunked has a chunked body. // 4. If multiple differing Content-Length headers or invalid, close connection. // 5. Content-Length header has a sized body. // 6. (irrelevant to Response) // 7. Read till EOF. match inc.subject.as_u16() { 101 => { return Ok(Some((DecodedLength::ZERO, true))); }, 100..=199 => { trace!("ignoring informational response: {}", inc.subject.as_u16()); return Ok(None); }, 204 | 304 => return Ok(Some((DecodedLength::ZERO, false))), _ => (), } match *method { Some(Method::HEAD) => { return Ok(Some((DecodedLength::ZERO, false))); } Some(Method::CONNECT) => if let 200..=299 = inc.subject.as_u16() { return Ok(Some((DecodedLength::ZERO, true))); } Some(_) => {}, None => { trace!("Client::decoder is missing the Method"); } } if inc.headers.contains_key(header::TRANSFER_ENCODING) { // https://tools.ietf.org/html/rfc7230#section-3.3.3 // If Transfer-Encoding header is present, and 'chunked' is // not the final encoding, and this is a Request, then it is // mal-formed. A server should respond with 400 Bad Request. if inc.version == Version::HTTP_10 { debug!("HTTP/1.0 cannot have Transfer-Encoding header"); Err(Parse::Header) } else if headers::transfer_encoding_is_chunked(&inc.headers) { Ok(Some((DecodedLength::CHUNKED, false))) } else { trace!("not chunked, read till eof"); Ok(Some((DecodedLength::CHUNKED, false))) } } else if let Some(len) = headers::content_length_parse_all(&inc.headers) { Ok(Some((DecodedLength::checked_new(len)?, false))) } else if inc.headers.contains_key(header::CONTENT_LENGTH) { debug!("illegal Content-Length header"); Err(Parse::Header) } else { trace!("neither Transfer-Encoding nor Content-Length"); Ok(Some((DecodedLength::CLOSE_DELIMITED, false))) } } } impl Client { fn set_length(head: &mut RequestHead, body: Option) -> Encoder { let body = if let Some(body) = body { body } else { head.headers.remove(header::TRANSFER_ENCODING); return Encoder::length(0) }; // HTTP/1.0 doesn't know about chunked let can_chunked = head.version == Version::HTTP_11; let headers = &mut head.headers; // If the user already set specific headers, we should respect them, regardless // of what the Payload knows about itself. They set them for a reason. // Because of the borrow checker, we can't check the for an existing // Content-Length header while holding an `Entry` for the Transfer-Encoding // header, so unfortunately, we must do the check here, first. let existing_con_len = headers::content_length_parse_all(headers); let mut should_remove_con_len = false; if !can_chunked { // Chunked isn't legal, so if it is set, we need to remove it. if headers.remove(header::TRANSFER_ENCODING).is_some() { trace!("removing illegal transfer-encoding header"); } return if let Some(len) = existing_con_len { Encoder::length(len) } else if let BodyLength::Known(len) = body { set_content_length(headers, len) } else { // HTTP/1.0 client requests without a content-length // cannot have any body at all. Encoder::length(0) }; } // If the user set a transfer-encoding, respect that. Let's just // make sure `chunked` is the final encoding. let encoder = match headers.entry(header::TRANSFER_ENCODING) .expect("TRANSFER_ENCODING is valid HeaderName") { Entry::Occupied(te) => { should_remove_con_len = true; if headers::is_chunked(te.iter()) { Some(Encoder::chunked()) } else { warn!("user provided transfer-encoding does not end in 'chunked'"); // There's a Transfer-Encoding, but it doesn't end in 'chunked'! // An example that could trigger this: // // Transfer-Encoding: gzip // // This can be bad, depending on if this is a request or a // response. // // - A request is illegal if there is a `Transfer-Encoding` // but it doesn't end in `chunked`. // - A response that has `Transfer-Encoding` but doesn't // end in `chunked` isn't illegal, it just forces this // to be close-delimited. // // We can try to repair this, by adding `chunked` ourselves. headers::add_chunked(te); Some(Encoder::chunked()) } }, Entry::Vacant(te) => { if let Some(len) = existing_con_len { Some(Encoder::length(len)) } else if let BodyLength::Unknown = body { // GET, HEAD, and CONNECT almost never have bodies. // // So instead of sending a "chunked" body with a 0-chunk, // assume no body here. If you *must* send a body, // set the headers explicitly. match head.subject.0 { Method::GET | Method::HEAD | Method::CONNECT => { Some(Encoder::length(0)) }, _ => { te.insert(HeaderValue::from_static("chunked")); Some(Encoder::chunked()) }, } } else { None } }, }; // This is because we need a second mutable borrow to remove // content-length header. if let Some(encoder) = encoder { if should_remove_con_len && existing_con_len.is_some() { headers.remove(header::CONTENT_LENGTH); } return encoder; } // User didn't set transfer-encoding, AND we know body length, // so we can just set the Content-Length automatically. let len = if let BodyLength::Known(len) = body { len } else { unreachable!("BodyLength::Unknown would set chunked"); }; set_content_length(headers, len) } } fn set_content_length(headers: &mut HeaderMap, len: u64) -> Encoder { // At this point, there should not be a valid Content-Length // header. However, since we'll be indexing in anyways, we can // warn the user if there was an existing illegal header. // // Or at least, we can in theory. It's actually a little bit slower, // so perhaps only do that while the user is developing/testing. if cfg!(debug_assertions) { match headers.entry(header::CONTENT_LENGTH) .expect("CONTENT_LENGTH is valid HeaderName") { Entry::Occupied(mut cl) => { // Internal sanity check, we should have already determined // that the header was illegal before calling this function. debug_assert!(headers::content_length_parse_all_values(cl.iter()).is_none()); // Uh oh, the user set `Content-Length` headers, but set bad ones. // This would be an illegal message anyways, so let's try to repair // with our known good length. error!("user provided content-length header was invalid"); cl.insert(HeaderValue::from(len)); Encoder::length(len) }, Entry::Vacant(cl) => { cl.insert(HeaderValue::from(len)); Encoder::length(len) } } } else { headers.insert(header::CONTENT_LENGTH, HeaderValue::from(len)); Encoder::length(len) } } #[derive(Clone, Copy)] struct HeaderIndices { name: (usize, usize), value: (usize, usize), } fn record_header_indices( bytes: &[u8], headers: &[httparse::Header], indices: &mut [HeaderIndices] ) -> Result<(), ::error::Parse> { let bytes_ptr = bytes.as_ptr() as usize; // FIXME: This should be a single plain `for` loop. // Splitting it is a work-around for https://github.com/rust-lang/rust/issues/55105 macro_rules! split_loops_if { ( cfg($($cfg: tt)+) for $i: pat in ($iter: expr) { $body1: block $body2: block } ) => { for $i in $iter { $body1 #[cfg(not($($cfg)+))] $body2 } #[cfg($($cfg)+)] for $i in $iter { $body2 } } } split_loops_if! { cfg(all(target_arch = "arm", target_feature = "v7", target_feature = "neon")) for (header, indices) in (headers.iter().zip(indices.iter_mut())) { { if header.name.len() >= (1 << 16) { debug!("header name larger than 64kb: {:?}", header.name); return Err(::error::Parse::TooLarge); } let name_start = header.name.as_ptr() as usize - bytes_ptr; let name_end = name_start + header.name.len(); indices.name = (name_start, name_end); } { let value_start = header.value.as_ptr() as usize - bytes_ptr; let value_end = value_start + header.value.len(); indices.value = (value_start, value_end); } } } Ok(()) } // Write header names as title case. The header name is assumed to be ASCII, // therefore it is trivial to convert an ASCII character from lowercase to // uppercase. It is as simple as XORing the lowercase character byte with // space. fn title_case(dst: &mut Vec, name: &[u8]) { dst.reserve(name.len()); let mut iter = name.iter(); // Uppercase the first character if let Some(c) = iter.next() { if *c >= b'a' && *c <= b'z' { dst.push(*c ^ b' '); } else { dst.push(*c); } } while let Some(c) = iter.next() { dst.push(*c); if *c == b'-' { if let Some(c) = iter.next() { if *c >= b'a' && *c <= b'z' { dst.push(*c ^ b' '); } else { dst.push(*c); } } } } } fn write_headers_title_case(headers: &HeaderMap, dst: &mut Vec) { for (name, value) in headers { title_case(dst, name.as_str().as_bytes()); extend(dst, b": "); extend(dst, value.as_bytes()); extend(dst, b"\r\n"); } } fn write_headers(headers: &HeaderMap, dst: &mut Vec) { for (name, value) in headers { extend(dst, name.as_str().as_bytes()); extend(dst, b": "); extend(dst, value.as_bytes()); extend(dst, b"\r\n"); } } struct FastWrite<'a>(&'a mut Vec); impl<'a> fmt::Write for FastWrite<'a> { #[inline] fn write_str(&mut self, s: &str) -> fmt::Result { extend(self.0, s.as_bytes()); Ok(()) } #[inline] fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result { fmt::write(self, args) } } #[inline] fn extend(dst: &mut Vec, data: &[u8]) { dst.extend_from_slice(data); } #[cfg(test)] mod tests { use bytes::BytesMut; use super::*; #[test] fn test_parse_request() { extern crate pretty_env_logger; let _ = pretty_env_logger::try_init(); let mut raw = BytesMut::from(b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n".to_vec()); let mut method = None; let msg = Server::parse(&mut raw, ParseContext { cached_headers: &mut None, req_method: &mut method, }).unwrap().unwrap(); assert_eq!(raw.len(), 0); assert_eq!(msg.head.subject.0, ::Method::GET); assert_eq!(msg.head.subject.1, "/echo"); assert_eq!(msg.head.version, ::Version::HTTP_11); assert_eq!(msg.head.headers.len(), 1); assert_eq!(msg.head.headers["Host"], "hyper.rs"); assert_eq!(method, Some(::Method::GET)); } #[test] fn test_parse_response() { extern crate pretty_env_logger; let _ = pretty_env_logger::try_init(); let mut raw = BytesMut::from(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".to_vec()); let ctx = ParseContext { cached_headers: &mut None, req_method: &mut Some(::Method::GET), }; let msg = Client::parse(&mut raw, ctx).unwrap().unwrap(); assert_eq!(raw.len(), 0); assert_eq!(msg.head.subject, ::StatusCode::OK); assert_eq!(msg.head.version, ::Version::HTTP_11); assert_eq!(msg.head.headers.len(), 1); assert_eq!(msg.head.headers["Content-Length"], "0"); } #[test] fn test_parse_request_errors() { let mut raw = BytesMut::from(b"GET htt:p// HTTP/1.1\r\nHost: hyper.rs\r\n\r\n".to_vec()); let ctx = ParseContext { cached_headers: &mut None, req_method: &mut None, }; Server::parse(&mut raw, ctx).unwrap_err(); } #[test] fn test_decoder_request() { fn parse(s: &str) -> ParsedMessage { let mut bytes = BytesMut::from(s); Server::parse(&mut bytes, ParseContext { cached_headers: &mut None, req_method: &mut None, }) .expect("parse ok") .expect("parse complete") } fn parse_err(s: &str, comment: &str) -> ::error::Parse { let mut bytes = BytesMut::from(s); Server::parse(&mut bytes, ParseContext { cached_headers: &mut None, req_method: &mut None, }) .expect_err(comment) } // no length or transfer-encoding means 0-length body assert_eq!(parse("\ GET / HTTP/1.1\r\n\ \r\n\ ").decode, DecodedLength::ZERO); assert_eq!(parse("\ POST / HTTP/1.1\r\n\ \r\n\ ").decode, DecodedLength::ZERO); // transfer-encoding: chunked assert_eq!(parse("\ POST / HTTP/1.1\r\n\ transfer-encoding: chunked\r\n\ \r\n\ ").decode, DecodedLength::CHUNKED); assert_eq!(parse("\ POST / HTTP/1.1\r\n\ transfer-encoding: gzip, chunked\r\n\ \r\n\ ").decode, DecodedLength::CHUNKED); assert_eq!(parse("\ POST / HTTP/1.1\r\n\ transfer-encoding: gzip\r\n\ transfer-encoding: chunked\r\n\ \r\n\ ").decode, DecodedLength::CHUNKED); // content-length assert_eq!(parse("\ POST / HTTP/1.1\r\n\ content-length: 10\r\n\ \r\n\ ").decode, DecodedLength::new(10)); // transfer-encoding and content-length = chunked assert_eq!(parse("\ POST / HTTP/1.1\r\n\ content-length: 10\r\n\ transfer-encoding: chunked\r\n\ \r\n\ ").decode, DecodedLength::CHUNKED); assert_eq!(parse("\ POST / HTTP/1.1\r\n\ transfer-encoding: chunked\r\n\ content-length: 10\r\n\ \r\n\ ").decode, DecodedLength::CHUNKED); assert_eq!(parse("\ POST / HTTP/1.1\r\n\ transfer-encoding: gzip\r\n\ content-length: 10\r\n\ transfer-encoding: chunked\r\n\ \r\n\ ").decode, DecodedLength::CHUNKED); // multiple content-lengths of same value are fine assert_eq!(parse("\ POST / HTTP/1.1\r\n\ content-length: 10\r\n\ content-length: 10\r\n\ \r\n\ ").decode, DecodedLength::new(10)); // multiple content-lengths with different values is an error parse_err("\ POST / HTTP/1.1\r\n\ content-length: 10\r\n\ content-length: 11\r\n\ \r\n\ ", "multiple content-lengths"); // transfer-encoding that isn't chunked is an error parse_err("\ POST / HTTP/1.1\r\n\ transfer-encoding: gzip\r\n\ \r\n\ ", "transfer-encoding but not chunked"); parse_err("\ POST / HTTP/1.1\r\n\ transfer-encoding: chunked, gzip\r\n\ \r\n\ ", "transfer-encoding doesn't end in chunked"); // http/1.0 assert_eq!(parse("\ POST / HTTP/1.0\r\n\ content-length: 10\r\n\ \r\n\ ").decode, DecodedLength::new(10)); // 1.0 doesn't understand chunked, so its an error parse_err("\ POST / HTTP/1.0\r\n\ transfer-encoding: chunked\r\n\ \r\n\ ", "1.0 chunked"); } #[test] fn test_decoder_response() { fn parse(s: &str) -> ParsedMessage { parse_with_method(s, Method::GET) } fn parse_ignores(s: &str) { let mut bytes = BytesMut::from(s); assert!(Client::parse(&mut bytes, ParseContext { cached_headers: &mut None, req_method: &mut Some(Method::GET), }) .expect("parse ok") .is_none()) } fn parse_with_method(s: &str, m: Method) -> ParsedMessage { let mut bytes = BytesMut::from(s); Client::parse(&mut bytes, ParseContext { cached_headers: &mut None, req_method: &mut Some(m), }) .expect("parse ok") .expect("parse complete") } fn parse_err(s: &str) -> ::error::Parse { let mut bytes = BytesMut::from(s); Client::parse(&mut bytes, ParseContext { cached_headers: &mut None, req_method: &mut Some(Method::GET), }) .expect_err("parse should err") } // no content-length or transfer-encoding means close-delimited assert_eq!(parse("\ HTTP/1.1 200 OK\r\n\ \r\n\ ").decode, DecodedLength::CLOSE_DELIMITED); // 204 and 304 never have a body assert_eq!(parse("\ HTTP/1.1 204 No Content\r\n\ \r\n\ ").decode, DecodedLength::ZERO); assert_eq!(parse("\ HTTP/1.1 304 Not Modified\r\n\ \r\n\ ").decode, DecodedLength::ZERO); // content-length assert_eq!(parse("\ HTTP/1.1 200 OK\r\n\ content-length: 8\r\n\ \r\n\ ").decode, DecodedLength::new(8)); assert_eq!(parse("\ HTTP/1.1 200 OK\r\n\ content-length: 8\r\n\ content-length: 8\r\n\ \r\n\ ").decode, DecodedLength::new(8)); parse_err("\ HTTP/1.1 200 OK\r\n\ content-length: 8\r\n\ content-length: 9\r\n\ \r\n\ "); // transfer-encoding assert_eq!(parse("\ HTTP/1.1 200 OK\r\n\ transfer-encoding: chunked\r\n\ \r\n\ ").decode, DecodedLength::CHUNKED); // transfer-encoding and content-length = chunked assert_eq!(parse("\ HTTP/1.1 200 OK\r\n\ content-length: 10\r\n\ transfer-encoding: chunked\r\n\ \r\n\ ").decode, DecodedLength::CHUNKED); // HEAD can have content-length, but not body assert_eq!(parse_with_method("\ HTTP/1.1 200 OK\r\n\ content-length: 8\r\n\ \r\n\ ", Method::HEAD).decode, DecodedLength::ZERO); // CONNECT with 200 never has body { let msg = parse_with_method("\ HTTP/1.1 200 OK\r\n\ \r\n\ ", Method::CONNECT); assert_eq!(msg.decode, DecodedLength::ZERO); assert!(!msg.keep_alive, "should be upgrade"); assert!(msg.wants_upgrade, "should be upgrade"); } // CONNECT receiving non 200 can have a body assert_eq!(parse_with_method("\ HTTP/1.1 400 Bad Request\r\n\ \r\n\ ", Method::CONNECT).decode, DecodedLength::CLOSE_DELIMITED); // 1xx status codes parse_ignores("\ HTTP/1.1 100 Continue\r\n\ \r\n\ "); parse_ignores("\ HTTP/1.1 103 Early Hints\r\n\ \r\n\ "); // 101 upgrade not supported yet { let msg = parse("\ HTTP/1.1 101 Switching Protocols\r\n\ \r\n\ "); assert_eq!(msg.decode, DecodedLength::ZERO); assert!(!msg.keep_alive, "should be last"); assert!(msg.wants_upgrade, "should be upgrade"); } // http/1.0 assert_eq!(parse("\ HTTP/1.0 200 OK\r\n\ \r\n\ ").decode, DecodedLength::CLOSE_DELIMITED); // 1.0 doesn't understand chunked parse_err("\ HTTP/1.0 200 OK\r\n\ transfer-encoding: chunked\r\n\ \r\n\ "); // keep-alive assert!(parse("\ HTTP/1.1 200 OK\r\n\ content-length: 0\r\n\ \r\n\ ").keep_alive, "HTTP/1.1 keep-alive is default"); assert!(!parse("\ HTTP/1.1 200 OK\r\n\ content-length: 0\r\n\ connection: foo, close, bar\r\n\ \r\n\ ").keep_alive, "connection close is always close"); assert!(!parse("\ HTTP/1.0 200 OK\r\n\ content-length: 0\r\n\ \r\n\ ").keep_alive, "HTTP/1.0 close is default"); assert!(parse("\ HTTP/1.0 200 OK\r\n\ content-length: 0\r\n\ connection: foo, keep-alive, bar\r\n\ \r\n\ ").keep_alive, "connection keep-alive is always keep-alive"); } #[test] fn test_client_request_encode_title_case() { use http::header::HeaderValue; use proto::BodyLength; let mut head = MessageHead::default(); head.headers.insert("content-length", HeaderValue::from_static("10")); head.headers.insert("content-type", HeaderValue::from_static("application/json")); head.headers.insert("*-*", HeaderValue::from_static("o_o")); let mut vec = Vec::new(); Client::encode(Encode { head: &mut head, body: Some(BodyLength::Known(10)), keep_alive: true, req_method: &mut None, title_case_headers: true, }, &mut vec).unwrap(); assert_eq!(vec, b"GET / HTTP/1.1\r\nContent-Length: 10\r\nContent-Type: application/json\r\n*-*: o_o\r\n\r\n".to_vec()); } #[test] fn test_server_encode_connect_method() { let mut head = MessageHead::default(); let mut vec = Vec::new(); let encoder = Server::encode(Encode { head: &mut head, body: None, keep_alive: true, req_method: &mut Some(Method::CONNECT), title_case_headers: false, }, &mut vec).unwrap(); assert!(encoder.is_last()); } #[test] fn parse_header_htabs() { let mut bytes = BytesMut::from("HTTP/1.1 200 OK\r\nserver: hello\tworld\r\n\r\n"); let parsed = Client::parse(&mut bytes, ParseContext { cached_headers: &mut None, req_method: &mut Some(Method::GET), }) .expect("parse ok") .expect("parse complete"); assert_eq!(parsed.head.headers["server"], "hello\tworld"); } #[cfg(feature = "nightly")] use test::Bencher; #[cfg(feature = "nightly")] #[bench] fn bench_parse_incoming(b: &mut Bencher) { let mut raw = BytesMut::from( b"GET /super_long_uri/and_whatever?what_should_we_talk_about/\ I_wonder/Hard_to_write_in_an_uri_after_all/you_have_to_make\ _up_the_punctuation_yourself/how_fun_is_that?test=foo&test1=\ foo1&test2=foo2&test3=foo3&test4=foo4 HTTP/1.1\r\nHost: \ hyper.rs\r\nAccept: a lot of things\r\nAccept-Charset: \ utf8\r\nAccept-Encoding: *\r\nAccess-Control-Allow-\ Credentials: None\r\nAccess-Control-Allow-Origin: None\r\n\ Access-Control-Allow-Methods: None\r\nAccess-Control-Allow-\ Headers: None\r\nContent-Encoding: utf8\r\nContent-Security-\ Policy: None\r\nContent-Type: text/html\r\nOrigin: hyper\ \r\nSec-Websocket-Extensions: It looks super important!\r\n\ Sec-Websocket-Origin: hyper\r\nSec-Websocket-Version: 4.3\r\ \nStrict-Transport-Security: None\r\nUser-Agent: hyper\r\n\ X-Content-Duration: None\r\nX-Content-Security-Policy: None\ \r\nX-DNSPrefetch-Control: None\r\nX-Frame-Options: \ Something important obviously\r\nX-Requested-With: Nothing\ \r\n\r\n".to_vec() ); let len = raw.len(); let mut headers = Some(HeaderMap::new()); b.bytes = len as u64; b.iter(|| { let mut msg = Server::parse(&mut raw, ParseContext { cached_headers: &mut headers, req_method: &mut None, }).unwrap().unwrap(); ::test::black_box(&msg); msg.head.headers.clear(); headers = Some(msg.head.headers); restart(&mut raw, len); }); fn restart(b: &mut BytesMut, len: usize) { b.reserve(1); unsafe { b.set_len(len); } } } #[cfg(feature = "nightly")] #[bench] fn bench_parse_short(b: &mut Bencher) { let s = &b"GET / HTTP/1.1\r\nHost: localhost:8080\r\n\r\n"[..]; let mut raw = BytesMut::from(s.to_vec()); let len = raw.len(); let mut headers = Some(HeaderMap::new()); b.bytes = len as u64; b.iter(|| { let mut msg = Server::parse(&mut raw, ParseContext { cached_headers: &mut headers, req_method: &mut None, }).unwrap().unwrap(); ::test::black_box(&msg); msg.head.headers.clear(); headers = Some(msg.head.headers); restart(&mut raw, len); }); fn restart(b: &mut BytesMut, len: usize) { b.reserve(1); unsafe { b.set_len(len); } } } #[cfg(feature = "nightly")] #[bench] fn bench_server_encode_headers_preset(b: &mut Bencher) { use http::header::HeaderValue; use proto::BodyLength; let len = 108; b.bytes = len as u64; let mut head = MessageHead::default(); let mut headers = HeaderMap::new(); headers.insert("content-length", HeaderValue::from_static("10")); headers.insert("content-type", HeaderValue::from_static("application/json")); b.iter(|| { let mut vec = Vec::new(); head.headers = headers.clone(); Server::encode(Encode { head: &mut head, body: Some(BodyLength::Known(10)), keep_alive: true, req_method: &mut Some(Method::GET), title_case_headers: false, }, &mut vec).unwrap(); assert_eq!(vec.len(), len); ::test::black_box(vec); }) } #[cfg(feature = "nightly")] #[bench] fn bench_server_encode_no_headers(b: &mut Bencher) { use proto::BodyLength; let len = 76; b.bytes = len as u64; let mut head = MessageHead::default(); let mut vec = Vec::with_capacity(128); b.iter(|| { Server::encode(Encode { head: &mut head, body: Some(BodyLength::Known(10)), keep_alive: true, req_method: &mut Some(Method::GET), title_case_headers: false, }, &mut vec).unwrap(); assert_eq!(vec.len(), len); ::test::black_box(&vec); vec.clear(); }) } } hyper-0.12.35/src/proto/h2/client.rs010066400017500001750000000214401353675567300153500ustar0000000000000000use bytes::IntoBuf; use futures::{Async, Future, Poll, Stream}; use futures::future::{self, Either}; use futures::sync::{mpsc, oneshot}; use h2::client::{Builder, Handshake, SendRequest}; use tokio_io::{AsyncRead, AsyncWrite}; use headers::content_length_parse_all; use body::Payload; use ::common::{Exec, Never}; use headers; use ::proto::Dispatched; use super::{PipeToSendStream, SendBuf}; use ::{Body, Request, Response}; type ClientRx = ::client::dispatch::Receiver, Response>; /// An mpsc channel is used to help notify the `Connection` task when *all* /// other handles to it have been dropped, so that it can shutdown. type ConnDropRef = mpsc::Sender; /// A oneshot channel watches the `Connection` task, and when it completes, /// the "dispatch" task will be notified and can shutdown sooner. type ConnEof = oneshot::Receiver; pub(crate) struct Client where B: Payload, { executor: Exec, rx: ClientRx, state: State>, } enum State where B: IntoBuf { Handshaking(Handshake), Ready(SendRequest, ConnDropRef, ConnEof), } impl Client where T: AsyncRead + AsyncWrite + Send + 'static, B: Payload, { pub(crate) fn new(io: T, rx: ClientRx, builder: &Builder, exec: Exec) -> Client { let handshake = builder.handshake(io); Client { executor: exec, rx: rx, state: State::Handshaking(handshake), } } } impl Future for Client where T: AsyncRead + AsyncWrite + Send + 'static, B: Payload + 'static, { type Item = Dispatched; type Error = ::Error; fn poll(&mut self) -> Poll { loop { let next = match self.state { State::Handshaking(ref mut h) => { let (request_tx, conn) = try_ready!(h.poll().map_err(::Error::new_h2)); // An mpsc channel is used entirely to detect when the // 'Client' has been dropped. This is to get around a bug // in h2 where dropping all SendRequests won't notify a // parked Connection. let (tx, rx) = mpsc::channel(0); let (cancel_tx, cancel_rx) = oneshot::channel(); let rx = rx.into_future() .map(|(msg, _)| match msg { Some(never) => match never {}, None => (), }) .map_err(|_| -> Never { unreachable!("mpsc cannot error") }); let fut = conn .inspect(move |_| { drop(cancel_tx); trace!("connection complete") }) .map_err(|e| debug!("connection error: {}", e)) .select2(rx) .then(|res| match res { Ok(Either::A(((), _))) | Err(Either::A(((), _))) => { // conn has finished either way Either::A(future::ok(())) }, Ok(Either::B(((), conn))) => { // mpsc has been dropped, hopefully polling // the connection some more should start shutdown // and then close trace!("send_request dropped, starting conn shutdown"); Either::B(conn) } Err(Either::B((never, _))) => match never {}, }); self.executor.execute(fut)?; State::Ready(request_tx, tx, cancel_rx) }, State::Ready(ref mut tx, ref conn_dropper, ref mut cancel_rx) => { match tx.poll_ready() { Ok(Async::Ready(())) => (), Ok(Async::NotReady) => return Ok(Async::NotReady), Err(err) => { return if err.reason() == Some(::h2::Reason::NO_ERROR) { trace!("connection gracefully shutdown"); Ok(Async::Ready(Dispatched::Shutdown)) } else { Err(::Error::new_h2(err)) }; } } match self.rx.poll() { Ok(Async::Ready(Some((req, cb)))) => { // check that future hasn't been canceled already if cb.is_canceled() { trace!("request callback is canceled"); continue; } let (head, body) = req.into_parts(); let mut req = ::http::Request::from_parts(head, ()); super::strip_connection_headers(req.headers_mut(), true); if let Some(len) = body.content_length() { headers::set_content_length_if_missing(req.headers_mut(), len); } let eos = body.is_end_stream(); let (fut, body_tx) = match tx.send_request(req, eos) { Ok(ok) => ok, Err(err) => { debug!("client send request error: {}", err); cb.send(Err((::Error::new_h2(err), None))); continue; } }; if !eos { let mut pipe = PipeToSendStream::new(body, body_tx) .map_err(|e| debug!("client request body error: {}", e)); // eagerly see if the body pipe is ready and // can thus skip allocating in the executor match pipe.poll() { Ok(Async::Ready(())) | Err(()) => (), Ok(Async::NotReady) => { let conn_drop_ref = conn_dropper.clone(); let pipe = pipe.then(move |x| { drop(conn_drop_ref); x }); self.executor.execute(pipe)?; } } } let fut = fut .then(move |result| { match result { Ok(res) => { let content_length = content_length_parse_all(res.headers()); let res = res.map(|stream| ::Body::h2(stream, content_length)); Ok(res) }, Err(err) => { debug!("client response error: {}", err); Err((::Error::new_h2(err), None)) } } }); self.executor.execute(cb.send_when(fut))?; continue; }, Ok(Async::NotReady) => { match cancel_rx.poll() { Ok(Async::Ready(never)) => match never {}, Ok(Async::NotReady) => return Ok(Async::NotReady), Err(_conn_is_eof) => { trace!("connection task is closed, closing dispatch task"); return Ok(Async::Ready(Dispatched::Shutdown)); } } }, Ok(Async::Ready(None)) => { trace!("client::dispatch::Sender dropped"); return Ok(Async::Ready(Dispatched::Shutdown)); }, Err(never) => match never {}, } }, }; self.state = next; } } } hyper-0.12.35/src/proto/h2/mod.rs010066400017500001750000000155431353675567300146600ustar0000000000000000use bytes::Buf; use futures::{Async, Future, Poll}; use h2::{SendStream}; use http::header::{ HeaderName, CONNECTION, PROXY_AUTHENTICATE, PROXY_AUTHORIZATION, TE, TRAILER, TRANSFER_ENCODING, UPGRADE, }; use http::HeaderMap; use body::Payload; mod client; pub(crate) mod server; pub(crate) use self::client::Client; pub(crate) use self::server::Server; fn strip_connection_headers(headers: &mut HeaderMap, is_request: bool) { // List of connection headers from: // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection // // TE headers are allowed in HTTP/2 requests as long as the value is "trailers", so they're // tested separately. let connection_headers = [ HeaderName::from_lowercase(b"keep-alive").unwrap(), HeaderName::from_lowercase(b"proxy-connection").unwrap(), PROXY_AUTHENTICATE, PROXY_AUTHORIZATION, TRAILER, TRANSFER_ENCODING, UPGRADE, ]; for header in connection_headers.iter() { if headers.remove(header).is_some() { warn!("Connection header illegal in HTTP/2: {}", header.as_str()); } } if is_request { if headers.get(TE).map(|te_header| te_header != "trailers").unwrap_or(false) { warn!("TE headers not set to \"trailers\" are illegal in HTTP/2 requests"); headers.remove(TE); } } else { if headers.remove(TE).is_some() { warn!("TE headers illegal in HTTP/2 responses"); } } if let Some(header) = headers.remove(CONNECTION) { warn!( "Connection header illegal in HTTP/2: {}", CONNECTION.as_str() ); let header_contents = header.to_str().unwrap(); // A `Connection` header may have a comma-separated list of names of other headers that // are meant for only this specific connection. // // Iterate these names and remove them as headers. Connection-specific headers are // forbidden in HTTP2, as that information has been moved into frame types of the h2 // protocol. for name in header_contents.split(',') { let name = name.trim(); headers.remove(name); } } } // body adapters used by both Client and Server struct PipeToSendStream where S: Payload, { body_tx: SendStream>, data_done: bool, stream: S, } impl PipeToSendStream where S: Payload, { fn new(stream: S, tx: SendStream>) -> PipeToSendStream { PipeToSendStream { body_tx: tx, data_done: false, stream: stream, } } fn on_user_err(&mut self, err: S::Error) -> ::Error { let err = ::Error::new_user_body(err); debug!("send body user stream error: {}", err); self.body_tx.send_reset(err.h2_reason()); err } fn send_eos_frame(&mut self) -> ::Result<()> { trace!("send body eos"); self.body_tx .send_data(SendBuf(None), true) .map_err(::Error::new_body_write) } } impl Future for PipeToSendStream where S: Payload, { type Item = (); type Error = ::Error; fn poll(&mut self) -> Poll { loop { if !self.data_done { // we don't have the next chunk of data yet, so just reserve 1 byte to make // sure there's some capacity available. h2 will handle the capacity management // for the actual body chunk. self.body_tx.reserve_capacity(1); if self.body_tx.capacity() == 0 { loop { match try_ready!(self.body_tx.poll_capacity().map_err(::Error::new_body_write)) { Some(0) => {} Some(_) => break, None => return Err(::Error::new_canceled()), } } } else { if let Async::Ready(reason) = self.body_tx.poll_reset().map_err(::Error::new_body_write)? { debug!("stream received RST_STREAM: {:?}", reason); return Err(::Error::new_body_write(::h2::Error::from(reason))); } } match try_ready!(self.stream.poll_data().map_err(|e| self.on_user_err(e))) { Some(chunk) => { let is_eos = self.stream.is_end_stream(); trace!( "send body chunk: {} bytes, eos={}", chunk.remaining(), is_eos, ); let buf = SendBuf(Some(chunk)); self.body_tx .send_data(buf, is_eos) .map_err(::Error::new_body_write)?; if is_eos { return Ok(Async::Ready(())); } } None => { self.body_tx.reserve_capacity(0); let is_eos = self.stream.is_end_stream(); if is_eos { return self.send_eos_frame().map(Async::Ready); } else { self.data_done = true; // loop again to poll_trailers } } } } else { if let Async::Ready(reason) = self.body_tx.poll_reset().map_err(|e| ::Error::new_body_write(e))? { debug!("stream received RST_STREAM: {:?}", reason); return Err(::Error::new_body_write(::h2::Error::from(reason))); } match try_ready!(self.stream.poll_trailers().map_err(|e| self.on_user_err(e))) { Some(trailers) => { self.body_tx .send_trailers(trailers) .map_err(::Error::new_body_write)?; return Ok(Async::Ready(())); } None => { // There were no trailers, so send an empty DATA frame... return self.send_eos_frame().map(Async::Ready); } } } } } } struct SendBuf(Option); impl Buf for SendBuf { #[inline] fn remaining(&self) -> usize { self.0.as_ref().map(|b| b.remaining()).unwrap_or(0) } #[inline] fn bytes(&self) -> &[u8] { self.0.as_ref().map(|b| b.bytes()).unwrap_or(&[]) } #[inline] fn advance(&mut self, cnt: usize) { self.0.as_mut().map(|b| b.advance(cnt)); } } hyper-0.12.35/src/proto/h2/server.rs010066400017500001750000000241761353675567300154110ustar0000000000000000use std::error::Error as StdError; use futures::{Async, Future, Poll, Stream}; use h2::Reason; use h2::server::{Builder, Connection, Handshake, SendResponse}; use tokio_io::{AsyncRead, AsyncWrite}; use ::headers::content_length_parse_all; use ::body::Payload; use body::internal::FullDataArg; use ::common::exec::H2Exec; use ::headers; use ::service::Service; use ::proto::Dispatched; use super::{PipeToSendStream, SendBuf}; use ::{Body, Response}; pub(crate) struct Server where S: Service, B: Payload, { exec: E, service: S, state: State, } enum State where B: Payload, { Handshaking(Handshake>), Serving(Serving), Closed, } struct Serving where B: Payload, { conn: Connection>, closing: Option<::Error>, } impl Server where T: AsyncRead + AsyncWrite, S: Service, S::Error: Into>, B: Payload, E: H2Exec, { pub(crate) fn new(io: T, service: S, builder: &Builder, exec: E) -> Server { let handshake = builder.handshake(io); Server { exec, state: State::Handshaking(handshake), service, } } pub fn graceful_shutdown(&mut self) { trace!("graceful_shutdown"); match self.state { State::Handshaking(..) => { // fall-through, to replace state with Closed }, State::Serving(ref mut srv) => { if srv.closing.is_none() { srv.conn.graceful_shutdown(); } return; }, State::Closed => { return; } } self.state = State::Closed; } } impl Future for Server where T: AsyncRead + AsyncWrite, S: Service, S::Error: Into>, B: Payload, E: H2Exec, { type Item = Dispatched; type Error = ::Error; fn poll(&mut self) -> Poll { loop { let next = match self.state { State::Handshaking(ref mut h) => { let conn = try_ready!(h.poll().map_err(::Error::new_h2)); State::Serving(Serving { conn, closing: None, }) }, State::Serving(ref mut srv) => { try_ready!(srv.poll_server(&mut self.service, &self.exec)); return Ok(Async::Ready(Dispatched::Shutdown)); } State::Closed => { // graceful_shutdown was called before handshaking finished, // nothing to do here... return Ok(Async::Ready(Dispatched::Shutdown)); } }; self.state = next; } } } impl Serving where T: AsyncRead + AsyncWrite, B: Payload, { fn poll_server(&mut self, service: &mut S, exec: &E) -> Poll<(), ::Error> where S: Service< ReqBody=Body, ResBody=B, >, S::Error: Into>, E: H2Exec, { if self.closing.is_none() { loop { // At first, polls the readiness of supplied service. match service.poll_ready() { Ok(Async::Ready(())) => (), Ok(Async::NotReady) => { // use `poll_close` instead of `poll`, in order to avoid accepting a request. try_ready!(self.conn.poll_close().map_err(::Error::new_h2)); trace!("incoming connection complete"); return Ok(Async::Ready(())); } Err(err) => { let err = ::Error::new_user_service(err); debug!("service closed: {}", err); let reason = err.h2_reason(); if reason == Reason::NO_ERROR { // NO_ERROR is only used for graceful shutdowns... trace!("interpretting NO_ERROR user error as graceful_shutdown"); self.conn.graceful_shutdown(); } else { trace!("abruptly shutting down with {:?}", reason); self.conn.abrupt_shutdown(reason); } self.closing = Some(err); break; } } // When the service is ready, accepts an incoming request. if let Some((req, respond)) = try_ready!(self.conn.poll().map_err(::Error::new_h2)) { trace!("incoming request"); let content_length = content_length_parse_all(req.headers()); let req = req.map(|stream| { ::Body::h2(stream, content_length) }); let fut = H2Stream::new(service.call(req), respond); exec.execute_h2stream(fut)?; } else { // no more incoming streams... trace!("incoming connection complete"); return Ok(Async::Ready(())) } } } debug_assert!(self.closing.is_some(), "poll_server broke loop without closing"); try_ready!(self.conn.poll_close().map_err(::Error::new_h2)); Err(self.closing.take().expect("polled after error")) } } #[allow(missing_debug_implementations)] pub struct H2Stream where B: Payload, { reply: SendResponse>, state: H2StreamState, } enum H2StreamState where B: Payload, { Service(F), Body(PipeToSendStream), } impl H2Stream where F: Future>, F::Error: Into>, B: Payload, { fn new(fut: F, respond: SendResponse>) -> H2Stream { H2Stream { reply: respond, state: H2StreamState::Service(fut), } } fn poll2(&mut self) -> Poll<(), ::Error> { loop { let next = match self.state { H2StreamState::Service(ref mut h) => { let res = match h.poll() { Ok(Async::Ready(r)) => r, Ok(Async::NotReady) => { // Body is not yet ready, so we want to check if the client has sent a // RST_STREAM frame which would cancel the current request. if let Async::Ready(reason) = self.reply.poll_reset().map_err(|e| ::Error::new_h2(e))? { debug!("stream received RST_STREAM: {:?}", reason); return Err(::Error::new_h2(reason.into())); } return Ok(Async::NotReady); } Err(e) => { let err = ::Error::new_user_service(e); warn!("http2 service errored: {}", err); self.reply.send_reset(err.h2_reason()); return Err(err); }, }; let (head, mut body) = res.into_parts(); let mut res = ::http::Response::from_parts(head, ()); super::strip_connection_headers(res.headers_mut(), false); // set Date header if it isn't already set... res .headers_mut() .entry(::http::header::DATE) .expect("DATE is a valid HeaderName") .or_insert_with(::proto::h1::date::update_and_header_value); macro_rules! reply { ($eos:expr) => ({ match self.reply.send_response(res, $eos) { Ok(tx) => tx, Err(e) => { debug!("send response error: {}", e); self.reply.send_reset(Reason::INTERNAL_ERROR); return Err(::Error::new_h2(e)); } } }) } // automatically set Content-Length from body... if let Some(len) = body.content_length() { headers::set_content_length_if_missing(res.headers_mut(), len); } if let Some(full) = body.__hyper_full_data(FullDataArg(())).0 { let mut body_tx = reply!(false); let buf = SendBuf(Some(full)); body_tx .send_data(buf, true) .map_err(::Error::new_body_write)?; return Ok(Async::Ready(())); } if !body.is_end_stream() { let body_tx = reply!(false); H2StreamState::Body(PipeToSendStream::new(body, body_tx)) } else { reply!(true); return Ok(Async::Ready(())); } }, H2StreamState::Body(ref mut pipe) => { return pipe.poll(); } }; self.state = next; } } } impl Future for H2Stream where F: Future>, F::Error: Into>, B: Payload, { type Item = (); type Error = (); fn poll(&mut self) -> Poll { self.poll2() .map_err(|e| debug!("stream error: {}", e)) } } hyper-0.12.35/src/proto/mod.rs010066400017500001750000000066121353675567300143440ustar0000000000000000//! Pieces pertaining to the HTTP message protocol. use http::{HeaderMap, Method, StatusCode, Uri, Version}; pub(crate) use self::h1::{dispatch, Conn, ServerTransaction}; use self::body_length::DecodedLength; pub(crate) mod h1; pub(crate) mod h2; /// An Incoming Message head. Includes request/status line, and headers. #[derive(Clone, Debug, Default, PartialEq)] pub struct MessageHead { /// HTTP version of the message. pub version: Version, /// Subject (request line or status line) of Incoming message. pub subject: S, /// Headers of the Incoming message. pub headers: HeaderMap, } /// An incoming request message. pub type RequestHead = MessageHead; #[derive(Debug, Default, PartialEq)] pub struct RequestLine(pub Method, pub Uri); /// An incoming response message. pub type ResponseHead = MessageHead; #[derive(Debug)] pub enum BodyLength { /// Content-Length Known(u64), /// Transfer-Encoding: chunked (if h1) Unknown, } /// Status of when a Disaptcher future completes. pub(crate) enum Dispatched { /// Dispatcher completely shutdown connection. Shutdown, /// Dispatcher has pending upgrade, and so did not shutdown. Upgrade(::upgrade::Pending), } /// A separate module to encapsulate the invariants of the DecodedLength type. mod body_length { use std::fmt; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub(crate) struct DecodedLength(u64); const MAX_LEN: u64 = ::std::u64::MAX - 2; impl DecodedLength { pub(crate) const CLOSE_DELIMITED: DecodedLength = DecodedLength(::std::u64::MAX); pub(crate) const CHUNKED: DecodedLength = DecodedLength(::std::u64::MAX - 1); pub(crate) const ZERO: DecodedLength = DecodedLength(0); #[cfg(test)] pub(crate) fn new(len: u64) -> Self { debug_assert!(len <= MAX_LEN); DecodedLength(len) } /// Takes the length as a content-length without other checks. /// /// Should only be called if previously confirmed this isn't /// CLOSE_DELIMITED or CHUNKED. #[inline] pub(crate) fn danger_len(self) -> u64 { debug_assert!(self.0 < Self::CHUNKED.0); self.0 } /// Converts to an Option representing a Known or Unknown length. pub(crate) fn into_opt(self) -> Option { match self { DecodedLength::CHUNKED | DecodedLength::CLOSE_DELIMITED => None, DecodedLength(known) => Some(known) } } /// Checks the `u64` is within the maximum allowed for content-length. pub(crate) fn checked_new(len: u64) -> Result { if len <= MAX_LEN { Ok(DecodedLength(len)) } else { warn!("content-length bigger than maximum: {} > {}", len, MAX_LEN); Err(::error::Parse::TooLarge) } } } impl fmt::Display for DecodedLength { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { DecodedLength::CLOSE_DELIMITED => f.write_str("close-delimited"), DecodedLength::CHUNKED => f.write_str("chunked encoding"), DecodedLength::ZERO => f.write_str("empty"), DecodedLength(n) => write!(f, "content-length ({} bytes)", n), } } } } hyper-0.12.35/src/rt.rs010066400017500001750000000025161353675567300130460ustar0000000000000000//! Default runtime //! //! By default, hyper includes the [tokio](https://tokio.rs) runtime. To ease //! using it, several types are re-exported here. //! //! The inclusion of a default runtime can be disabled by turning off hyper's //! `runtime` Cargo feature. pub use futures::{Future, Stream}; pub use futures::future::{lazy, poll_fn}; use tokio; use self::inner::Spawn; /// Spawns a future on the default executor. /// /// # Panics /// /// This function will panic if the default executor is not set. /// /// # Note /// /// The `Spawn` return type is not currently meant for anything other than /// to reserve adding new trait implementations to it later. It can be /// ignored for now. pub fn spawn(f: F) -> Spawn where F: Future + Send + 'static, { tokio::spawn(f); Spawn { _inner: (), } } /// Start the Tokio runtime using the supplied future to bootstrap execution. /// /// # Example /// /// See the [server documentation](::server) for an example of its usage. pub fn run(f: F) where F: Future + Send + 'static { tokio::run(f); } // Make the `Spawn` type an unnameable, so we can add // methods or trait impls to it later without a breaking change. mod inner { #[allow(missing_debug_implementations)] pub struct Spawn { pub(super) _inner: (), } } hyper-0.12.35/src/server/conn.rs010066400017500001750000000762351353675567300146750ustar0000000000000000//! Lower-level Server connection API. //! //! The types in this module are to provide a lower-level API based around a //! single connection. Accepting a connection and binding it with a service //! are not handled at this level. This module provides the building blocks to //! customize those things externally. //! //! If you don't have need to manage connections yourself, consider using the //! higher-level [Server](super) API. use std::error::Error as StdError; use std::fmt; use std::mem; #[cfg(feature = "runtime")] use std::net::SocketAddr; use std::sync::Arc; #[cfg(feature = "runtime")] use std::time::Duration; use bytes::Bytes; use futures::{Async, Future, Poll, Stream}; use futures::future::{Either, Executor}; use h2; use tokio_io::{AsyncRead, AsyncWrite}; #[cfg(feature = "runtime")] use tokio_reactor::Handle; use body::{Body, Payload}; use common::exec::{Exec, H2Exec, NewSvcExec}; use common::io::Rewind; use error::{Kind, Parse}; use proto; use service::{MakeServiceRef, Service}; use upgrade::Upgraded; pub(super) use self::spawn_all::NoopWatcher; use self::spawn_all::NewSvcTask; pub(super) use self::spawn_all::Watcher; pub(super) use self::upgrades::UpgradeableConnection; #[cfg(feature = "runtime")] pub use super::tcp::{AddrIncoming, AddrStream}; /// A lower-level configuration of the HTTP protocol. /// /// This structure is used to configure options for an HTTP server connection. /// /// If you don't have need to manage connections yourself, consider using the /// higher-level [Server](super) API. #[derive(Clone, Debug)] pub struct Http { exec: E, h1_half_close: bool, h1_writev: bool, h2_builder: h2::server::Builder, mode: ConnectionMode, keep_alive: bool, max_buf_size: Option, pipeline_flush: bool, } /// The internal mode of HTTP protocol which indicates the behavior when a parse error occurs. #[derive(Clone, Debug, PartialEq)] enum ConnectionMode { /// Always use HTTP/1 and do not upgrade when a parse error occurs. H1Only, /// Always use HTTP/2. H2Only, /// Use HTTP/1 and try to upgrade to h2 when a parse error occurs. Fallback, } /// A stream mapping incoming IOs to new services. /// /// Yields `Connecting`s that are futures that should be put on a reactor. #[must_use = "streams do nothing unless polled"] #[derive(Debug)] pub struct Serve { incoming: I, make_service: S, protocol: Http, } /// A future building a new `Service` to a `Connection`. /// /// Wraps the future returned from `MakeService` into one that returns /// a `Connection`. #[must_use = "futures do nothing unless polled"] #[derive(Debug)] pub struct Connecting { future: F, io: Option, protocol: Http, } #[must_use = "futures do nothing unless polled"] #[derive(Debug)] pub(super) struct SpawnAll { pub(super) serve: Serve, } /// A future binding a connection with a Service. /// /// Polling this future will drive HTTP forward. #[must_use = "futures do nothing unless polled"] pub struct Connection where S: Service, { pub(super) conn: Option< Either< proto::h1::Dispatcher< proto::h1::dispatch::Server, S::ResBody, T, proto::ServerTransaction, >, proto::h2::Server< Rewind, S, S::ResBody, E, >, >>, fallback: Fallback, } #[derive(Clone, Debug)] enum Fallback { ToHttp2(h2::server::Builder, E), Http1Only, } impl Fallback { fn to_h2(&self) -> bool { match *self { Fallback::ToHttp2(..) => true, Fallback::Http1Only => false, } } } /// Deconstructed parts of a `Connection`. /// /// This allows taking apart a `Connection` at a later time, in order to /// reclaim the IO object, and additional related pieces. #[derive(Debug)] pub struct Parts { /// The original IO object used in the handshake. pub io: T, /// A buffer of bytes that have been read but not processed as HTTP. /// /// If the client sent additional bytes after its last request, and /// this connection "ended" with an upgrade, the read buffer will contain /// those bytes. /// /// You will want to check for any existing bytes if you plan to continue /// communicating on the IO object. pub read_buf: Bytes, /// The `Service` used to serve this connection. pub service: S, _inner: (), } // ===== impl Http ===== impl Http { /// Creates a new instance of the HTTP protocol, ready to spawn a server or /// start accepting connections. pub fn new() -> Http { Http { exec: Exec::Default, h1_half_close: true, h1_writev: true, h2_builder: h2::server::Builder::default(), mode: ConnectionMode::Fallback, keep_alive: true, max_buf_size: None, pipeline_flush: false, } } #[doc(hidden)] #[deprecated(note = "use Http::with_executor instead")] pub fn executor(&mut self, exec: E) -> &mut Self where E: Executor + Send>> + Send + Sync + 'static { self.exec = Exec::Executor(Arc::new(exec)); self } } impl Http { /// Sets whether HTTP1 is required. /// /// Default is false pub fn http1_only(&mut self, val: bool) -> &mut Self { if val { self.mode = ConnectionMode::H1Only; } else { self.mode = ConnectionMode::Fallback; } self } /// Set whether HTTP/1 connections should support half-closures. /// /// Clients can chose to shutdown their write-side while waiting /// for the server to respond. Setting this to `false` will /// automatically close any connection immediately if `read` /// detects an EOF. /// /// Default is `true`. #[inline] pub fn http1_half_close(&mut self, val: bool) -> &mut Self { self.h1_half_close = val; self } /// Set whether HTTP/1 connections should try to use vectored writes, /// or always flatten into a single buffer. /// /// Note that setting this to false may mean more copies of body data, /// but may also improve performance when an IO transport doesn't /// support vectored writes well, such as most TLS implementations. /// /// Default is `true`. #[inline] pub fn http1_writev(&mut self, val: bool) -> &mut Self { self.h1_writev = val; self } /// Sets whether HTTP2 is required. /// /// Default is false pub fn http2_only(&mut self, val: bool) -> &mut Self { if val { self.mode = ConnectionMode::H2Only; } else { self.mode = ConnectionMode::Fallback; } self } /// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`][spec] option for HTTP2 /// stream-level flow control. /// /// Default is 65,535 /// /// [spec]: https://http2.github.io/http2-spec/#SETTINGS_INITIAL_WINDOW_SIZE pub fn http2_initial_stream_window_size(&mut self, sz: impl Into>) -> &mut Self { if let Some(sz) = sz.into() { self.h2_builder.initial_window_size(sz); } self } /// Sets the max connection-level flow control for HTTP2 /// /// Default is 65,535 pub fn http2_initial_connection_window_size(&mut self, sz: impl Into>) -> &mut Self { if let Some(sz) = sz.into() { self.h2_builder.initial_connection_window_size(sz); } self } /// Sets the [`SETTINGS_MAX_CONCURRENT_STREAMS`][spec] option for HTTP2 /// connections. /// /// Default is no limit (`None`). /// /// [spec]: https://http2.github.io/http2-spec/#SETTINGS_MAX_CONCURRENT_STREAMS pub fn http2_max_concurrent_streams(&mut self, max: impl Into>) -> &mut Self { if let Some(max) = max.into() { self.h2_builder.max_concurrent_streams(max); } self } /// Enables or disables HTTP keep-alive. /// /// Default is true. pub fn keep_alive(&mut self, val: bool) -> &mut Self { self.keep_alive = val; self } /// Set the maximum buffer size for the connection. /// /// Default is ~400kb. /// /// # Panics /// /// The minimum value allowed is 8192. This method panics if the passed `max` is less than the minimum. pub fn max_buf_size(&mut self, max: usize) -> &mut Self { assert!( max >= proto::h1::MINIMUM_MAX_BUFFER_SIZE, "the max_buf_size cannot be smaller than the minimum that h1 specifies." ); self.max_buf_size = Some(max); self } /// Aggregates flushes to better support pipelined responses. /// /// Experimental, may have bugs. /// /// Default is false. pub fn pipeline_flush(&mut self, enabled: bool) -> &mut Self { self.pipeline_flush = enabled; self } /// Set the executor used to spawn background tasks. /// /// Default uses implicit default (like `tokio::spawn`). pub fn with_executor(self, exec: E2) -> Http { Http { exec, h1_half_close: self.h1_half_close, h1_writev: self.h1_writev, h2_builder: self.h2_builder, mode: self.mode, keep_alive: self.keep_alive, max_buf_size: self.max_buf_size, pipeline_flush: self.pipeline_flush, } } /// Bind a connection together with a [`Service`](::service::Service). /// /// This returns a Future that must be polled in order for HTTP to be /// driven on the connection. /// /// # Example /// /// ``` /// # extern crate hyper; /// # extern crate tokio_io; /// # #[cfg(feature = "runtime")] /// # extern crate tokio; /// # use hyper::{Body, Request, Response}; /// # use hyper::service::Service; /// # use hyper::server::conn::Http; /// # use tokio_io::{AsyncRead, AsyncWrite}; /// # #[cfg(feature = "runtime")] /// # fn run(some_io: I, some_service: S) /// # where /// # I: AsyncRead + AsyncWrite + Send + 'static, /// # S: Service + Send + 'static, /// # S::Future: Send /// # { /// # use hyper::rt::Future; /// # use tokio::reactor::Handle; /// let http = Http::new(); /// let conn = http.serve_connection(some_io, some_service); /// /// let fut = conn.map_err(|e| { /// eprintln!("server connection error: {}", e); /// }); /// /// hyper::rt::spawn(fut); /// # } /// # fn main() {} /// ``` pub fn serve_connection(&self, io: I, service: S) -> Connection where S: Service, S::Error: Into>, Bd: Payload, I: AsyncRead + AsyncWrite, E: H2Exec, { let either = match self.mode { ConnectionMode::H1Only | ConnectionMode::Fallback => { let mut conn = proto::Conn::new(io); if !self.keep_alive { conn.disable_keep_alive(); } if !self.h1_half_close { conn.set_disable_half_close(); } if !self.h1_writev { conn.set_write_strategy_flatten(); } conn.set_flush_pipeline(self.pipeline_flush); if let Some(max) = self.max_buf_size { conn.set_max_buf_size(max); } let sd = proto::h1::dispatch::Server::new(service); Either::A(proto::h1::Dispatcher::new(sd, conn)) } ConnectionMode::H2Only => { let rewind_io = Rewind::new(io); let h2 = proto::h2::Server::new(rewind_io, service, &self.h2_builder, self.exec.clone()); Either::B(h2) } }; Connection { conn: Some(either), fallback: if self.mode == ConnectionMode::Fallback { Fallback::ToHttp2(self.h2_builder.clone(), self.exec.clone()) } else { Fallback::Http1Only }, } } /// Bind the provided `addr` with the default `Handle` and return [`Serve`](Serve). /// /// This method will bind the `addr` provided with a new TCP listener ready /// to accept connections. Each connection will be processed with the /// `make_service` object provided, creating a new service per /// connection. #[cfg(feature = "runtime")] pub fn serve_addr(&self, addr: &SocketAddr, make_service: S) -> ::Result> where S: MakeServiceRef< AddrStream, ReqBody=Body, ResBody=Bd, >, S::Error: Into>, Bd: Payload, E: H2Exec<::Future, Bd>, { let mut incoming = AddrIncoming::new(addr, None)?; if self.keep_alive { incoming.set_keepalive(Some(Duration::from_secs(90))); } Ok(self.serve_incoming(incoming, make_service)) } /// Bind the provided `addr` with the `Handle` and return a [`Serve`](Serve) /// /// This method will bind the `addr` provided with a new TCP listener ready /// to accept connections. Each connection will be processed with the /// `make_service` object provided, creating a new service per /// connection. #[cfg(feature = "runtime")] pub fn serve_addr_handle(&self, addr: &SocketAddr, handle: &Handle, make_service: S) -> ::Result> where S: MakeServiceRef< AddrStream, ReqBody=Body, ResBody=Bd, >, S::Error: Into>, Bd: Payload, E: H2Exec<::Future, Bd>, { let mut incoming = AddrIncoming::new(addr, Some(handle))?; if self.keep_alive { incoming.set_keepalive(Some(Duration::from_secs(90))); } Ok(self.serve_incoming(incoming, make_service)) } /// Bind the provided stream of incoming IO objects with a `MakeService`. pub fn serve_incoming(&self, incoming: I, make_service: S) -> Serve where I: Stream, I::Error: Into>, I::Item: AsyncRead + AsyncWrite, S: MakeServiceRef< I::Item, ReqBody=Body, ResBody=Bd, >, S::Error: Into>, Bd: Payload, E: H2Exec<::Future, Bd>, { Serve { incoming, make_service, protocol: self.clone(), } } } // ===== impl Connection ===== impl Connection where S: Service, S::Error: Into>, I: AsyncRead + AsyncWrite, B: Payload + 'static, E: H2Exec, { /// Start a graceful shutdown process for this connection. /// /// This `Connection` should continue to be polled until shutdown /// can finish. pub fn graceful_shutdown(&mut self) { match *self.conn.as_mut().unwrap() { Either::A(ref mut h1) => { h1.disable_keep_alive(); }, Either::B(ref mut h2) => { h2.graceful_shutdown(); } } } /// Return the inner IO object, and additional information. /// /// If the IO object has been "rewound" the io will not contain those bytes rewound. /// This should only be called after `poll_without_shutdown` signals /// that the connection is "done". Otherwise, it may not have finished /// flushing all necessary HTTP bytes. /// /// # Panics /// This method will panic if this connection is using an h2 protocol. pub fn into_parts(self) -> Parts { self.try_into_parts().unwrap_or_else(|| panic!("h2 cannot into_inner")) } /// Return the inner IO object, and additional information, if available. /// /// This method will return a `None` if this connection is using an h2 protocol. pub fn try_into_parts(self) -> Option> { match self.conn.unwrap() { Either::A(h1) => { let (io, read_buf, dispatch) = h1.into_inner(); Some(Parts { io: io, read_buf: read_buf, service: dispatch.into_service(), _inner: (), }) }, Either::B(_h2) => None, } } /// Poll the connection for completion, but without calling `shutdown` /// on the underlying IO. /// /// This is useful to allow running a connection while doing an HTTP /// upgrade. Once the upgrade is completed, the connection would be "done", /// but it is not desired to actally shutdown the IO object. Instead you /// would take it back using `into_parts`. /// /// Use [`poll_fn`](https://docs.rs/futures/0.1.25/futures/future/fn.poll_fn.html) /// and [`try_ready!`](https://docs.rs/futures/0.1.25/futures/macro.try_ready.html) /// to work with this function; or use the `without_shutdown` wrapper. pub fn poll_without_shutdown(&mut self) -> Poll<(), ::Error> { loop { let polled = match *self.conn.as_mut().unwrap() { Either::A(ref mut h1) => h1.poll_without_shutdown(), Either::B(ref mut h2) => return h2.poll().map(|x| x.map(|_| ())), }; match polled { Ok(x) => return Ok(x), Err(e) => { match *e.kind() { Kind::Parse(Parse::VersionH2) if self.fallback.to_h2() => { self.upgrade_h2(); continue; } _ => return Err(e), } } } } } /// Prevent shutdown of the underlying IO object at the end of service the request, /// instead run `into_parts`. This is a convenience wrapper over `poll_without_shutdown`. pub fn without_shutdown(self) -> impl Future, Error=::Error> { let mut conn = Some(self); ::futures::future::poll_fn(move || -> ::Result<_> { try_ready!(conn.as_mut().unwrap().poll_without_shutdown()); Ok(conn.take().unwrap().into_parts().into()) }) } fn upgrade_h2(&mut self) { trace!("Trying to upgrade connection to h2"); let conn = self.conn.take(); let (io, read_buf, dispatch) = match conn.unwrap() { Either::A(h1) => { h1.into_inner() }, Either::B(_h2) => { panic!("h2 cannot into_inner"); } }; let mut rewind_io = Rewind::new(io); rewind_io.rewind(read_buf); let (builder, exec) = match self.fallback { Fallback::ToHttp2(ref builder, ref exec) => (builder, exec), Fallback::Http1Only => unreachable!("upgrade_h2 with Fallback::Http1Only"), }; let h2 = proto::h2::Server::new( rewind_io, dispatch.into_service(), builder, exec.clone(), ); debug_assert!(self.conn.is_none()); self.conn = Some(Either::B(h2)); } /// Enable this connection to support higher-level HTTP upgrades. /// /// See [the `upgrade` module](::upgrade) for more. pub fn with_upgrades(self) -> UpgradeableConnection where I: Send, { UpgradeableConnection { inner: self, } } } impl Future for Connection where S: Service + 'static, S::Error: Into>, I: AsyncRead + AsyncWrite + 'static, B: Payload + 'static, E: H2Exec, { type Item = (); type Error = ::Error; fn poll(&mut self) -> Poll { loop { match self.conn.poll() { Ok(x) => return Ok(x.map(|opt| { if let Some(proto::Dispatched::Upgrade(pending)) = opt { // With no `Send` bound on `I`, we can't try to do // upgrades here. In case a user was trying to use // `Body::on_upgrade` with this API, send a special // error letting them know about that. pending.manual(); } })), Err(e) => { match *e.kind() { Kind::Parse(Parse::VersionH2) if self.fallback.to_h2() => { self.upgrade_h2(); continue; } _ => return Err(e), } } } } } } impl fmt::Debug for Connection where S: Service, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Connection") .finish() } } // ===== impl Serve ===== impl Serve { /// Spawn all incoming connections onto the executor in `Http`. pub(super) fn spawn_all(self) -> SpawnAll { SpawnAll { serve: self, } } /// Get a reference to the incoming stream. #[inline] pub fn incoming_ref(&self) -> &I { &self.incoming } /// Get a mutable reference to the incoming stream. #[inline] pub fn incoming_mut(&mut self) -> &mut I { &mut self.incoming } } impl Stream for Serve where I: Stream, I::Item: AsyncRead + AsyncWrite, I::Error: Into>, S: MakeServiceRef, //S::Error2: Into>, //SME: Into>, B: Payload, E: H2Exec<::Future, B>, { type Item = Connecting; type Error = ::Error; fn poll(&mut self) -> Poll, Self::Error> { match self.make_service.poll_ready_ref() { Ok(Async::Ready(())) => (), Ok(Async::NotReady) => return Ok(Async::NotReady), Err(e) => { trace!("make_service closed"); return Err(::Error::new_user_make_service(e)); } } if let Some(io) = try_ready!(self.incoming.poll().map_err(::Error::new_accept)) { let new_fut = self.make_service.make_service_ref(&io); Ok(Async::Ready(Some(Connecting { future: new_fut, io: Some(io), protocol: self.protocol.clone(), }))) } else { Ok(Async::Ready(None)) } } } // ===== impl Connecting ===== impl Future for Connecting where I: AsyncRead + AsyncWrite, F: Future, S: Service, B: Payload, E: H2Exec, { type Item = Connection; type Error = F::Error; fn poll(&mut self) -> Poll { let service = try_ready!(self.future.poll()); let io = self.io.take().expect("polled after complete"); Ok(self.protocol.serve_connection(io, service).into()) } } // ===== impl SpawnAll ===== #[cfg(feature = "runtime")] impl SpawnAll { pub(super) fn local_addr(&self) -> SocketAddr { self.serve.incoming.local_addr() } } impl SpawnAll { pub(super) fn incoming_ref(&self) -> &I { self.serve.incoming_ref() } } impl SpawnAll where I: Stream, I::Error: Into>, I::Item: AsyncRead + AsyncWrite + Send + 'static, S: MakeServiceRef< I::Item, ReqBody=Body, ResBody=B, >, B: Payload, E: H2Exec<::Future, B>, { pub(super) fn poll_watch(&mut self, watcher: &W) -> Poll<(), ::Error> where E: NewSvcExec, W: Watcher, { loop { if let Some(connecting) = try_ready!(self.serve.poll()) { let fut = NewSvcTask::new(connecting, watcher.clone()); self.serve.protocol.exec.execute_new_svc(fut)?; } else { return Ok(Async::Ready(())) } } } } pub(crate) mod spawn_all { use std::error::Error as StdError; use futures::{Future, Poll}; use tokio_io::{AsyncRead, AsyncWrite}; use body::{Body, Payload}; use common::exec::H2Exec; use service::Service; use super::{Connecting, UpgradeableConnection}; // Used by `SpawnAll` to optionally watch a `Connection` future. // // The regular `hyper::Server` just uses a `NoopWatcher`, which does // not need to watch anything, and so returns the `Connection` untouched. // // The `Server::with_graceful_shutdown` needs to keep track of all active // connections, and signal that they start to shutdown when prompted, so // it has a `GracefulWatcher` implementation to do that. pub trait Watcher: Clone { type Future: Future; fn watch(&self, conn: UpgradeableConnection) -> Self::Future; } #[allow(missing_debug_implementations)] #[derive(Copy, Clone)] pub struct NoopWatcher; impl Watcher for NoopWatcher where I: AsyncRead + AsyncWrite + Send + 'static, S: Service + 'static, E: H2Exec, { type Future = UpgradeableConnection; fn watch(&self, conn: UpgradeableConnection) -> Self::Future { conn } } // This is a `Future` spawned to an `Executor` inside // the `SpawnAll`. By being a nameable type, we can be generic over the // user's `Service::Future`, and thus an `Executor` can execute it. // // Doing this allows for the server to conditionally require `Send` futures, // depending on the `Executor` configured. // // Users cannot import this type, nor the associated `NewSvcExec`. Instead, // a blanket implementation for `Executor` is sufficient. #[allow(missing_debug_implementations)] pub struct NewSvcTask> { state: State, } enum State> { Connecting(Connecting, W), Connected(W::Future), } impl> NewSvcTask { pub(super) fn new(connecting: Connecting, watcher: W) -> Self { NewSvcTask { state: State::Connecting(connecting, watcher), } } } impl Future for NewSvcTask where I: AsyncRead + AsyncWrite + Send + 'static, N: Future, N::Error: Into>, S: Service, B: Payload, E: H2Exec, W: Watcher, { type Item = (); type Error = (); fn poll(&mut self) -> Poll { loop { let next = match self.state { State::Connecting(ref mut connecting, ref watcher) => { let conn = try_ready!(connecting .poll() .map_err(|err| { let err = ::Error::new_user_make_service(err); debug!("connecting error: {}", err); })); let connected = watcher.watch(conn.with_upgrades()); State::Connected(connected) }, State::Connected(ref mut future) => { return future .poll() .map_err(|err| { debug!("connection error: {}", err); }); } }; self.state = next; } } } } mod upgrades { use super::*; // A future binding a connection with a Service with Upgrade support. // // This type is unnameable outside the crate, and so basically just an // `impl Future`, without requiring Rust 1.26. #[must_use = "futures do nothing unless polled"] #[allow(missing_debug_implementations)] pub struct UpgradeableConnection where S: Service, { pub(super) inner: Connection, } impl UpgradeableConnection where S: Service,// + 'static, S::Error: Into>, I: AsyncRead + AsyncWrite, B: Payload + 'static, E: H2Exec, { /// Start a graceful shutdown process for this connection. /// /// This `Connection` should continue to be polled until shutdown /// can finish. pub fn graceful_shutdown(&mut self) { self.inner.graceful_shutdown() } } impl Future for UpgradeableConnection where S: Service + 'static, S::Error: Into>, I: AsyncRead + AsyncWrite + Send + 'static, B: Payload + 'static, E: super::H2Exec, { type Item = (); type Error = ::Error; fn poll(&mut self) -> Poll { loop { match self.inner.conn.poll() { Ok(Async::NotReady) => return Ok(Async::NotReady), Ok(Async::Ready(Some(proto::Dispatched::Shutdown))) | Ok(Async::Ready(None)) => { return Ok(Async::Ready(())); }, Ok(Async::Ready(Some(proto::Dispatched::Upgrade(pending)))) => { let h1 = match mem::replace(&mut self.inner.conn, None) { Some(Either::A(h1)) => h1, _ => unreachable!("Upgrade expects h1"), }; let (io, buf, _) = h1.into_inner(); pending.fulfill(Upgraded::new(Box::new(io), buf)); return Ok(Async::Ready(())); }, Err(e) => { match *e.kind() { Kind::Parse(Parse::VersionH2) if self.inner.fallback.to_h2() => { self.inner.upgrade_h2(); continue; } _ => return Err(e), } } } } } } } hyper-0.12.35/src/server/mod.rs010066400017500001750000000350041353675567300145040ustar0000000000000000//! HTTP Server //! //! A `Server` is created to listen on a port, parse HTTP requests, and hand //! them off to a `Service`. //! //! There are two levels of APIs provide for constructing HTTP servers: //! //! - The higher-level [`Server`](Server) type. //! - The lower-level [`conn`](server::conn) module. //! //! # Server //! //! The [`Server`](Server) is main way to start listening for HTTP requests. //! It wraps a listener with a [`MakeService`](::service), and then should //! be executed to start serving requests. //! //! [`Server`](Server) accepts connections in both HTTP1 and HTTP2 by default. //! //! ## Example //! //! ```no_run //! extern crate hyper; //! //! use hyper::{Body, Response, Server}; //! use hyper::service::service_fn_ok; //! //! # #[cfg(feature = "runtime")] //! fn main() { //! # use hyper::rt::Future; //! // Construct our SocketAddr to listen on... //! let addr = ([127, 0, 0, 1], 3000).into(); //! //! // And a MakeService to handle each connection... //! let make_service = || { //! service_fn_ok(|_req| { //! Response::new(Body::from("Hello World")) //! }) //! }; //! //! // Then bind and serve... //! let server = Server::bind(&addr) //! .serve(make_service); //! //! // Finally, spawn `server` onto an Executor... //! hyper::rt::run(server.map_err(|e| { //! eprintln!("server error: {}", e); //! })); //! } //! # #[cfg(not(feature = "runtime"))] //! # fn main() {} //! ``` pub mod conn; mod shutdown; #[cfg(feature = "runtime")] mod tcp; use std::error::Error as StdError; use std::fmt; #[cfg(feature = "runtime")] use std::net::{SocketAddr, TcpListener as StdTcpListener}; #[cfg(feature = "runtime")] use std::time::Duration; use futures::{Future, Stream, Poll}; use tokio_io::{AsyncRead, AsyncWrite}; #[cfg(feature = "runtime")] use tokio_reactor; use body::{Body, Payload}; use common::exec::{Exec, H2Exec, NewSvcExec}; use service::{MakeServiceRef, Service}; // Renamed `Http` as `Http_` for now so that people upgrading don't see an // error that `hyper::server::Http` is private... use self::conn::{Http as Http_, NoopWatcher, SpawnAll}; use self::shutdown::{Graceful, GracefulWatcher}; #[cfg(feature = "runtime")] use self::tcp::AddrIncoming; /// A listening HTTP server that accepts connections in both HTTP1 and HTTP2 by default. /// /// `Server` is a `Future` mapping a bound listener with a set of service /// handlers. It is built using the [`Builder`](Builder), and the future /// completes when the server has been shutdown. It should be run by an /// `Executor`. pub struct Server { spawn_all: SpawnAll, } /// A builder for a [`Server`](Server). #[derive(Debug)] pub struct Builder { incoming: I, protocol: Http_, } // ===== impl Server ===== impl Server { /// Starts a [`Builder`](Builder) with the provided incoming stream. pub fn builder(incoming: I) -> Builder { Builder { incoming, protocol: Http_::new(), } } } #[cfg(feature = "runtime")] impl Server { /// Binds to the provided address, and returns a [`Builder`](Builder). /// /// # Panics /// /// This method will panic if binding to the address fails. For a method /// to bind to an address and return a `Result`, see `Server::try_bind`. pub fn bind(addr: &SocketAddr) -> Builder { let incoming = AddrIncoming::new(addr, None) .unwrap_or_else(|e| { panic!("error binding to {}: {}", addr, e); }); Server::builder(incoming) } /// Tries to bind to the provided address, and returns a [`Builder`](Builder). pub fn try_bind(addr: &SocketAddr) -> ::Result> { AddrIncoming::new(addr, None) .map(Server::builder) } /// Create a new instance from a `std::net::TcpListener` instance. pub fn from_tcp(listener: StdTcpListener) -> Result, ::Error> { let handle = tokio_reactor::Handle::default(); AddrIncoming::from_std(listener, &handle) .map(Server::builder) } } #[cfg(feature = "runtime")] impl Server { /// Returns the local address that this server is bound to. pub fn local_addr(&self) -> SocketAddr { self.spawn_all.local_addr() } } impl Server where I: Stream, I::Error: Into>, I::Item: AsyncRead + AsyncWrite + Send + 'static, S: MakeServiceRef, S::Error: Into>, S::Service: 'static, B: Payload, E: H2Exec<::Future, B>, E: NewSvcExec, { /// Prepares a server to handle graceful shutdown when the provided future /// completes. /// /// # Example /// /// ``` /// # extern crate hyper; /// # extern crate futures; /// # use futures::Future; /// # fn main() {} /// # #[cfg(feature = "runtime")] /// # fn run() { /// # use hyper::{Body, Response, Server}; /// # use hyper::service::service_fn_ok; /// # let new_service = || { /// # service_fn_ok(|_req| { /// # Response::new(Body::from("Hello World")) /// # }) /// # }; /// /// // Make a server from the previous examples... /// let server = Server::bind(&([127, 0, 0, 1], 3000).into()) /// .serve(new_service); /// /// // Prepare some signal for when the server should start /// // shutting down... /// let (tx, rx) = futures::sync::oneshot::channel::<()>(); /// /// let graceful = server /// .with_graceful_shutdown(rx) /// .map_err(|err| eprintln!("server error: {}", err)); /// /// // Spawn `server` onto an Executor... /// hyper::rt::spawn(graceful); /// /// // And later, trigger the signal by calling `tx.send(())`. /// let _ = tx.send(()); /// # } /// ``` pub fn with_graceful_shutdown(self, signal: F) -> Graceful where F: Future { Graceful::new(self.spawn_all, signal) } } impl Future for Server where I: Stream, I::Error: Into>, I::Item: AsyncRead + AsyncWrite + Send + 'static, S: MakeServiceRef, S::Error: Into>, S::Service: 'static, B: Payload, E: H2Exec<::Future, B>, E: NewSvcExec, { type Item = (); type Error = ::Error; fn poll(&mut self) -> Poll { self.spawn_all.poll_watch(&NoopWatcher) } } impl fmt::Debug for Server { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Server") .field("listener", &self.spawn_all.incoming_ref()) .finish() } } // ===== impl Builder ===== impl Builder { /// Start a new builder, wrapping an incoming stream and low-level options. /// /// For a more convenient constructor, see [`Server::bind`](Server::bind). pub fn new(incoming: I, protocol: Http_) -> Self { Builder { incoming, protocol, } } /// Sets whether to use keep-alive for HTTP/1 connections. /// /// Default is `true`. pub fn http1_keepalive(mut self, val: bool) -> Self { self.protocol.keep_alive(val); self } /// Set whether HTTP/1 connections should support half-closures. /// /// Clients can chose to shutdown their write-side while waiting /// for the server to respond. Setting this to `false` will /// automatically close any connection immediately if `read` /// detects an EOF. /// /// Default is `true`. pub fn http1_half_close(mut self, val: bool) -> Self { self.protocol.http1_half_close(val); self } /// Sets whether HTTP/1 is required. /// /// Default is `false`. pub fn http1_only(mut self, val: bool) -> Self { self.protocol.http1_only(val); self } // Sets whether to bunch up HTTP/1 writes until the read buffer is empty. // // This isn't really desirable in most cases, only really being useful in // silly pipeline benchmarks. #[doc(hidden)] pub fn http1_pipeline_flush(mut self, val: bool) -> Self { self.protocol.pipeline_flush(val); self } /// Set whether HTTP/1 connections should try to use vectored writes, /// or always flatten into a single buffer. /// /// # Note /// /// Setting this to `false` may mean more copies of body data, /// but may also improve performance when an IO transport doesn't /// support vectored writes well, such as most TLS implementations. /// /// Default is `true`. pub fn http1_writev(mut self, val: bool) -> Self { self.protocol.http1_writev(val); self } /// Sets whether HTTP/2 is required. /// /// Default is `false`. pub fn http2_only(mut self, val: bool) -> Self { self.protocol.http2_only(val); self } // soft-deprecated? deprecation warning just seems annoying... // reimplemented to take `self` instead of `&mut self` #[doc(hidden)] pub fn http2_initial_stream_window_size(&mut self, sz: impl Into>) -> &mut Self { self.protocol.http2_initial_stream_window_size(sz.into()); self } // soft-deprecated? deprecation warning just seems annoying... // reimplemented to take `self` instead of `&mut self` #[doc(hidden)] pub fn http2_initial_connection_window_size(&mut self, sz: impl Into>) -> &mut Self { self.protocol.http2_initial_connection_window_size(sz.into()); self } /// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`][spec] option for HTTP2 /// stream-level flow control. /// /// Default is 65,535 /// /// [spec]: https://http2.github.io/http2-spec/#SETTINGS_INITIAL_WINDOW_SIZE pub fn http2_initial_stream_window_size_(mut self, sz: impl Into>) -> Self { self.protocol.http2_initial_stream_window_size(sz.into()); self } /// Sets the max connection-level flow control for HTTP2 /// /// Default is 65,535 pub fn http2_initial_connection_window_size_(mut self, sz: impl Into>) -> Self { self.protocol.http2_initial_connection_window_size(sz.into()); self } /// Sets the [`SETTINGS_MAX_CONCURRENT_STREAMS`][spec] option for HTTP2 /// connections. /// /// Default is no limit (`None`). /// /// [spec]: https://http2.github.io/http2-spec/#SETTINGS_MAX_CONCURRENT_STREAMS pub fn http2_max_concurrent_streams(mut self, max: impl Into>) -> Self { self.protocol.http2_max_concurrent_streams(max.into()); self } /// Set the maximum buffer size. /// /// Default is ~ 400kb. pub fn http1_max_buf_size(mut self, val: usize) -> Self { self.protocol.max_buf_size(val); self } /// Sets the `Executor` to deal with connection tasks. /// /// Default is `tokio::spawn`. pub fn executor(self, executor: E2) -> Builder { Builder { incoming: self.incoming, protocol: self.protocol.with_executor(executor), } } /// Consume this `Builder`, creating a [`Server`](Server). /// /// # Example /// /// ``` /// # extern crate hyper; /// # fn main() {} /// # #[cfg(feature = "runtime")] /// # fn run() { /// use hyper::{Body, Response, Server}; /// use hyper::service::service_fn_ok; /// /// // Construct our SocketAddr to listen on... /// let addr = ([127, 0, 0, 1], 3000).into(); /// /// // And a NewService to handle each connection... /// let new_service = || { /// service_fn_ok(|_req| { /// Response::new(Body::from("Hello World")) /// }) /// }; /// /// // Then bind and serve... /// let server = Server::bind(&addr) /// .serve(new_service); /// /// // Finally, spawn `server` onto an Executor... /// # } /// ``` pub fn serve(self, new_service: S) -> Server where I: Stream, I::Error: Into>, I::Item: AsyncRead + AsyncWrite + Send + 'static, S: MakeServiceRef, S::Error: Into>, S::Service: 'static, B: Payload, E: NewSvcExec, E: H2Exec<::Future, B>, { let serve = self.protocol.serve_incoming(self.incoming, new_service); let spawn_all = serve.spawn_all(); Server { spawn_all, } } } #[cfg(feature = "runtime")] impl Builder { /// Set whether TCP keepalive messages are enabled on accepted connections. /// /// If `None` is specified, keepalive is disabled, otherwise the duration /// specified will be the time to remain idle before sending TCP keepalive /// probes. pub fn tcp_keepalive(mut self, keepalive: Option) -> Self { self.incoming.set_keepalive(keepalive); self } /// Set the value of `TCP_NODELAY` option for accepted connections. pub fn tcp_nodelay(mut self, enabled: bool) -> Self { self.incoming.set_nodelay(enabled); self } /// Set whether to sleep on accept errors. /// /// A possible scenario is that the process has hit the max open files /// allowed, and so trying to accept a new connection will fail with /// EMFILE. In some cases, it's preferable to just wait for some time, if /// the application will likely close some files (or connections), and try /// to accept the connection again. If this option is true, the error will /// be logged at the error level, since it is still a big deal, and then /// the listener will sleep for 1 second. /// /// In other cases, hitting the max open files should be treat similarly /// to being out-of-memory, and simply error (and shutdown). Setting this /// option to false will allow that. /// /// For more details see [`AddrIncoming::set_sleep_on_errors`] pub fn tcp_sleep_on_accept_errors(mut self, val: bool) -> Self { self.incoming.set_sleep_on_errors(val); self } } hyper-0.12.35/src/server/shutdown.rs010066400017500001750000000070421353675567300156010ustar0000000000000000use std::error::Error as StdError; use futures::{Async, Future, Stream, Poll}; use tokio_io::{AsyncRead, AsyncWrite}; use body::{Body, Payload}; use common::drain::{self, Draining, Signal, Watch, Watching}; use common::exec::{H2Exec, NewSvcExec}; use service::{MakeServiceRef, Service}; use super::conn::{SpawnAll, UpgradeableConnection, Watcher}; #[allow(missing_debug_implementations)] pub struct Graceful { state: State, } enum State { Running { drain: Option<(Signal, Watch)>, spawn_all: SpawnAll, signal: F, }, Draining(Draining), } impl Graceful { pub(super) fn new(spawn_all: SpawnAll, signal: F) -> Self { let drain = Some(drain::channel()); Graceful { state: State::Running { drain, spawn_all, signal, }, } } } impl Future for Graceful where I: Stream, I::Error: Into>, I::Item: AsyncRead + AsyncWrite + Send + 'static, S: MakeServiceRef, S::Service: 'static, S::Error: Into>, B: Payload, F: Future, E: H2Exec<::Future, B>, E: NewSvcExec, { type Item = (); type Error = ::Error; fn poll(&mut self) -> Poll { loop { let next = match self.state { State::Running { ref mut drain, ref mut spawn_all, ref mut signal, } => match signal.poll() { Ok(Async::Ready(())) | Err(_) => { debug!("signal received, starting graceful shutdown"); let sig = drain .take() .expect("drain channel") .0; State::Draining(sig.drain()) }, Ok(Async::NotReady) => { let watch = drain .as_ref() .expect("drain channel") .1 .clone(); return spawn_all.poll_watch(&GracefulWatcher(watch)); }, }, State::Draining(ref mut draining) => { return draining.poll() .map_err(|()| unreachable!("drain mpsc rx never errors")); } }; self.state = next; } } } #[allow(missing_debug_implementations)] #[derive(Clone)] pub struct GracefulWatcher(Watch); impl Watcher for GracefulWatcher where I: AsyncRead + AsyncWrite + Send + 'static, S: Service + 'static, E: H2Exec, { type Future = Watching, fn(&mut UpgradeableConnection)>; fn watch(&self, conn: UpgradeableConnection) -> Self::Future { self .0 .clone() .watch(conn, on_drain) } } fn on_drain(conn: &mut UpgradeableConnection) where S: Service, S::Error: Into>, I: AsyncRead + AsyncWrite, S::ResBody: Payload + 'static, E: H2Exec, { conn.graceful_shutdown() } hyper-0.12.35/src/server/tcp.rs010066400017500001750000000222531353675567300145150ustar0000000000000000use std::fmt; use std::io; use std::net::{SocketAddr, TcpListener as StdTcpListener}; use std::time::{Duration, Instant}; use futures::{Async, Future, Poll, Stream}; use tokio_reactor::Handle; use tokio_tcp::TcpListener; use tokio_timer::Delay; pub use self::addr_stream::AddrStream; /// A stream of connections from binding to an address. #[must_use = "streams do nothing unless polled"] pub struct AddrIncoming { addr: SocketAddr, listener: TcpListener, sleep_on_errors: bool, tcp_keepalive_timeout: Option, tcp_nodelay: bool, timeout: Option, } impl AddrIncoming { pub(super) fn new(addr: &SocketAddr, handle: Option<&Handle>) -> ::Result { let std_listener = StdTcpListener::bind(addr) .map_err(::Error::new_listen)?; if let Some(handle) = handle { AddrIncoming::from_std(std_listener, handle) } else { let handle = Handle::default(); AddrIncoming::from_std(std_listener, &handle) } } pub(super) fn from_std(std_listener: StdTcpListener, handle: &Handle) -> ::Result { let listener = TcpListener::from_std(std_listener, &handle) .map_err(::Error::new_listen)?; let addr = listener.local_addr().map_err(::Error::new_listen)?; Ok(AddrIncoming { listener, addr: addr, sleep_on_errors: true, tcp_keepalive_timeout: None, tcp_nodelay: false, timeout: None, }) } /// Creates a new `AddrIncoming` binding to provided socket address. pub fn bind(addr: &SocketAddr) -> ::Result { AddrIncoming::new(addr, None) } /// Get the local address bound to this listener. pub fn local_addr(&self) -> SocketAddr { self.addr } /// Set whether TCP keepalive messages are enabled on accepted connections. /// /// If `None` is specified, keepalive is disabled, otherwise the duration /// specified will be the time to remain idle before sending TCP keepalive /// probes. pub fn set_keepalive(&mut self, keepalive: Option) -> &mut Self { self.tcp_keepalive_timeout = keepalive; self } /// Set the value of `TCP_NODELAY` option for accepted connections. pub fn set_nodelay(&mut self, enabled: bool) -> &mut Self { self.tcp_nodelay = enabled; self } /// Set whether to sleep on accept errors. /// /// A possible scenario is that the process has hit the max open files /// allowed, and so trying to accept a new connection will fail with /// `EMFILE`. In some cases, it's preferable to just wait for some time, if /// the application will likely close some files (or connections), and try /// to accept the connection again. If this option is `true`, the error /// will be logged at the `error` level, since it is still a big deal, /// and then the listener will sleep for 1 second. /// /// In other cases, hitting the max open files should be treat similarly /// to being out-of-memory, and simply error (and shutdown). Setting /// this option to `false` will allow that. /// /// Default is `true`. pub fn set_sleep_on_errors(&mut self, val: bool) { self.sleep_on_errors = val; } } impl Stream for AddrIncoming { // currently unnameable... type Item = AddrStream; type Error = ::std::io::Error; fn poll(&mut self) -> Poll, Self::Error> { // Check if a previous timeout is active that was set by IO errors. if let Some(ref mut to) = self.timeout { match to.poll() { Ok(Async::Ready(())) => {} Ok(Async::NotReady) => return Ok(Async::NotReady), Err(err) => { error!("sleep timer error: {}", err); } } } self.timeout = None; loop { match self.listener.poll_accept() { Ok(Async::Ready((socket, addr))) => { if let Some(dur) = self.tcp_keepalive_timeout { if let Err(e) = socket.set_keepalive(Some(dur)) { trace!("error trying to set TCP keepalive: {}", e); } } if let Err(e) = socket.set_nodelay(self.tcp_nodelay) { trace!("error trying to set TCP nodelay: {}", e); } return Ok(Async::Ready(Some(AddrStream::new(socket, addr)))); }, Ok(Async::NotReady) => return Ok(Async::NotReady), Err(e) => { // Connection errors can be ignored directly, continue by // accepting the next request. if is_connection_error(&e) { debug!("accepted connection already errored: {}", e); continue; } if self.sleep_on_errors { // Sleep 1s. let delay = Instant::now() + Duration::from_secs(1); let mut timeout = Delay::new(delay); match timeout.poll() { Ok(Async::Ready(())) => { // Wow, it's been a second already? Ok then... error!("accept error: {}", e); continue }, Ok(Async::NotReady) => { error!("accept error: {}", e); self.timeout = Some(timeout); return Ok(Async::NotReady); }, Err(timer_err) => { error!("couldn't sleep on error, timer error: {}", timer_err); return Err(e); } } } else { return Err(e); } }, } } } } /// This function defines errors that are per-connection. Which basically /// means that if we get this error from `accept()` system call it means /// next connection might be ready to be accepted. /// /// All other errors will incur a timeout before next `accept()` is performed. /// The timeout is useful to handle resource exhaustion errors like ENFILE /// and EMFILE. Otherwise, could enter into tight loop. fn is_connection_error(e: &io::Error) -> bool { match e.kind() { io::ErrorKind::ConnectionRefused | io::ErrorKind::ConnectionAborted | io::ErrorKind::ConnectionReset => true, _ => false, } } impl fmt::Debug for AddrIncoming { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("AddrIncoming") .field("addr", &self.addr) .field("sleep_on_errors", &self.sleep_on_errors) .field("tcp_keepalive_timeout", &self.tcp_keepalive_timeout) .field("tcp_nodelay", &self.tcp_nodelay) .finish() } } mod addr_stream { use std::io::{self, Read, Write}; use std::net::SocketAddr; use bytes::{Buf, BufMut}; use futures::Poll; use tokio_tcp::TcpStream; use tokio_io::{AsyncRead, AsyncWrite}; /// A transport returned yieled by `AddrIncoming`. #[derive(Debug)] pub struct AddrStream { inner: TcpStream, pub(super) remote_addr: SocketAddr, } impl AddrStream { pub(super) fn new(tcp: TcpStream, addr: SocketAddr) -> AddrStream { AddrStream { inner: tcp, remote_addr: addr, } } /// Returns the remote (peer) address of this connection. #[inline] pub fn remote_addr(&self) -> SocketAddr { self.remote_addr } /// Consumes the AddrStream and returns the underlying IO object #[inline] pub fn into_inner(self) -> TcpStream { self.inner } } impl Read for AddrStream { #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } } impl Write for AddrStream { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { self.inner.write(buf) } #[inline] fn flush(&mut self) -> io::Result<()> { // TcpStream::flush is a noop, so skip calling it... Ok(()) } } impl AsyncRead for AddrStream { #[inline] unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { self.inner.prepare_uninitialized_buffer(buf) } #[inline] fn read_buf(&mut self, buf: &mut B) -> Poll { self.inner.read_buf(buf) } } impl AsyncWrite for AddrStream { #[inline] fn shutdown(&mut self) -> Poll<(), io::Error> { AsyncWrite::shutdown(&mut self.inner) } #[inline] fn write_buf(&mut self, buf: &mut B) -> Poll { self.inner.write_buf(buf) } } } hyper-0.12.35/src/service/make_service.rs010066400017500001750000000134541353675567300165210ustar0000000000000000use std::error::Error as StdError; use std::fmt; use futures::{Async, Future, IntoFuture, Poll}; use body::Payload; use super::Service; /// An asynchronous constructor of `Service`s. pub trait MakeService { /// The `Payload` body of the `http::Request`. type ReqBody: Payload; /// The `Payload` body of the `http::Response`. type ResBody: Payload; /// The error type that can be returned by `Service`s. type Error: Into>; /// The resolved `Service` from `new_service()`. type Service: Service< ReqBody=Self::ReqBody, ResBody=Self::ResBody, Error=Self::Error, >; /// The future returned from `new_service` of a `Service`. type Future: Future; /// The error type that can be returned when creating a new `Service`. type MakeError: Into>; /// Returns `Ready` when the constructor is ready to create a new `Service`. /// /// The implementation of this method is allowed to return a `Ready` even if /// the factory is not ready to create a new service. In this case, the future /// returned from `make_service` will resolve to an error. fn poll_ready(&mut self) -> Poll<(), Self::MakeError> { Ok(Async::Ready(())) } /// Create a new `Service`. fn make_service(&mut self, ctx: Ctx) -> Self::Future; } // Just a sort-of "trait alias" of `MakeService`, not to be implemented // by anyone, only used as bounds. #[doc(hidden)] pub trait MakeServiceRef: self::sealed::Sealed { type ReqBody: Payload; type ResBody: Payload; type Error: Into>; type Service: Service< ReqBody=Self::ReqBody, ResBody=Self::ResBody, Error=Self::Error, >; type MakeError: Into>; type Future: Future; // Acting like a #[non_exhaustive] for associated types of this trait. // // Basically, no one outside of hyper should be able to set this type // or declare bounds on it, so it should prevent people from creating // trait objects or otherwise writing code that requires using *all* // of the associated types. // // Why? So we can add new associated types to this alias in the future, // if necessary. type __DontNameMe: self::sealed::CantImpl; fn poll_ready_ref(&mut self) -> Poll<(), Self::MakeError>; fn make_service_ref(&mut self, ctx: &Ctx) -> Self::Future; } impl MakeServiceRef for T where T: for<'a> MakeService<&'a Ctx, Error=E, MakeError=ME, Service=S, Future=F, ReqBody=IB, ResBody=OB>, E: Into>, ME: Into>, S: Service, F: Future, IB: Payload, OB: Payload, { type Error = E; type Service = S; type ReqBody = IB; type ResBody = OB; type MakeError = ME; type Future = F; type __DontNameMe = self::sealed::CantName; fn poll_ready_ref(&mut self) -> Poll<(), Self::MakeError> { self.poll_ready() } fn make_service_ref(&mut self, ctx: &Ctx) -> Self::Future { self.make_service(ctx) } } impl self::sealed::Sealed for T where T: for<'a> MakeService<&'a Ctx, Error=E, MakeError=ME, Service=S, Future=F, ReqBody=IB, ResBody=OB>, E: Into>, ME: Into>, S: Service, F: Future, IB: Payload, OB: Payload, {} /// Create a `MakeService` from a function. /// /// # Example /// /// ```rust,no_run /// # #[cfg(feature = "runtime")] fn main() { /// use std::net::TcpStream; /// use hyper::{Body, Request, Response, Server}; /// use hyper::rt::{self, Future}; /// use hyper::server::conn::AddrStream; /// use hyper::service::{make_service_fn, service_fn_ok}; /// /// let addr = ([127, 0, 0, 1], 3000).into(); /// /// let make_svc = make_service_fn(|socket: &AddrStream| { /// let remote_addr = socket.remote_addr(); /// service_fn_ok(move |_: Request| { /// Response::new(Body::from(format!("Hello, {}", remote_addr))) /// }) /// }); /// /// // Then bind and serve... /// let server = Server::bind(&addr) /// .serve(make_svc); /// /// // Finally, spawn `server` onto an Executor... /// rt::run(server.map_err(|e| { /// eprintln!("server error: {}", e); /// })); /// # } /// # #[cfg(not(feature = "runtime"))] fn main() {} /// ``` pub fn make_service_fn(f: F) -> MakeServiceFn where F: FnMut(&Ctx) -> Ret, Ret: IntoFuture, { MakeServiceFn { f, } } // Not exported from crate as this will likely be replaced with `impl Service`. pub struct MakeServiceFn { f: F, } impl<'c, F, Ctx, Ret, ReqBody, ResBody> MakeService<&'c Ctx> for MakeServiceFn where F: FnMut(&Ctx) -> Ret, Ret: IntoFuture, Ret::Item: Service, Ret::Error: Into>, ReqBody: Payload, ResBody: Payload, { type ReqBody = ReqBody; type ResBody = ResBody; type Error = ::Error; type Service = Ret::Item; type Future = Ret::Future; type MakeError = Ret::Error; fn make_service(&mut self, ctx: &'c Ctx) -> Self::Future { (self.f)(ctx).into_future() } } impl fmt::Debug for MakeServiceFn { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("MakeServiceFn") .finish() } } mod sealed { pub trait Sealed {} pub trait CantImpl {} #[allow(missing_debug_implementations)] pub enum CantName {} impl CantImpl for CantName {} } hyper-0.12.35/src/service/mod.rs010066400017500001750000000027751353675567300146470ustar0000000000000000//! Services and MakeServices //! //! - A [`Service`](service::Service) is a trait representing an asynchronous //! function of a request to a response. It's similar to //! `async fn(Request) -> Result`. //! - A [`MakeService`](service::MakeService) is a trait creating specific //! instances of a `Service`. //! //! These types are conceptually similar to those in //! [tower](https://crates.io/crates/tower), while being specific to hyper. //! //! # Service //! //! In hyper, especially in the server setting, a `Service` is usually bound //! to a single connection. It defines how to respond to **all** requests that //! connection will receive. //! //! While it's possible to implement `Service` for a type manually, the helpers //! [`service_fn`](service::service_fn) and //! [`service_fn_ok`](service::service_fn_ok) should be sufficient for most //! cases. //! //! # MakeService //! //! Since a `Service` is bound to a single connection, a [`Server`](::Server) //! needs a way to make them as it accepts connections. This is what a //! `MakeService` does. //! //! Resources that need to be shared by all `Service`s can be put into a //! `MakeService`, and then passed to individual `Service`s when `make_service` //! is called. mod make_service; mod new_service; mod service; pub use self::make_service::{make_service_fn, MakeService, MakeServiceRef}; // NewService is soft-deprecated. #[doc(hidden)] pub use self::new_service::NewService; pub use self::service::{service_fn, service_fn_ok, Service}; hyper-0.12.35/src/service/new_service.rs010066400017500001750000000036701353675567300163740ustar0000000000000000use std::error::Error as StdError; use futures::{Async, Future, IntoFuture, Poll}; use body::Payload; use super::{MakeService, Service}; /// An asynchronous constructor of `Service`s. pub trait NewService { /// The `Payload` body of the `http::Request`. type ReqBody: Payload; /// The `Payload` body of the `http::Response`. type ResBody: Payload; /// The error type that can be returned by `Service`s. type Error: Into>; /// The resolved `Service` from `new_service()`. type Service: Service< ReqBody=Self::ReqBody, ResBody=Self::ResBody, Error=Self::Error, >; /// The future returned from `new_service` of a `Service`. type Future: Future; /// The error type that can be returned when creating a new `Service`. type InitError: Into>; #[doc(hidden)] fn poll_ready(&mut self) -> Poll<(), Self::InitError> { Ok(Async::Ready(())) } /// Create a new `Service`. fn new_service(&self) -> Self::Future; } impl NewService for F where F: Fn() -> R, R: IntoFuture, R::Error: Into>, S: Service, { type ReqBody = S::ReqBody; type ResBody = S::ResBody; type Error = S::Error; type Service = S; type Future = R::Future; type InitError = R::Error; fn new_service(&self) -> Self::Future { (*self)().into_future() } } impl MakeService for N where N: NewService, { type ReqBody = N::ReqBody; type ResBody = N::ResBody; type Error = N::Error; type Service = N::Service; type Future = N::Future; type MakeError = N::InitError; fn poll_ready(&mut self) -> Poll<(), Self::MakeError> { NewService::poll_ready(self) } fn make_service(&mut self, _: Ctx) -> Self::Future { self.new_service() } } hyper-0.12.35/src/service/service.rs010066400017500001750000000120361353675567300155170ustar0000000000000000use std::error::Error as StdError; use std::fmt; use std::marker::PhantomData; use futures::{future, Async, Future, IntoFuture, Poll}; use body::Payload; use common::Never; use ::{Request, Response}; /// An asynchronous function from `Request` to `Response`. pub trait Service { /// The `Payload` body of the `http::Request`. type ReqBody: Payload; /// The `Payload` body of the `http::Response`. type ResBody: Payload; /// The error type that can occur within this `Service`. /// /// Note: Returning an `Error` to a hyper server will cause the connection /// to be abruptly aborted. In most cases, it is better to return a `Response` /// with a 4xx or 5xx status code. type Error: Into>; /// The `Future` returned by this `Service`. type Future: Future, Error=Self::Error>; /// Returns `Ready` when the service is able to process requests. /// /// The implementation of this method is allowed to return a `Ready` even if /// the service is not ready to process. In this case, the future returned /// from `call` will resolve to an error. fn poll_ready(&mut self) -> Poll<(), Self::Error> { Ok(Async::Ready(())) } /// Calls this `Service` with a request, returning a `Future` of the response. fn call(&mut self, req: Request) -> Self::Future; } /// Create a `Service` from a function. /// /// # Example /// /// ```rust /// use hyper::{Body, Request, Response, Version}; /// use hyper::service::service_fn; /// /// let service = service_fn(|req: Request| { /// if req.version() == Version::HTTP_11 { /// Ok(Response::new(Body::from("Hello World"))) /// } else { /// // Note: it's usually better to return a Response /// // with an appropriate StatusCode instead of an Err. /// Err("not HTTP/1.1, abort connection") /// } /// }); /// ``` pub fn service_fn(f: F) -> ServiceFn where F: FnMut(Request) -> S, S: IntoFuture, { ServiceFn { f, _req: PhantomData, } } /// Create a `Service` from a function that never errors. /// /// # Example /// /// ```rust /// use hyper::{Body, Request, Response}; /// use hyper::service::service_fn_ok; /// /// let service = service_fn_ok(|req: Request| { /// println!("request: {} {}", req.method(), req.uri()); /// Response::new(Body::from("Hello World")) /// }); /// ``` pub fn service_fn_ok(f: F) -> ServiceFnOk where F: FnMut(Request) -> Response, S: Payload, { ServiceFnOk { f, _req: PhantomData, } } // Not exported from crate as this will likely be replaced with `impl Service`. pub struct ServiceFn { f: F, _req: PhantomData, } impl Service for ServiceFn where F: FnMut(Request) -> Ret, ReqBody: Payload, Ret: IntoFuture>, Ret::Error: Into>, ResBody: Payload, { type ReqBody = ReqBody; type ResBody = ResBody; type Error = Ret::Error; type Future = Ret::Future; fn call(&mut self, req: Request) -> Self::Future { (self.f)(req).into_future() } } impl IntoFuture for ServiceFn { type Future = future::FutureResult; type Item = Self; type Error = Never; fn into_future(self) -> Self::Future { future::ok(self) } } impl fmt::Debug for ServiceFn { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("impl Service") .finish() } } // Not exported from crate as this will likely be replaced with `impl Service`. pub struct ServiceFnOk { f: F, _req: PhantomData, } impl Service for ServiceFnOk where F: FnMut(Request) -> Response, ReqBody: Payload, ResBody: Payload, { type ReqBody = ReqBody; type ResBody = ResBody; type Error = Never; type Future = future::FutureResult, Never>; fn call(&mut self, req: Request) -> Self::Future { future::ok((self.f)(req)) } } impl IntoFuture for ServiceFnOk { type Future = future::FutureResult; type Item = Self; type Error = Never; fn into_future(self) -> Self::Future { future::ok(self) } } impl fmt::Debug for ServiceFnOk { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("impl Service") .finish() } } //#[cfg(test)] fn _assert_fn_mut() { fn assert_service(_t: &T) {} let mut val = 0; let svc = service_fn(move |_req: Request<::Body>| { val += 1; future::ok::<_, Never>(Response::new(::Body::empty())) }); assert_service(&svc); let svc = service_fn_ok(move |_req: Request<::Body>| { val += 1; Response::new(::Body::empty()) }); assert_service(&svc); } hyper-0.12.35/src/upgrade.rs010066400017500001750000000151161353675567300140500ustar0000000000000000//! HTTP Upgrades //! //! See [this example][example] showing how upgrades work with both //! Clients and Servers. //! //! [example]: https://github.com/hyperium/hyper/blob/0.12.x/examples/upgrades.rs use std::any::TypeId; use std::error::Error as StdError; use std::fmt; use std::io::{self, Read, Write}; use bytes::{Buf, BufMut, Bytes}; use futures::{Async, Future, Poll}; use futures::sync::oneshot; use tokio_io::{AsyncRead, AsyncWrite}; use common::io::Rewind; /// An upgraded HTTP connection. /// /// This type holds a trait object internally of the original IO that /// was used to speak HTTP before the upgrade. It can be used directly /// as a `Read` or `Write` for convenience. /// /// Alternatively, if the exact type is known, this can be deconstructed /// into its parts. pub struct Upgraded { io: Rewind>, } /// A future for a possible HTTP upgrade. /// /// If no upgrade was available, or it doesn't succeed, yields an `Error`. pub struct OnUpgrade { rx: Option>>, } /// The deconstructed parts of an [`Upgraded`](Upgraded) type. /// /// Includes the original IO type, and a read buffer of bytes that the /// HTTP state machine may have already read before completing an upgrade. #[derive(Debug)] pub struct Parts { /// The original IO object used before the upgrade. pub io: T, /// A buffer of bytes that have been read but not processed as HTTP. /// /// For instance, if the `Connection` is used for an HTTP upgrade request, /// it is possible the server sent back the first bytes of the new protocol /// along with the response upgrade. /// /// You will want to check for any existing bytes if you plan to continue /// communicating on the IO object. pub read_buf: Bytes, _inner: (), } pub(crate) struct Pending { tx: oneshot::Sender<::Result> } /// Error cause returned when an upgrade was expected but canceled /// for whatever reason. /// /// This likely means the actual `Conn` future wasn't polled and upgraded. #[derive(Debug)] struct UpgradeExpected(()); pub(crate) fn pending() -> (Pending, OnUpgrade) { let (tx, rx) = oneshot::channel(); ( Pending { tx, }, OnUpgrade { rx: Some(rx), }, ) } pub(crate) trait Io: AsyncRead + AsyncWrite + 'static { fn __hyper_type_id(&self) -> TypeId { TypeId::of::() } } impl dyn Io + Send { fn __hyper_is(&self) -> bool { let t = TypeId::of::(); self.__hyper_type_id() == t } fn __hyper_downcast(self: Box) -> Result, Box> { if self.__hyper_is::() { // Taken from `std::error::Error::downcast()`. unsafe { let raw: *mut dyn Io = Box::into_raw(self); Ok(Box::from_raw(raw as *mut T)) } } else { Err(self) } } } impl Io for T {} // ===== impl Upgraded ===== impl Upgraded { pub(crate) fn new(io: Box, read_buf: Bytes) -> Self { Upgraded { io: Rewind::new_buffered(io, read_buf), } } /// Tries to downcast the internal trait object to the type passed. /// /// On success, returns the downcasted parts. On error, returns the /// `Upgraded` back. pub fn downcast(self) -> Result, Self> { let (io, buf) = self.io.into_inner(); match io.__hyper_downcast() { Ok(t) => Ok(Parts { io: *t, read_buf: buf, _inner: (), }), Err(io) => Err(Upgraded { io: Rewind::new_buffered(io, buf), }) } } } impl Read for Upgraded { #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { self.io.read(buf) } } impl Write for Upgraded { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { self.io.write(buf) } #[inline] fn flush(&mut self) -> io::Result<()> { self.io.flush() } } impl AsyncRead for Upgraded { #[inline] unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { self.io.prepare_uninitialized_buffer(buf) } #[inline] fn read_buf(&mut self, buf: &mut B) -> Poll { self.io.read_buf(buf) } } impl AsyncWrite for Upgraded { #[inline] fn shutdown(&mut self) -> Poll<(), io::Error> { AsyncWrite::shutdown(&mut self.io) } #[inline] fn write_buf(&mut self, buf: &mut B) -> Poll { self.io.write_buf(buf) } } impl fmt::Debug for Upgraded { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Upgraded") .finish() } } // ===== impl OnUpgrade ===== impl OnUpgrade { pub(crate) fn none() -> Self { OnUpgrade { rx: None, } } pub(crate) fn is_none(&self) -> bool { self.rx.is_none() } } impl Future for OnUpgrade { type Item = Upgraded; type Error = ::Error; fn poll(&mut self) -> Poll { match self.rx { Some(ref mut rx) => match rx.poll() { Ok(Async::NotReady) => Ok(Async::NotReady), Ok(Async::Ready(Ok(upgraded))) => Ok(Async::Ready(upgraded)), Ok(Async::Ready(Err(err))) => Err(err), Err(_oneshot_canceled) => Err( ::Error::new_canceled().with(UpgradeExpected(())) ), }, None => Err(::Error::new_user_no_upgrade()), } } } impl fmt::Debug for OnUpgrade { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("OnUpgrade") .finish() } } // ===== impl Pending ===== impl Pending { pub(crate) fn fulfill(self, upgraded: Upgraded) { trace!("pending upgrade fulfill"); let _ = self.tx.send(Ok(upgraded)); } /// Don't fulfill the pending Upgrade, but instead signal that /// upgrades are handled manually. pub(crate) fn manual(self) { trace!("pending upgrade handled manually"); let _ = self.tx.send(Err(::Error::new_user_manual_upgrade())); } } // ===== impl UpgradeExpected ===== impl fmt::Display for UpgradeExpected { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.description()) } } impl StdError for UpgradeExpected { fn description(&self) -> &str { "upgrade expected but not completed" } } hyper-0.12.35/Cargo.lock0000644000001432310000000000000103510ustar00# This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "aho-corasick" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "arrayvec" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "atty" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "autocfg" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "byteorder" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bytes" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cfg-if" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "chrono" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-deque" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-epoch" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-queue" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-utils" version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "either" version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "env_logger" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "fnv" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "fuchsia-cprng" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "fuchsia-zircon" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "fuchsia-zircon-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures" version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures-cpupool" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "futures-timer" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "h2" version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "http" version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "http-body" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "httparse" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "humantime" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hyper" version = "0.12.35" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_env_logger 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "spmc 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-mockstream 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "idna" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "indexmap" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "iovec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "itoa" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "kernel32-sys" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" version = "0.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lock_api" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "log" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "matches" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memchr" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memoffset" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "mio" version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "miow" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "net2" version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "nodrop" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num-integer" version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num_cpus" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "owning_ref" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "parking_lot" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "parking_lot_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "percent-encoding" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "pretty_env_logger" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "proc-macro2" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quick-error" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_chacha" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rand_hc" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_isaac" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_jitter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_os" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_pcg" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_xorshift" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rdrand" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "regex" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rustc_version" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ryu" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "scopeguard" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "scopeguard" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "semver" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "semver-parser" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "slab" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "spmc" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "stable_deref_trait" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "string" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "termcolor" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thread_local" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio" version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-buf" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-current-thread" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-executor" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-fs" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-io" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-mockstream" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-reactor" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-sync 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-sync" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-tcp" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-threadpool" version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-timer" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "try-lock" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-bidi" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "unicode-normalization" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "url" version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "want" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "winapi" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi-util" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wincolor" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ws2_32-sys" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" "checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum futures-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5cedfe9b6dc756220782cc1ba5bcb1fa091cdcba155e40d3556159c3db58043" "checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" "checksum http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "372bcb56f939e449117fb0869c2e8fd8753a8223d92a172c6e808cf123a5b6e4" "checksum http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" "checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4d6d89e0948bf10c08b9ecc8ac5b83f07f857ebe2c0cbe38de15b4e4f510356" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" "checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum pretty_env_logger 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "717ee476b1690853d222af4634056d830b5197ffd747726a9a1eee6da9f49074" "checksum proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c5c2380ae88876faae57698be9e9775e3544decad214599c3a6266cca6ac802" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" "checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88c3d9193984285d544df4a30c23a4e62ead42edf70a4452ceb76dac1ce05c26" "checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" "checksum serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425" "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" "checksum spmc 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02a8428da277a8e3a15271d79943e80ccc2ef254e78813a166a08d65e4c3ece5" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" "checksum tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" "checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443" "checksum tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f27ee0e6db01c5f0b2973824547ce7e637b2ed79b891a9677b0de9bd532b6ac" "checksum tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe6dc22b08d6993916647d108a1a7d15b9cd29c4f4496c62b92c45b5041b7af" "checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926" "checksum tokio-mockstream 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41bfc436ef8b7f60c19adf3df086330ae9992385e4d8c53b17a323cad288e155" "checksum tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6af16bfac7e112bea8b0442542161bfc41cbfa4466b580bdda7d18cb88b911ce" "checksum tokio-sync 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2162248ff317e2bc713b261f242b69dbb838b85248ed20bb21df56d60ea4cae7" "checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" "checksum tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "90ca01319dea1e376a001e8dc192d42ebde6dd532532a5bad988ac37db365b19" "checksum tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f2106812d500ed25a4f38235b9cae8f78a09edf43203e16e59c3b769a342a60e" "checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"