mirror of https://github.com/rwf2/Rocket.git
Update 'hyper', 'futures-*-preview', and 'tokio-*' dependencies.
Use I/O traits and types from 'tokio-io' as much as possible. A few adapters only exist in futures-io-preview and use futures-tokio-compat as a bridge for now.
This commit is contained in:
parent
0d89637e8b
commit
ea06878581
|
@ -42,7 +42,8 @@ memcache_pool = ["databases", "memcache", "r2d2-memcache"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Global dependencies.
|
# Global dependencies.
|
||||||
futures-preview = { version = "0.3.0-alpha.18" }
|
futures-util-preview = "0.3.0-alpha.19"
|
||||||
|
tokio-io = "=0.2.0-alpha.6"
|
||||||
rocket_contrib_codegen = { version = "0.5.0-dev", path = "../codegen", optional = true }
|
rocket_contrib_codegen = { version = "0.5.0-dev", path = "../codegen", optional = true }
|
||||||
rocket = { version = "0.5.0-dev", path = "../../core/lib/", default-features = false }
|
rocket = { version = "0.5.0-dev", path = "../../core/lib/", default-features = false }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
@ -87,7 +88,7 @@ brotli = { version = "3.3", optional = true }
|
||||||
flate2 = { version = "1.0", optional = true }
|
flate2 = { version = "1.0", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio-timer = "=0.3.0-alpha.5"
|
tokio-timer = "=0.3.0-alpha.6"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
all-features = true
|
all-features = true
|
||||||
|
|
|
@ -18,14 +18,13 @@ use std::ops::{Deref, DerefMut};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
|
|
||||||
use futures::io::AsyncReadExt;
|
use tokio_io::AsyncReadExt;
|
||||||
|
|
||||||
use rocket::request::Request;
|
use rocket::request::Request;
|
||||||
use rocket::outcome::Outcome::*;
|
use rocket::outcome::Outcome::*;
|
||||||
use rocket::data::{Transform::*, Transformed, Data, FromData, TransformFuture, FromDataFuture};
|
use rocket::data::{Transform::*, Transformed, Data, FromData, TransformFuture, FromDataFuture};
|
||||||
use rocket::response::{self, Responder, content};
|
use rocket::response::{self, Responder, content};
|
||||||
use rocket::http::Status;
|
use rocket::http::Status;
|
||||||
use rocket::AsyncReadExt as _;
|
|
||||||
|
|
||||||
use serde::{Serialize, Serializer};
|
use serde::{Serialize, Serializer};
|
||||||
use serde::de::{Deserialize, Deserializer};
|
use serde::de::{Deserialize, Deserializer};
|
||||||
|
|
|
@ -16,14 +16,13 @@
|
||||||
|
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use futures::io::AsyncReadExt;
|
use tokio_io::AsyncReadExt;
|
||||||
|
|
||||||
use rocket::request::Request;
|
use rocket::request::Request;
|
||||||
use rocket::outcome::Outcome::*;
|
use rocket::outcome::Outcome::*;
|
||||||
use rocket::data::{Data, FromData, FromDataFuture, Transform::*, TransformFuture, Transformed};
|
use rocket::data::{Data, FromData, FromDataFuture, Transform::*, TransformFuture, Transformed};
|
||||||
use rocket::http::Status;
|
use rocket::http::Status;
|
||||||
use rocket::response::{self, content, Responder};
|
use rocket::response::{self, content, Responder};
|
||||||
use rocket::AsyncReadExt as _;
|
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde::de::Deserialize;
|
use serde::de::Deserialize;
|
||||||
|
|
|
@ -28,5 +28,6 @@ version_check = "0.9.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rocket = { version = "0.5.0-dev", path = "../lib" }
|
rocket = { version = "0.5.0-dev", path = "../lib" }
|
||||||
futures-preview = "0.3.0-alpha.18"
|
futures-preview = "0.3.0-alpha.19"
|
||||||
|
tokio-io = "0.2.0-alpha.6"
|
||||||
compiletest_rs = { version = "0.3", features = ["stable"] }
|
compiletest_rs = { version = "0.3", features = ["stable"] }
|
||||||
|
|
|
@ -22,8 +22,7 @@ impl FromDataSimple for Simple {
|
||||||
|
|
||||||
fn from_data(_: &Request<'_>, data: Data) -> data::FromDataFuture<'static, Self, ()> {
|
fn from_data(_: &Request<'_>, data: Data) -> data::FromDataFuture<'static, Self, ()> {
|
||||||
Box::pin(async {
|
Box::pin(async {
|
||||||
use futures::io::AsyncReadExt as _;
|
use tokio_io::AsyncReadExt;
|
||||||
use rocket::AsyncReadExt as _;
|
|
||||||
|
|
||||||
let mut string = String::new();
|
let mut string = String::new();
|
||||||
let mut stream = data.open().take(64);
|
let mut stream = data.open().take(64);
|
||||||
|
|
|
@ -30,8 +30,7 @@ impl FromDataSimple for Simple {
|
||||||
|
|
||||||
fn from_data(_: &Request<'_>, data: Data) -> data::FromDataFuture<'static, Self, ()> {
|
fn from_data(_: &Request<'_>, data: Data) -> data::FromDataFuture<'static, Self, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
use futures::io::AsyncReadExt as _;
|
use tokio_io::AsyncReadExt;
|
||||||
use rocket::AsyncReadExt as _;
|
|
||||||
|
|
||||||
let mut string = String::new();
|
let mut string = String::new();
|
||||||
let mut stream = data.open().take(64);
|
let mut stream = data.open().take(64);
|
||||||
|
|
|
@ -23,20 +23,20 @@ private-cookies = ["cookie/private", "cookie/key-expansion"]
|
||||||
smallvec = "1.0"
|
smallvec = "1.0"
|
||||||
percent-encoding = "1"
|
percent-encoding = "1"
|
||||||
# TODO.async: stop using stream-unstable
|
# TODO.async: stop using stream-unstable
|
||||||
hyper = { version = "=0.13.0-alpha.2", default-features = false, features = ["unstable-stream"] }
|
hyper = { version = "=0.13.0-alpha.4", default-features = false, features = ["unstable-stream"] }
|
||||||
http = "0.1.17"
|
http = "0.1.17"
|
||||||
mime = "0.3.13"
|
mime = "0.3.13"
|
||||||
time = "0.2.11"
|
time = "0.2.11"
|
||||||
indexmap = "1.0"
|
indexmap = "1.0"
|
||||||
state = "0.4"
|
state = "0.4"
|
||||||
tokio-rustls = { version = "0.12.0-alpha.3", optional = true }
|
tokio-rustls = { version = "0.12.0-alpha.4", optional = true }
|
||||||
tokio-io = "=0.2.0-alpha.5"
|
tokio-io = "=0.2.0-alpha.6"
|
||||||
tokio-net = "=0.2.0-alpha.5"
|
tokio-net = { version = "=0.2.0-alpha.6", features = ["tcp"] }
|
||||||
tokio-timer = "=0.3.0-alpha.5"
|
tokio-timer = "=0.3.0-alpha.6"
|
||||||
cookie = { version = "0.14.0", features = ["percent-encode"] }
|
cookie = { version = "0.14.0", features = ["percent-encode"] }
|
||||||
pear = "0.1"
|
pear = "0.1"
|
||||||
unicode-xid = "0.2"
|
unicode-xid = "0.2"
|
||||||
futures-preview = "0.3.0-alpha.18"
|
futures-core-preview = "0.3.0-alpha.19"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -101,7 +101,6 @@ impl<L: Listener> Incoming<L> {
|
||||||
|
|
||||||
// Sleep for the specified duration
|
// Sleep for the specified duration
|
||||||
let delay = Instant::now() + duration;
|
let delay = Instant::now() + duration;
|
||||||
// TODO.async: This depends on a tokio Timer being set in the environment
|
|
||||||
let mut error_delay = tokio_timer::delay(delay);
|
let mut error_delay = tokio_timer::delay(delay);
|
||||||
|
|
||||||
match Pin::new(&mut error_delay).poll(cx) {
|
match Pin::new(&mut error_delay).poll(cx) {
|
||||||
|
@ -128,7 +127,7 @@ impl<L: Listener + Unpin> Accept for Incoming<L> {
|
||||||
type Error = io::Error;
|
type Error = io::Error;
|
||||||
|
|
||||||
fn poll_accept(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Result<Self::Conn, Self::Error>>> {
|
fn poll_accept(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Result<Self::Conn, Self::Error>>> {
|
||||||
let result = futures::ready!(self.poll_next(cx));
|
let result = futures_core::ready!(self.poll_next(cx));
|
||||||
Poll::Ready(Some(result))
|
Poll::Ready(Some(result))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,8 +156,6 @@ impl<L: fmt::Debug> fmt::Debug for Incoming<L> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO.async: Put these under a feature such as #[cfg(feature = "tokio-runtime")]
|
|
||||||
|
|
||||||
pub fn bind_tcp(address: SocketAddr) -> Pin<Box<dyn Future<Output=Result<TcpListener, io::Error>> + Send>> {
|
pub fn bind_tcp(address: SocketAddr) -> Pin<Box<dyn Future<Output=Result<TcpListener, io::Error>> + Send>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
Ok(TcpListener::bind(address).await?)
|
Ok(TcpListener::bind(address).await?)
|
||||||
|
@ -174,8 +171,8 @@ impl Listener for TcpListener {
|
||||||
|
|
||||||
fn poll_accept(&mut self, cx: &mut Context<'_>) -> Poll<Result<Self::Connection, io::Error>> {
|
fn poll_accept(&mut self, cx: &mut Context<'_>) -> Poll<Result<Self::Connection, io::Error>> {
|
||||||
// NB: This is only okay because TcpListener::accept() is stateless.
|
// NB: This is only okay because TcpListener::accept() is stateless.
|
||||||
let accept = self.accept();
|
let mut accept = self.accept();
|
||||||
futures::pin_mut!(accept);
|
let accept = unsafe { Pin::new_unchecked(&mut accept) };
|
||||||
accept.poll(cx).map_ok(|(stream, _addr)| stream)
|
accept.poll(cx).map_ok(|(stream, _addr)| stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,8 +67,6 @@ pub fn load_private_key<P: AsRef<Path>>(path: P) -> Result<rustls::PrivateKey, E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO.async: Put these under a feature such as #[cfg(feature = "tokio-runtime")]
|
|
||||||
|
|
||||||
pub struct TlsListener {
|
pub struct TlsListener {
|
||||||
listener: TcpListener,
|
listener: TcpListener,
|
||||||
acceptor: TlsAcceptor,
|
acceptor: TlsAcceptor,
|
||||||
|
|
|
@ -27,9 +27,11 @@ ctrl_c_shutdown = ["tokio/signal"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rocket_codegen = { version = "0.5.0-dev", path = "../codegen" }
|
rocket_codegen = { version = "0.5.0-dev", path = "../codegen" }
|
||||||
rocket_http = { version = "0.5.0-dev", path = "../http" }
|
rocket_http = { version = "0.5.0-dev", path = "../http" }
|
||||||
futures-preview = "0.3.0-alpha.18"
|
futures-core-preview = "0.3.0-alpha.19"
|
||||||
futures-tokio-compat = { git = "https://github.com/Nemo157/futures-tokio-compat", rev = "8a93702" }
|
futures-channel-preview = "0.3.0-alpha.19"
|
||||||
tokio = "=0.2.0-alpha.5"
|
futures-util-preview = "0.3.0-alpha.19"
|
||||||
|
tokio = "=0.2.0-alpha.6"
|
||||||
|
tokio-io = "=0.2.0-alpha.6"
|
||||||
yansi = "0.5"
|
yansi = "0.5"
|
||||||
log = { version = "0.4", features = ["std"] }
|
log = { version = "0.4", features = ["std"] }
|
||||||
toml = "0.4.7"
|
toml = "0.4.7"
|
||||||
|
@ -40,12 +42,13 @@ memchr = "2" # TODO: Use pear instead.
|
||||||
binascii = "0.1"
|
binascii = "0.1"
|
||||||
pear = "0.1"
|
pear = "0.1"
|
||||||
atty = "0.2"
|
atty = "0.2"
|
||||||
async-std = "0.99.4"
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
yansi = "0.5"
|
yansi = "0.5"
|
||||||
version_check = "0.9.1"
|
version_check = "0.9.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
futures-preview = "0.3.0-alpha.19"
|
||||||
|
futures-tokio-compat = { git = "https://github.com/Nemo157/futures-tokio-compat", rev = "8a93702" }
|
||||||
# TODO: Find a way to not depend on this.
|
# TODO: Find a way to not depend on this.
|
||||||
lazy_static = "1.0"
|
lazy_static = "1.0"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use futures::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
use crate::response;
|
use crate::response;
|
||||||
use crate::handler::ErrorHandler;
|
use crate::handler::ErrorHandler;
|
||||||
|
@ -154,7 +154,7 @@ macro_rules! default_catchers {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
|
|
||||||
$(
|
$(
|
||||||
fn $fn_name<'r>(req: &'r Request<'_>) -> futures::future::BoxFuture<'r, response::Result<'r>> {
|
fn $fn_name<'r>(req: &'r Request<'_>) -> futures_core::future::BoxFuture<'r, response::Result<'r>> {
|
||||||
status::Custom(Status::from_code($code).unwrap(),
|
status::Custom(Status::from_code($code).unwrap(),
|
||||||
content::Html(error_page_template!($code, $name, $description))
|
content::Html(error_page_template!($code, $name, $description))
|
||||||
).respond_to(req)
|
).respond_to(req)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use futures::future::BoxFuture;
|
use futures_core::future::BoxFuture;
|
||||||
|
|
||||||
use crate::{Request, Data};
|
use crate::{Request, Data};
|
||||||
use crate::handler::{Outcome, ErrorHandler};
|
use crate::handler::{Outcome, ErrorHandler};
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
|
use std::future::Future;
|
||||||
|
use std::io;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use futures::io::{self, AsyncRead, AsyncReadExt as _, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite, AsyncReadExt as _};
|
||||||
use futures::future::Future;
|
|
||||||
use futures::stream::TryStreamExt;
|
|
||||||
|
|
||||||
use super::data_stream::DataStream;
|
use super::data_stream::DataStream;
|
||||||
|
|
||||||
use crate::http::hyper;
|
use crate::http::hyper;
|
||||||
|
use crate::ext::{AsyncReadExt, AsyncReadBody};
|
||||||
use crate::ext::AsyncReadExt;
|
|
||||||
|
|
||||||
/// The number of bytes to read into the "peek" buffer.
|
/// The number of bytes to read into the "peek" buffer.
|
||||||
const PEEK_BYTES: usize = 512;
|
const PEEK_BYTES: usize = 512;
|
||||||
|
@ -135,20 +134,19 @@ impl Data {
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use std::io;
|
/// use std::io;
|
||||||
/// use futures::io::AllowStdIo;
|
|
||||||
/// use rocket::Data;
|
/// use rocket::Data;
|
||||||
///
|
///
|
||||||
/// async fn handler(mut data: Data) -> io::Result<String> {
|
/// async fn handler(mut data: Data) -> io::Result<String> {
|
||||||
/// // write all of the data to stdout
|
/// // write all of the data to stdout
|
||||||
/// let written = data.stream_to(AllowStdIo::new(io::stdout())).await?;
|
/// let written = data.stream_to(tokio::io::stdout()).await?;
|
||||||
/// Ok(format!("Wrote {} bytes.", written))
|
/// Ok(format!("Wrote {} bytes.", written))
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn stream_to<'w, W: AsyncWrite + Unpin + 'w>(self, mut writer: W) -> impl Future<Output = io::Result<u64>> + 'w {
|
pub fn stream_to<'w, W: AsyncWrite + Unpin + 'w>(self, mut writer: W) -> impl Future<Output = io::Result<u64>> + 'w {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let stream = self.open();
|
let mut stream = self.open();
|
||||||
stream.copy_into(&mut writer).await
|
stream.copy(&mut writer).await
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +170,7 @@ impl Data {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn stream_to_file<P: AsRef<Path> + Send + Unpin + 'static>(self, path: P) -> impl Future<Output = io::Result<u64>> {
|
pub fn stream_to_file<P: AsRef<Path> + Send + Unpin + 'static>(self, path: P) -> impl Future<Output = io::Result<u64>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let mut file = async_std::fs::File::create(path).await?;
|
let mut file = tokio::fs::File::create(path).await?;
|
||||||
let streaming = self.stream_to(&mut file);
|
let streaming = self.stream_to(&mut file);
|
||||||
streaming.await
|
streaming.await
|
||||||
})
|
})
|
||||||
|
@ -186,9 +184,7 @@ impl Data {
|
||||||
pub(crate) async fn new(body: hyper::Body) -> Data {
|
pub(crate) async fn new(body: hyper::Body) -> Data {
|
||||||
trace_!("Data::new({:?})", body);
|
trace_!("Data::new({:?})", body);
|
||||||
|
|
||||||
let mut stream = body.map_err(|e| {
|
let mut stream = AsyncReadBody::from(body);
|
||||||
io::Error::new(io::ErrorKind::Other, e)
|
|
||||||
}).into_async_read();
|
|
||||||
|
|
||||||
let mut peek_buf = vec![0; PEEK_BYTES];
|
let mut peek_buf = vec![0; PEEK_BYTES];
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
use futures::io::{AsyncRead, Error as IoError};
|
use tokio_io::AsyncRead;
|
||||||
use futures::task::{Poll, Context};
|
|
||||||
|
|
||||||
// TODO.async: Consider storing the real type here instead of a Box to avoid
|
// TODO.async: Consider storing the real type here instead of a Box to avoid
|
||||||
// the dynamic dispatch
|
// the dynamic dispatch
|
||||||
|
@ -19,7 +19,7 @@ pub struct DataStream(pub(crate) Vec<u8>, pub(crate) Box<dyn AsyncRead + Unpin +
|
||||||
// possible since Hyper's `HttpReader` doesn't implement `BufRead`.
|
// possible since Hyper's `HttpReader` doesn't implement `BufRead`.
|
||||||
impl AsyncRead for DataStream {
|
impl AsyncRead for DataStream {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<Result<usize, IoError>> {
|
fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<Result<usize, std::io::Error>> {
|
||||||
trace_!("DataStream::poll_read()");
|
trace_!("DataStream::poll_read()");
|
||||||
if self.0.len() > 0 {
|
if self.0.len() > 0 {
|
||||||
let count = std::cmp::min(buf.len(), self.0.len());
|
let count = std::cmp::min(buf.len(), self.0.len());
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
|
|
||||||
use futures::future::{ready, FutureExt, BoxFuture};
|
use futures_core::future::BoxFuture;
|
||||||
use futures::io::AsyncReadExt;
|
use futures_util::future::{ready, FutureExt};
|
||||||
|
use tokio_io::AsyncReadExt;
|
||||||
|
|
||||||
use crate::outcome::{self, IntoOutcome};
|
use crate::outcome::{self, IntoOutcome};
|
||||||
use crate::outcome::Outcome::*;
|
use crate::outcome::Outcome::*;
|
||||||
|
@ -193,14 +194,12 @@ pub type FromDataFuture<'a, T, E> = BoxFuture<'a, Outcome<T, E>>;
|
||||||
/// # struct Name<'a> { first: &'a str, last: &'a str, }
|
/// # struct Name<'a> { first: &'a str, last: &'a str, }
|
||||||
/// use std::io::{self, Read};
|
/// use std::io::{self, Read};
|
||||||
///
|
///
|
||||||
/// use futures::io::AsyncReadExt;
|
/// use tokio::io::AsyncReadExt;
|
||||||
///
|
///
|
||||||
/// use rocket::{Request, Data, Outcome::*};
|
/// use rocket::{Request, Data, Outcome::*};
|
||||||
/// use rocket::data::{FromData, Outcome, Transform, Transformed, TransformFuture, FromDataFuture};
|
/// use rocket::data::{FromData, Outcome, Transform, Transformed, TransformFuture, FromDataFuture};
|
||||||
/// use rocket::http::Status;
|
/// use rocket::http::Status;
|
||||||
///
|
///
|
||||||
/// use rocket::AsyncReadExt as _;
|
|
||||||
///
|
|
||||||
/// const NAME_LIMIT: u64 = 256;
|
/// const NAME_LIMIT: u64 = 256;
|
||||||
///
|
///
|
||||||
/// enum NameError {
|
/// enum NameError {
|
||||||
|
@ -462,14 +461,12 @@ impl<'a> FromData<'a> for Data {
|
||||||
/// #
|
/// #
|
||||||
/// use std::io::Read;
|
/// use std::io::Read;
|
||||||
///
|
///
|
||||||
/// use futures::io::AsyncReadExt;
|
/// use tokio::io::AsyncReadExt;
|
||||||
///
|
///
|
||||||
/// use rocket::{Request, Data, Outcome, Outcome::*};
|
/// use rocket::{Request, Data, Outcome, Outcome::*};
|
||||||
/// use rocket::data::{self, FromDataSimple, FromDataFuture};
|
/// use rocket::data::{self, FromDataSimple, FromDataFuture};
|
||||||
/// use rocket::http::{Status, ContentType};
|
/// use rocket::http::{Status, ContentType};
|
||||||
///
|
///
|
||||||
/// use rocket::AsyncReadExt as _;
|
|
||||||
///
|
|
||||||
/// // Always use a limit to prevent DoS attacks.
|
/// // Always use a limit to prevent DoS attacks.
|
||||||
/// const LIMIT: u64 = 256;
|
/// const LIMIT: u64 = 256;
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,37 +1,12 @@
|
||||||
use std::io;
|
use std::io::{self, Cursor};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
use std::task::{Poll, Context};
|
||||||
|
|
||||||
use futures::io::{AsyncRead, AsyncReadExt as _};
|
use futures_core::{ready, future::BoxFuture, stream::Stream};
|
||||||
use futures::future::BoxFuture;
|
use tokio_io::{AsyncRead, AsyncReadExt as _};
|
||||||
use futures::stream::Stream;
|
|
||||||
use futures::task::{Poll, Context};
|
|
||||||
|
|
||||||
use crate::http::hyper::Chunk;
|
use crate::http::hyper;
|
||||||
|
use hyper::{Chunk, Payload};
|
||||||
// Based on std::io::Take, but for AsyncRead instead of Read
|
|
||||||
pub struct Take<R>{
|
|
||||||
inner: R,
|
|
||||||
limit: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO.async: Verify correctness of this implementation.
|
|
||||||
impl<R> AsyncRead for Take<R> where R: AsyncRead + Unpin {
|
|
||||||
fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<Result<usize, io::Error>> {
|
|
||||||
if self.limit == 0 {
|
|
||||||
return Poll::Ready(Ok(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
let max = std::cmp::min(buf.len() as u64, self.limit) as usize;
|
|
||||||
match Pin::new(&mut self.inner).poll_read(cx, &mut buf[..max]) {
|
|
||||||
Poll::Pending => Poll::Pending,
|
|
||||||
Poll::Ready(Ok(n)) => {
|
|
||||||
self.limit -= n as u64;
|
|
||||||
Poll::Ready(Ok(n))
|
|
||||||
},
|
|
||||||
Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct IntoChunkStream<R> {
|
pub struct IntoChunkStream<R> {
|
||||||
inner: R,
|
inner: R,
|
||||||
|
@ -64,10 +39,6 @@ impl<R> Stream for IntoChunkStream<R>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait AsyncReadExt: AsyncRead {
|
pub trait AsyncReadExt: AsyncRead {
|
||||||
fn take(self, limit: u64) -> Take<Self> where Self: Sized {
|
|
||||||
Take { inner: self, limit }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_chunk_stream(self, buf_size: usize) -> IntoChunkStream<Self> where Self: Sized {
|
fn into_chunk_stream(self, buf_size: usize) -> IntoChunkStream<Self> where Self: Sized {
|
||||||
IntoChunkStream { inner: self, buf_size, buffer: vec![0; buf_size] }
|
IntoChunkStream { inner: self, buf_size, buffer: vec![0; buf_size] }
|
||||||
}
|
}
|
||||||
|
@ -93,3 +64,46 @@ pub trait AsyncReadExt: AsyncRead {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: AsyncRead> AsyncReadExt for T { }
|
impl<T: AsyncRead> AsyncReadExt for T { }
|
||||||
|
|
||||||
|
pub struct AsyncReadBody {
|
||||||
|
inner: hyper::Body,
|
||||||
|
state: AsyncReadBodyState,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AsyncReadBodyState {
|
||||||
|
Pending,
|
||||||
|
Partial(Cursor<Chunk>),
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<hyper::Body> for AsyncReadBody {
|
||||||
|
fn from(body: hyper::Body) -> Self {
|
||||||
|
Self { inner: body, state: AsyncReadBodyState::Pending }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsyncRead for AsyncReadBody {
|
||||||
|
fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
|
||||||
|
loop {
|
||||||
|
match self.state {
|
||||||
|
AsyncReadBodyState::Pending => {
|
||||||
|
match ready!(Pin::new(&mut self.inner).poll_data(cx)) {
|
||||||
|
Some(Ok(chunk)) => self.state = AsyncReadBodyState::Partial(Cursor::new(chunk)),
|
||||||
|
Some(Err(e)) => return Poll::Ready(Err(io::Error::new(io::ErrorKind::Other, e))),
|
||||||
|
None => self.state = AsyncReadBodyState::Done,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
AsyncReadBodyState::Partial(ref mut cursor) => {
|
||||||
|
match ready!(Pin::new(cursor).poll_read(cx, buf)) {
|
||||||
|
Ok(n) if n == 0 => {
|
||||||
|
self.state = AsyncReadBodyState::Pending;
|
||||||
|
}
|
||||||
|
Ok(n) => return Poll::Ready(Ok(n)),
|
||||||
|
Err(e) => return Poll::Ready(Err(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AsyncReadBodyState::Done => return Poll::Ready(Ok(0)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use futures::future::BoxFuture;
|
use futures_core::future::BoxFuture;
|
||||||
|
|
||||||
use crate::{Rocket, Request, Response, Data};
|
use crate::{Rocket, Request, Response, Data};
|
||||||
use crate::fairing::{Fairing, Kind, Info};
|
use crate::fairing::{Fairing, Kind, Info};
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
//! of other `Fairings` are not jeopardized. For instance, unless it is made
|
//! of other `Fairings` are not jeopardized. For instance, unless it is made
|
||||||
//! abundantly clear, a fairing should not rewrite every request.
|
//! abundantly clear, a fairing should not rewrite every request.
|
||||||
|
|
||||||
use futures::future::BoxFuture;
|
use futures_core::future::BoxFuture;
|
||||||
|
|
||||||
use crate::{Rocket, Request, Response, Data};
|
use crate::{Rocket, Request, Response, Data};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Types and traits for request and error handlers and their return values.
|
//! Types and traits for request and error handlers and their return values.
|
||||||
|
|
||||||
use futures::future::BoxFuture;
|
use futures_core::future::BoxFuture;
|
||||||
|
|
||||||
use crate::data::Data;
|
use crate::data::Data;
|
||||||
use crate::request::Request;
|
use crate::request::Request;
|
||||||
|
|
|
@ -137,7 +137,6 @@ pub use crate::router::Route;
|
||||||
pub use crate::request::{Request, State};
|
pub use crate::request::{Request, State};
|
||||||
pub use crate::catcher::Catcher;
|
pub use crate::catcher::Catcher;
|
||||||
pub use crate::rocket::Rocket;
|
pub use crate::rocket::Rocket;
|
||||||
pub use ext::AsyncReadExt;
|
|
||||||
|
|
||||||
/// Alias to [`Rocket::ignite()`] Creates a new instance of `Rocket`.
|
/// Alias to [`Rocket::ignite()`] Creates a new instance of `Rocket`.
|
||||||
pub fn ignite() -> Rocket {
|
pub fn ignite() -> Rocket {
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use futures::io::AsyncReadExt;
|
use tokio_io::AsyncReadExt;
|
||||||
|
|
||||||
use crate::outcome::Outcome::*;
|
use crate::outcome::Outcome::*;
|
||||||
use crate::request::{Request, form::{FromForm, FormItems, FormDataError}};
|
use crate::request::{Request, form::{FromForm, FormItems, FormDataError}};
|
||||||
use crate::data::{Outcome, Transform, Transformed, Data, FromData, TransformFuture, FromDataFuture};
|
use crate::data::{Outcome, Transform, Transformed, Data, FromData, TransformFuture, FromDataFuture};
|
||||||
use crate::http::{Status, uri::{Query, FromUriParam}};
|
use crate::http::{Status, uri::{Query, FromUriParam}};
|
||||||
use crate::ext::AsyncReadExt as _;
|
|
||||||
|
|
||||||
/// A data guard for parsing [`FromForm`] types strictly.
|
/// A data guard for parsing [`FromForm`] types strictly.
|
||||||
///
|
///
|
||||||
|
@ -200,7 +199,7 @@ impl<'f, T: FromForm<'f> + Send + 'f> FromData<'f> for Form<T> {
|
||||||
|
|
||||||
if !request.content_type().map_or(false, |ct| ct.is_form()) {
|
if !request.content_type().map_or(false, |ct| ct.is_form()) {
|
||||||
warn_!("Form data does not have form content type.");
|
warn_!("Form data does not have form content type.");
|
||||||
return Box::pin(futures::future::ready(Transform::Borrowed(Forward(data))));
|
return Box::pin(futures_util::future::ready(Transform::Borrowed(Forward(data))));
|
||||||
}
|
}
|
||||||
|
|
||||||
let limit = request.limits().forms;
|
let limit = request.limits().forms;
|
||||||
|
@ -216,7 +215,7 @@ impl<'f, T: FromForm<'f> + Send + 'f> FromData<'f> for Form<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_data(_: &Request<'_>, o: Transformed<'f, Self>) -> FromDataFuture<'f, Self, Self::Error> {
|
fn from_data(_: &Request<'_>, o: Transformed<'f, Self>) -> FromDataFuture<'f, Self, Self::Error> {
|
||||||
Box::pin(futures::future::ready(o.borrowed().and_then(|data| {
|
Box::pin(futures_util::future::ready(o.borrowed().and_then(|data| {
|
||||||
<Form<T>>::from_data(data, true).map(Form)
|
<Form<T>>::from_data(data, true).map(Form)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,7 +105,7 @@ impl<'f, T: FromForm<'f> + Send + 'f> FromData<'f> for LenientForm<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_data(_: &Request<'_>, o: Transformed<'f, Self>) -> FromDataFuture<'f, Self, Self::Error> {
|
fn from_data(_: &Request<'_>, o: Transformed<'f, Self>) -> FromDataFuture<'f, Self, Self::Error> {
|
||||||
Box::pin(futures::future::ready(o.borrowed().and_then(|form| {
|
Box::pin(futures_util::future::ready(o.borrowed().and_then(|form| {
|
||||||
<Form<T>>::from_data(form, false).map(LenientForm)
|
<Form<T>>::from_data(form, false).map(LenientForm)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,14 +20,12 @@ use yansi::Paint;
|
||||||
/// # #![feature(proc_macro_hygiene)]
|
/// # #![feature(proc_macro_hygiene)]
|
||||||
/// use std::io;
|
/// use std::io;
|
||||||
///
|
///
|
||||||
/// use futures::io::AsyncReadExt;
|
/// use tokio::io::AsyncReadExt;
|
||||||
///
|
///
|
||||||
/// # use rocket::post;
|
/// # use rocket::post;
|
||||||
/// use rocket::Data;
|
/// use rocket::Data;
|
||||||
/// use rocket::response::Debug;
|
/// use rocket::response::Debug;
|
||||||
///
|
///
|
||||||
/// use rocket::AsyncReadExt as _;
|
|
||||||
///
|
|
||||||
/// #[post("/", format = "plain", data = "<data>")]
|
/// #[post("/", format = "plain", data = "<data>")]
|
||||||
/// async fn post(data: Data) -> Result<String, Debug<io::Error>> {
|
/// async fn post(data: Data) -> Result<String, Debug<io::Error>> {
|
||||||
/// let mut name = String::with_capacity(32);
|
/// let mut name = String::with_capacity(32);
|
||||||
|
|
|
@ -49,4 +49,4 @@ pub use self::debug::Debug;
|
||||||
/// Type alias for the `Result` of a `Responder::respond` call.
|
/// Type alias for the `Result` of a `Responder::respond` call.
|
||||||
pub type Result<'r> = std::result::Result<self::Response<'r>, crate::http::Status>;
|
pub type Result<'r> = std::result::Result<self::Response<'r>, crate::http::Status>;
|
||||||
/// Type alias for the `Result` of a `Responder::respond` call.
|
/// Type alias for the `Result` of a `Responder::respond` call.
|
||||||
pub type ResultFuture<'r> = futures::future::BoxFuture<'r, Result<'r>>;
|
pub type ResultFuture<'r> = futures_core::future::BoxFuture<'r, Result<'r>>;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
use futures::io::BufReader;
|
use futures_util::future::ready;
|
||||||
use futures::future;
|
use tokio_io::BufReader;
|
||||||
|
|
||||||
use crate::http::{Status, ContentType, StatusClass};
|
use crate::http::{Status, ContentType, StatusClass};
|
||||||
use crate::response::{self, Response, Body};
|
use crate::response::{self, Response, Body};
|
||||||
|
@ -255,7 +255,7 @@ impl Responder<'_> for Vec<u8> {
|
||||||
impl Responder<'_> for File {
|
impl Responder<'_> for File {
|
||||||
fn respond_to(self, _: &Request<'_>) -> response::ResultFuture<'static> {
|
fn respond_to(self, _: &Request<'_>) -> response::ResultFuture<'static> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let file = async_std::fs::File::from(self);
|
let file = tokio::fs::File::from(self);
|
||||||
let metadata = file.metadata().await;
|
let metadata = file.metadata().await;
|
||||||
let stream = BufReader::new(file);
|
let stream = BufReader::new(file);
|
||||||
match metadata {
|
match metadata {
|
||||||
|
@ -283,7 +283,7 @@ impl<'r, R: Responder<'r> + Send + 'r> Responder<'r> for Option<R> {
|
||||||
Some(r) => r.respond_to(req),
|
Some(r) => r.respond_to(req),
|
||||||
None => {
|
None => {
|
||||||
warn_!("Response was `None`.");
|
warn_!("Response was `None`.");
|
||||||
Box::pin(future::err(Status::NotFound))
|
Box::pin(ready(Err(Status::NotFound)))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
use std::{io, fmt, str};
|
use std::{io, fmt, str};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::future::Future;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
use futures::future::{Future, FutureExt};
|
use tokio_io::{AsyncRead, AsyncReadExt};
|
||||||
use futures::io::{AsyncRead, AsyncReadExt};
|
use futures_util::future::FutureExt;
|
||||||
|
|
||||||
use crate::response::{Responder, ResultFuture};
|
use crate::response::{Responder, ResultFuture};
|
||||||
use crate::http::{Header, HeaderMap, Status, ContentType, Cookie};
|
use crate::http::{Header, HeaderMap, Status, ContentType, Cookie};
|
||||||
use crate::ext::AsyncReadExt as _;
|
|
||||||
|
|
||||||
/// The default size, in bytes, of a chunk for streamed responses.
|
/// The default size, in bytes, of a chunk for streamed responses.
|
||||||
pub const DEFAULT_CHUNK_SIZE: u64 = 4096;
|
pub const DEFAULT_CHUNK_SIZE: u64 = 4096;
|
||||||
|
@ -346,7 +346,7 @@ impl<'r> ResponseBuilder<'r> {
|
||||||
///
|
///
|
||||||
/// ```rust,ignore
|
/// ```rust,ignore
|
||||||
/// use rocket::Response;
|
/// use rocket::Response;
|
||||||
/// use async_std::fs::File;
|
/// use tokio::fs::File;
|
||||||
/// # use std::io;
|
/// # use std::io;
|
||||||
///
|
///
|
||||||
/// # #[allow(dead_code)]
|
/// # #[allow(dead_code)]
|
||||||
|
@ -372,7 +372,7 @@ impl<'r> ResponseBuilder<'r> {
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use rocket::Response;
|
/// use rocket::Response;
|
||||||
/// use async_std::fs::File;
|
/// use tokio::fs::File;
|
||||||
/// # use std::io;
|
/// # use std::io;
|
||||||
///
|
///
|
||||||
/// # #[allow(dead_code)]
|
/// # #[allow(dead_code)]
|
||||||
|
@ -399,7 +399,7 @@ impl<'r> ResponseBuilder<'r> {
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use rocket::Response;
|
/// use rocket::Response;
|
||||||
/// use async_std::fs::File;
|
/// use tokio::fs::File;
|
||||||
/// # use std::io;
|
/// # use std::io;
|
||||||
///
|
///
|
||||||
/// # #[allow(dead_code)]
|
/// # #[allow(dead_code)]
|
||||||
|
@ -1010,7 +1010,7 @@ impl<'r> Response<'r> {
|
||||||
pub(crate) fn strip_body(&mut self) {
|
pub(crate) fn strip_body(&mut self) {
|
||||||
if let Some(body) = self.take_body() {
|
if let Some(body) = self.take_body() {
|
||||||
self.body = match body {
|
self.body = match body {
|
||||||
Body::Sized(_, n) => Some(Body::Sized(Box::pin(io::empty()), n)),
|
Body::Sized(_, n) => Some(Body::Sized(Box::pin(io::Cursor::new(&[])), n)),
|
||||||
Body::Chunked(..) => None
|
Body::Chunked(..) => None
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1057,14 +1057,14 @@ impl<'r> Response<'r> {
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use std::io::repeat;
|
/// use futures::io::repeat;
|
||||||
/// use futures::io::AsyncReadExt;
|
/// use futures_tokio_compat::Compat;
|
||||||
|
/// use tokio::io::AsyncReadExt;
|
||||||
/// use rocket::Response;
|
/// use rocket::Response;
|
||||||
/// use rocket::AsyncReadExt as _;
|
|
||||||
///
|
///
|
||||||
/// # rocket::async_test(async {
|
/// # rocket::async_test(async {
|
||||||
/// let mut response = Response::new();
|
/// let mut response = Response::new();
|
||||||
/// response.set_streamed_body(repeat(97).take(5));
|
/// response.set_streamed_body(Compat::new(repeat(97)).take(5));
|
||||||
/// assert_eq!(response.body_string().await, Some("aaaaa".to_string()));
|
/// assert_eq!(response.body_string().await, Some("aaaaa".to_string()));
|
||||||
/// # })
|
/// # })
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -1079,14 +1079,14 @@ impl<'r> Response<'r> {
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use std::io::repeat;
|
/// use futures::io::repeat;
|
||||||
/// use futures::io::AsyncReadExt;
|
/// use futures_tokio_compat::Compat;
|
||||||
|
/// use tokio::io::AsyncReadExt;
|
||||||
/// use rocket::Response;
|
/// use rocket::Response;
|
||||||
/// use rocket::AsyncReadExt as _;
|
|
||||||
///
|
///
|
||||||
/// # rocket::async_test(async {
|
/// # rocket::async_test(async {
|
||||||
/// let mut response = Response::new();
|
/// let mut response = Response::new();
|
||||||
/// response.set_chunked_body(repeat(97).take(5), 10);
|
/// response.set_chunked_body(Compat::new(repeat(97)).take(5), 10);
|
||||||
/// assert_eq!(response.body_string().await, Some("aaaaa".to_string()));
|
/// assert_eq!(response.body_string().await, Some("aaaaa".to_string()));
|
||||||
/// # })
|
/// # })
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::fmt::{self, Debug};
|
use std::fmt::{self, Debug};
|
||||||
|
|
||||||
use futures::io::AsyncRead;
|
use tokio_io::AsyncRead;
|
||||||
|
|
||||||
use crate::request::Request;
|
use crate::request::Request;
|
||||||
use crate::response::{Response, Responder, ResultFuture, DEFAULT_CHUNK_SIZE};
|
use crate::response::{Response, Responder, ResultFuture, DEFAULT_CHUNK_SIZE};
|
||||||
|
@ -23,12 +23,10 @@ impl<T: AsyncRead> Stream<T> {
|
||||||
/// bytes. Note: you probably shouldn't do this.
|
/// bytes. Note: you probably shouldn't do this.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use std::io;
|
|
||||||
/// use futures::io::AllowStdIo;
|
|
||||||
/// use rocket::response::Stream;
|
/// use rocket::response::Stream;
|
||||||
///
|
///
|
||||||
/// # #[allow(unused_variables)]
|
/// # #[allow(unused_variables)]
|
||||||
/// let response = Stream::chunked(AllowStdIo::new(io::stdin()), 10);
|
/// let response = Stream::chunked(tokio::io::stdin(), 10);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn chunked(reader: T, chunk_size: u64) -> Stream<T> {
|
pub fn chunked(reader: T, chunk_size: u64) -> Stream<T> {
|
||||||
Stream(reader, chunk_size)
|
Stream(reader, chunk_size)
|
||||||
|
@ -49,12 +47,10 @@ impl<T: AsyncRead + Debug> Debug for Stream<T> {
|
||||||
/// shouldn't do this.
|
/// shouldn't do this.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use std::io;
|
|
||||||
/// use futures::io::AllowStdIo;
|
|
||||||
/// use rocket::response::Stream;
|
/// use rocket::response::Stream;
|
||||||
///
|
///
|
||||||
/// # #[allow(unused_variables)]
|
/// # #[allow(unused_variables)]
|
||||||
/// let response = Stream::from(AllowStdIo::new(io::stdin()));
|
/// let response = Stream::from(tokio::io::stdin());
|
||||||
/// ```
|
/// ```
|
||||||
impl<T: AsyncRead> From<T> for Stream<T> {
|
impl<T: AsyncRead> From<T> for Stream<T> {
|
||||||
fn from(reader: T) -> Self {
|
fn from(reader: T) -> Self {
|
||||||
|
|
|
@ -5,11 +5,9 @@ use std::io;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use futures::future::{Future, FutureExt, BoxFuture};
|
use futures_core::future::{Future, BoxFuture};
|
||||||
use futures::channel::{mpsc, oneshot};
|
use futures_channel::{mpsc, oneshot};
|
||||||
use futures::stream::StreamExt;
|
use futures_util::{future::FutureExt, stream::StreamExt};
|
||||||
use futures::task::{Spawn, SpawnExt};
|
|
||||||
use futures_tokio_compat::Compat as TokioCompat;
|
|
||||||
|
|
||||||
use yansi::Paint;
|
use yansi::Paint;
|
||||||
use state::Container;
|
use state::Container;
|
||||||
|
@ -54,7 +52,6 @@ pub struct Rocket {
|
||||||
fn hyper_service_fn(
|
fn hyper_service_fn(
|
||||||
rocket: Arc<Rocket>,
|
rocket: Arc<Rocket>,
|
||||||
h_addr: std::net::SocketAddr,
|
h_addr: std::net::SocketAddr,
|
||||||
mut spawn: impl futures::task::Spawn,
|
|
||||||
hyp_req: hyper::Request<hyper::Body>,
|
hyp_req: hyper::Request<hyper::Body>,
|
||||||
) -> impl Future<Output = Result<hyper::Response<hyper::Body>, io::Error>> {
|
) -> impl Future<Output = Result<hyper::Response<hyper::Body>, io::Error>> {
|
||||||
// This future must return a hyper::Response, but that's not easy
|
// This future must return a hyper::Response, but that's not easy
|
||||||
|
@ -63,7 +60,7 @@ fn hyper_service_fn(
|
||||||
// the response metadata (and a body channel) beforehand.
|
// the response metadata (and a body channel) beforehand.
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
|
|
||||||
spawn.spawn(async move {
|
tokio::spawn(async move {
|
||||||
// Get all of the information from Hyper.
|
// Get all of the information from Hyper.
|
||||||
let (h_parts, h_body) = hyp_req.into_parts();
|
let (h_parts, h_body) = hyp_req.into_parts();
|
||||||
|
|
||||||
|
@ -89,7 +86,7 @@ fn hyper_service_fn(
|
||||||
// Dispatch the request to get a response, then write that response out.
|
// Dispatch the request to get a response, then write that response out.
|
||||||
let r = rocket.dispatch(&mut req, data).await;
|
let r = rocket.dispatch(&mut req, data).await;
|
||||||
rocket.issue_response(r, tx).await;
|
rocket.issue_response(r, tx).await;
|
||||||
}).expect("failed to spawn handler");
|
});
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
rx.await.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
|
rx.await.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
|
||||||
|
@ -708,11 +705,10 @@ impl Rocket {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO.async: Solidify the Listener APIs and make this function public
|
// TODO.async: Solidify the Listener APIs and make this function public
|
||||||
async fn listen_on<L, S>(mut self, listener: L, spawn: S) -> Result<(), crate::error::Error>
|
async fn listen_on<L>(mut self, listener: L) -> Result<(), crate::error::Error>
|
||||||
where
|
where
|
||||||
L: Listener + Send + Unpin + 'static,
|
L: Listener + Send + Unpin + 'static,
|
||||||
<L as Listener>::Connection: Send + Unpin + 'static,
|
<L as Listener>::Connection: Send + Unpin + 'static,
|
||||||
S: Spawn + Clone + Send + 'static,
|
|
||||||
{
|
{
|
||||||
self = self.prelaunch_check().map_err(crate::error::Error::Launch)?;
|
self = self.prelaunch_check().map_err(crate::error::Error::Launch)?;
|
||||||
|
|
||||||
|
@ -754,21 +750,19 @@ impl Rocket {
|
||||||
.take().expect("shutdown receiver has already been used");
|
.take().expect("shutdown receiver has already been used");
|
||||||
|
|
||||||
let rocket = Arc::new(self);
|
let rocket = Arc::new(self);
|
||||||
let spawn_makeservice = spawn.clone();
|
|
||||||
let service = hyper::make_service_fn(move |connection: &<L as Listener>::Connection| {
|
let service = hyper::make_service_fn(move |connection: &<L as Listener>::Connection| {
|
||||||
let rocket = rocket.clone();
|
let rocket = rocket.clone();
|
||||||
let remote_addr = connection.remote_addr().unwrap_or_else(|| "0.0.0.0".parse().unwrap());
|
let remote_addr = connection.remote_addr().unwrap_or_else(|| "0.0.0.0".parse().unwrap());
|
||||||
let spawn_service = spawn_makeservice.clone();
|
|
||||||
async move {
|
async move {
|
||||||
Ok::<_, std::convert::Infallible>(hyper::service_fn(move |req| {
|
Ok::<_, std::convert::Infallible>(hyper::service_fn(move |req| {
|
||||||
hyper_service_fn(rocket.clone(), remote_addr, spawn_service.clone(), req)
|
hyper_service_fn(rocket.clone(), remote_addr, req)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// NB: executor must be passed manually here, see hyperium/hyper#1537
|
// NB: executor must be passed manually here, see hyperium/hyper#1537
|
||||||
hyper::Server::builder(Incoming::from_listener(listener))
|
hyper::Server::builder(Incoming::from_listener(listener))
|
||||||
.executor(TokioCompat::new(spawn))
|
.executor(tokio::executor::DefaultExecutor::current())
|
||||||
.serve(service)
|
.serve(service)
|
||||||
.with_graceful_shutdown(async move { shutdown_receiver.next().await; })
|
.with_graceful_shutdown(async move { shutdown_receiver.next().await; })
|
||||||
.await
|
.await
|
||||||
|
@ -808,10 +802,9 @@ impl Rocket {
|
||||||
let full_addr = format!("{}:{}", self.config.address, self.config.port);
|
let full_addr = format!("{}:{}", self.config.address, self.config.port);
|
||||||
let addrs = match full_addr.to_socket_addrs() {
|
let addrs = match full_addr.to_socket_addrs() {
|
||||||
Ok(a) => a.collect::<Vec<_>>(),
|
Ok(a) => a.collect::<Vec<_>>(),
|
||||||
Err(e) => return futures::future::err(Launch(From::from(e))).boxed(),
|
Err(e) => return futures_util::future::ready(Err(Launch(From::from(e)))).boxed(),
|
||||||
};
|
};
|
||||||
let addr = addrs[0];
|
let addr = addrs[0];
|
||||||
let spawn = TokioCompat::new(runtime.executor());
|
|
||||||
|
|
||||||
#[cfg(feature = "ctrl_c_shutdown")]
|
#[cfg(feature = "ctrl_c_shutdown")]
|
||||||
let (
|
let (
|
||||||
|
@ -824,26 +817,26 @@ impl Rocket {
|
||||||
|
|
||||||
let server = async move {
|
let server = async move {
|
||||||
macro_rules! listen_on {
|
macro_rules! listen_on {
|
||||||
($spawn:expr, $expr:expr) => {{
|
($expr:expr) => {{
|
||||||
let listener = match $expr {
|
let listener = match $expr {
|
||||||
Ok(ok) => ok,
|
Ok(ok) => ok,
|
||||||
Err(err) => return Err(Launch(LaunchError::new(LaunchErrorKind::Bind(err)))),
|
Err(err) => return Err(Launch(LaunchError::new(LaunchErrorKind::Bind(err)))),
|
||||||
};
|
};
|
||||||
self.listen_on(listener, spawn).await
|
self.listen_on(listener).await
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "tls")]
|
||||||
{
|
{
|
||||||
if let Some(tls) = self.config.tls.clone() {
|
if let Some(tls) = self.config.tls.clone() {
|
||||||
listen_on!(spawn, crate::http::tls::bind_tls(addr, tls.certs, tls.key).await)
|
listen_on!(crate::http::tls::bind_tls(addr, tls.certs, tls.key).await)
|
||||||
} else {
|
} else {
|
||||||
listen_on!(spawn, crate::http::private::bind_tcp(addr).await)
|
listen_on!(crate::http::private::bind_tcp(addr).await)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "tls"))]
|
#[cfg(not(feature = "tls"))]
|
||||||
{
|
{
|
||||||
listen_on!(spawn, crate::http::private::bind_tcp(addr).await)
|
listen_on!(crate::http::private::bind_tcp(addr).await)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -858,7 +851,7 @@ impl Rocket {
|
||||||
runtime.spawn(async move {
|
runtime.spawn(async move {
|
||||||
// Stop listening for `ctrl_c` if the server shuts down
|
// Stop listening for `ctrl_c` if the server shuts down
|
||||||
// a different way to avoid waiting forever.
|
// a different way to avoid waiting forever.
|
||||||
futures::future::select(
|
futures_util::future::select(
|
||||||
ctrl_c.next(),
|
ctrl_c.next(),
|
||||||
cancel_ctrl_c_listener_receiver,
|
cancel_ctrl_c_listener_receiver,
|
||||||
).await;
|
).await;
|
||||||
|
|
|
@ -3,7 +3,7 @@ mod route;
|
||||||
|
|
||||||
use std::collections::hash_map::HashMap;
|
use std::collections::hash_map::HashMap;
|
||||||
|
|
||||||
use futures::future::BoxFuture;
|
use futures_core::future::BoxFuture;
|
||||||
|
|
||||||
pub use self::route::Route;
|
pub use self::route::Route;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::request::{FromRequest, Outcome, Request};
|
use crate::request::{FromRequest, Outcome, Request};
|
||||||
use futures::channel::mpsc;
|
use futures_channel::mpsc;
|
||||||
|
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
|
|
|
@ -22,7 +22,7 @@ fn other() -> content::Json<&'static str> {
|
||||||
mod head_handling_tests {
|
mod head_handling_tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use futures::io::AsyncReadExt;
|
use tokio_io::{AsyncRead, AsyncReadExt};
|
||||||
|
|
||||||
use rocket::Route;
|
use rocket::Route;
|
||||||
use rocket::local::Client;
|
use rocket::local::Client;
|
||||||
|
@ -33,7 +33,7 @@ mod head_handling_tests {
|
||||||
routes![index, empty, other]
|
routes![index, empty, other]
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn assert_empty_sized_body<T: futures::AsyncRead + Unpin>(body: Body<T>, expected_size: u64) {
|
async fn assert_empty_sized_body<T: AsyncRead + Unpin>(body: Body<T>, expected_size: u64) {
|
||||||
match body {
|
match body {
|
||||||
Body::Sized(mut body, size) => {
|
Body::Sized(mut body, size) => {
|
||||||
let mut buffer = vec![];
|
let mut buffer = vec![];
|
||||||
|
|
|
@ -26,7 +26,7 @@ impl FromDataSimple for HasContentType {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn from_data(request: &Request<'_>, data: Data) -> data::FromDataFuture<'static, Self, Self::Error> {
|
fn from_data(request: &Request<'_>, data: Data) -> data::FromDataFuture<'static, Self, Self::Error> {
|
||||||
Box::pin(futures::future::ready(if request.content_type().is_some() {
|
Box::pin(futures_util::future::ready(if request.content_type().is_some() {
|
||||||
Success(HasContentType)
|
Success(HasContentType)
|
||||||
} else {
|
} else {
|
||||||
Forward(data)
|
Forward(data)
|
||||||
|
|
|
@ -6,7 +6,7 @@ edition = "2018"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures-preview = "0.3.0-alpha.18"
|
tokio = "0.2.0-alpha.6"
|
||||||
rocket = { path = "../../core/lib" }
|
rocket = { path = "../../core/lib" }
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|
|
@ -7,11 +7,10 @@
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use futures::io::AsyncReadExt as _;
|
use tokio::io::AsyncReadExt;
|
||||||
|
|
||||||
use rocket::{Request, data::Data};
|
use rocket::{Request, data::Data};
|
||||||
use rocket::response::{Debug, content::{Json, Html}};
|
use rocket::response::{Debug, content::{Json, Html}};
|
||||||
use rocket::AsyncReadExt as _;
|
|
||||||
|
|
||||||
// NOTE: This example explicitly uses the `Json` type from `response::content`
|
// NOTE: This example explicitly uses the `Json` type from `response::content`
|
||||||
// for demonstration purposes. In a real application, _always_ prefer to use
|
// for demonstration purposes. In a real application, _always_ prefer to use
|
||||||
|
|
|
@ -7,4 +7,4 @@ publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rocket = { path = "../../core/lib" }
|
rocket = { path = "../../core/lib" }
|
||||||
async-std = "0.99.4"
|
tokio = "=0.2.0-alpha.6"
|
||||||
|
|
|
@ -4,7 +4,8 @@ extern crate rocket;
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use async_std::fs::File;
|
|
||||||
|
use tokio::fs::File;
|
||||||
|
|
||||||
use rocket::{Request, Handler, Route, Data, Catcher, try_outcome};
|
use rocket::{Request, Handler, Route, Data, Catcher, try_outcome};
|
||||||
use rocket::http::{Status, RawStr};
|
use rocket::http::{Status, RawStr};
|
||||||
|
|
|
@ -7,5 +7,6 @@ publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rocket = { path = "../../core/lib" }
|
rocket = { path = "../../core/lib" }
|
||||||
futures-preview = "0.3.0-alpha.18"
|
tokio = "0.2.0-alpha.6"
|
||||||
async-std = "0.99.4"
|
futures-preview = "0.3.0-alpha.19"
|
||||||
|
futures-tokio-compat = { git = "https://github.com/Nemo157/futures-tokio-compat", rev = "8a93702" }
|
||||||
|
|
|
@ -6,20 +6,17 @@
|
||||||
|
|
||||||
use rocket::response::{content, Stream};
|
use rocket::response::{content, Stream};
|
||||||
|
|
||||||
use std::io::repeat;
|
use futures::io::repeat;
|
||||||
use async_std::fs::File;
|
use futures_tokio_compat::Compat;
|
||||||
|
use tokio::fs::File;
|
||||||
use rocket::AsyncReadExt as _;
|
use tokio::io::{AsyncRead, AsyncReadExt};
|
||||||
|
|
||||||
//type LimitedRepeat = Take<Repeat>;
|
|
||||||
type LimitedRepeat = Box<dyn futures::io::AsyncRead + Send + Unpin>;
|
|
||||||
|
|
||||||
// Generate this file using: head -c BYTES /dev/random > big_file.dat
|
// Generate this file using: head -c BYTES /dev/random > big_file.dat
|
||||||
const FILENAME: &str = "big_file.dat";
|
const FILENAME: &str = "big_file.dat";
|
||||||
|
|
||||||
#[get("/")]
|
#[get("/")]
|
||||||
fn root() -> content::Plain<Stream<LimitedRepeat>> {
|
fn root() -> content::Plain<Stream<impl AsyncRead>> {
|
||||||
content::Plain(Stream::from(Box::new(repeat('a' as u8).take(25000)) as Box<_>))
|
content::Plain(Stream::from(Compat::new(repeat('a' as u8)).take(25000)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/big_file")]
|
#[get("/big_file")]
|
||||||
|
|
Loading…
Reference in New Issue