Skip to content

Commit ffefea0

Browse files
aknuds1janpetschexainjxspaolobarboliniranile
authored
Upgrade to Tokio 1.0 (#753)
Co-authored-by: janpetschexain <[email protected]> Co-authored-by: João Oliveira <[email protected]> Co-authored-by: Paolo Barbolini <[email protected]> Co-authored-by: Muhammad Hamza <[email protected]> Co-authored-by: teenjuna <[email protected]>
1 parent f59de24 commit ffefea0

18 files changed

+100
-68
lines changed

.github/workflows/ci.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@ jobs:
4545
benches: true
4646
- build: tls
4747
features: "--features tls"
48-
- build: uds
49-
features: "--features tokio/uds"
5048
- build: no-default-features
5149
features: "--no-default-features"
5250
- build: compression

Cargo.toml

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ edition = "2018"
1717
all-features = true
1818

1919
[dependencies]
20-
async-compression = { version = "0.3.1", features = ["brotli", "deflate", "gzip", "stream"], optional = true }
21-
bytes = "0.5"
20+
async-compression = { version = "0.3.7", features = ["brotli", "deflate", "gzip", "tokio"], optional = true }
21+
bytes = "1.0"
2222
futures = { version = "0.3", default-features = false, features = ["alloc"] }
2323
headers = "0.3"
2424
http = "0.2"
25-
hyper = { version = "0.13", features = ["stream"] }
25+
hyper = { version = "0.14", features = ["stream", "server", "http1", "http2", "tcp", "client"] }
2626
log = "0.4"
2727
mime = "0.3"
2828
mime_guess = "2.0.0"
@@ -31,23 +31,26 @@ scoped-tls = "1.0"
3131
serde = "1.0"
3232
serde_json = "1.0"
3333
serde_urlencoded = "0.7"
34-
tokio = { version = "0.2", features = ["fs", "stream", "sync", "time"] }
34+
tokio = { version = "1.0", features = ["fs", "sync", "time"] }
35+
tokio-stream = "0.1.1"
36+
tokio-util = { version = "0.6", features = ["io"] }
3537
tracing = { version = "0.1", default-features = false, features = ["log", "std"] }
3638
tracing-futures = { version = "0.2", default-features = false, features = ["std-future"] }
3739
tower-service = "0.3"
3840
# tls is enabled by default, we don't want that yet
39-
tokio-tungstenite = { version = "0.11", default-features = false, optional = true }
41+
tokio-tungstenite = { version = "0.13", default-features = false, optional = true }
4042
percent-encoding = "2.1"
4143
pin-project = "1.0"
42-
tokio-rustls = { version = "0.14", optional = true }
44+
tokio-rustls = { version = "0.22", optional = true }
4345

4446
[dev-dependencies]
4547
pretty_env_logger = "0.4"
4648
tracing-subscriber = "0.2.7"
4749
tracing-log = "0.1"
4850
serde_derive = "1.0"
4951
handlebars = "3.0.0"
50-
tokio = { version = "0.2", features = ["macros"] }
52+
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
53+
tokio-stream = { version = "0.1.1", features = ["net"] }
5154
listenfd = "0.3"
5255

5356
[features]
@@ -78,7 +81,6 @@ required-features = ["compression"]
7881

7982
[[example]]
8083
name = "unix_socket"
81-
required-features = ["tokio/uds"]
8284

8385
[[example]]
8486
name = "websockets"

examples/futures.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ async fn main() {
1616
}
1717

1818
async fn sleepy(Seconds(seconds): Seconds) -> Result<impl warp::Reply, Infallible> {
19-
tokio::time::delay_for(Duration::from_secs(seconds)).await;
19+
tokio::time::sleep(Duration::from_secs(seconds)).await;
2020
Ok(format!("I waited {} seconds!", seconds))
2121
}
2222

examples/sse.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use futures::StreamExt;
22
use std::convert::Infallible;
33
use std::time::Duration;
44
use tokio::time::interval;
5+
use tokio_stream::wrappers::IntervalStream;
56
use warp::{sse::Event, Filter};
67

78
// create server-sent event
@@ -16,7 +17,9 @@ async fn main() {
1617
let routes = warp::path("ticks").and(warp::get()).map(|| {
1718
let mut counter: u64 = 0;
1819
// create server event source
19-
let event_stream = interval(Duration::from_secs(1)).map(move |_| {
20+
let interval = interval(Duration::from_secs(1));
21+
let stream = IntervalStream::new(interval);
22+
let event_stream = stream.map(move |_| {
2023
counter += 1;
2124
sse_counter(counter)
2225
});

examples/sse_chat.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::sync::{
55
Arc, Mutex,
66
};
77
use tokio::sync::mpsc;
8+
use tokio_stream::wrappers::UnboundedReceiverStream;
89
use warp::{sse::Event, Filter};
910

1011
#[tokio::main]
@@ -83,6 +84,7 @@ fn user_connected(users: Users) -> impl Stream<Item = Result<Event, warp::Error>
8384
// Use an unbounded channel to handle buffering and flushing of messages
8485
// to the event source...
8586
let (tx, rx) = mpsc::unbounded_channel();
87+
let rx = UnboundedReceiverStream::new(rx);
8688

8789
tx.send(Message::UserId(my_id))
8890
// rx is right above, so this cannot fail

examples/unix_socket.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
#![deny(warnings)]
22

33
use tokio::net::UnixListener;
4+
use tokio_stream::wrappers::UnixListenerStream;
45

56
#[tokio::main]
67
async fn main() {
78
pretty_env_logger::init();
89

9-
let mut listener = UnixListener::bind("/tmp/warp.sock").unwrap();
10-
let incoming = listener.incoming();
10+
let listener = UnixListener::bind("/tmp/warp.sock").unwrap();
11+
let incoming = UnixListenerStream::new(listener);
1112
warp::serve(warp::fs::dir("examples/dir"))
1213
.run_incoming(incoming)
1314
.await;

examples/websockets_chat.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use std::sync::{
77

88
use futures::{FutureExt, StreamExt};
99
use tokio::sync::{mpsc, RwLock};
10+
use tokio_stream::wrappers::UnboundedReceiverStream;
1011
use warp::ws::{Message, WebSocket};
1112
use warp::Filter;
1213

@@ -59,6 +60,7 @@ async fn user_connected(ws: WebSocket, users: Users) {
5960
// Use an unbounded channel to handle buffering and flushing of messages
6061
// to the websocket...
6162
let (tx, rx) = mpsc::unbounded_channel();
63+
let rx = UnboundedReceiverStream::new(rx);
6264
tokio::task::spawn(rx.forward(user_ws_tx).map(|result| {
6365
if let Err(e) = result {
6466
eprintln!("websocket send error: {}", e);

src/filters/body.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::fmt;
77
use std::pin::Pin;
88
use std::task::{Context, Poll};
99

10-
use bytes::{buf::BufExt, Buf, Bytes};
10+
use bytes::{Buf, Bytes};
1111
use futures::{future, ready, Stream, TryFutureExt};
1212
use headers::ContentLength;
1313
use http::header::CONTENT_TYPE;
@@ -131,8 +131,8 @@ pub fn bytes() -> impl Filter<Extract = (Bytes,), Error = Rejection> + Copy {
131131
/// fn full_body(mut body: impl Buf) {
132132
/// // It could have several non-contiguous slices of memory...
133133
/// while body.has_remaining() {
134-
/// println!("slice = {:?}", body.bytes());
135-
/// let cnt = body.bytes().len();
134+
/// println!("slice = {:?}", body.chunk());
135+
/// let cnt = body.chunk().len();
136136
/// body.advance(cnt);
137137
/// }
138138
/// }
@@ -232,7 +232,7 @@ impl Decode for Json {
232232
const WITH_NO_CONTENT_TYPE: bool = true;
233233

234234
fn decode<B: Buf, T: DeserializeOwned>(mut buf: B) -> Result<T, BoxError> {
235-
serde_json::from_slice(&buf.to_bytes()).map_err(Into::into)
235+
serde_json::from_slice(&buf.copy_to_bytes(buf.remaining())).map_err(Into::into)
236236
}
237237
}
238238

src/filters/compression.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
//!
33
//! Filters that compress the body of a response.
44
5-
use async_compression::stream::{BrotliEncoder, DeflateEncoder, GzipEncoder};
5+
use async_compression::tokio::bufread::{BrotliEncoder, DeflateEncoder, GzipEncoder};
66
use http::header::HeaderValue;
77
use hyper::{
88
header::{CONTENT_ENCODING, CONTENT_LENGTH},
99
Body,
1010
};
11+
use tokio_util::io::{ReaderStream, StreamReader};
1112

1213
use crate::filter::{Filter, WrapSealed};
1314
use crate::reject::IsReject;
@@ -56,7 +57,9 @@ pub struct Compression<F> {
5657
/// ```
5758
pub fn gzip() -> Compression<impl Fn(CompressionProps) -> Response + Copy> {
5859
let func = move |mut props: CompressionProps| {
59-
let body = Body::wrap_stream(GzipEncoder::new(props.body));
60+
let body = Body::wrap_stream(ReaderStream::new(GzipEncoder::new(StreamReader::new(
61+
props.body,
62+
))));
6063
props
6164
.head
6265
.headers
@@ -82,7 +85,9 @@ pub fn gzip() -> Compression<impl Fn(CompressionProps) -> Response + Copy> {
8285
/// ```
8386
pub fn deflate() -> Compression<impl Fn(CompressionProps) -> Response + Copy> {
8487
let func = move |mut props: CompressionProps| {
85-
let body = Body::wrap_stream(DeflateEncoder::new(props.body));
88+
let body = Body::wrap_stream(ReaderStream::new(DeflateEncoder::new(StreamReader::new(
89+
props.body,
90+
))));
8691
props
8792
.head
8893
.headers
@@ -108,7 +113,9 @@ pub fn deflate() -> Compression<impl Fn(CompressionProps) -> Response + Copy> {
108113
/// ```
109114
pub fn brotli() -> Compression<impl Fn(CompressionProps) -> Response + Copy> {
110115
let func = move |mut props: CompressionProps| {
111-
let body = Body::wrap_stream(BrotliEncoder::new(props.body));
116+
let body = Body::wrap_stream(ReaderStream::new(BrotliEncoder::new(StreamReader::new(
117+
props.body,
118+
))));
112119
props
113120
.head
114121
.headers

src/filters/fs.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ use hyper::Body;
2222
use mime_guess;
2323
use percent_encoding::percent_decode_str;
2424
use tokio::fs::File as TkFile;
25-
use tokio::io::AsyncRead;
25+
use tokio::io::AsyncSeekExt;
26+
use tokio_util::io::poll_read_buf;
2627

2728
use crate::filter::{Filter, FilterClone, One};
2829
use crate::reject::{self, Rejection};
@@ -419,7 +420,7 @@ fn file_stream(
419420
}
420421
reserve_at_least(&mut buf, buf_size);
421422

422-
let n = match ready!(Pin::new(&mut f).poll_read_buf(cx, &mut buf)) {
423+
let n = match ready!(poll_read_buf(Pin::new(&mut f), cx, &mut buf)) {
423424
Ok(n) => n as u64,
424425
Err(err) => {
425426
tracing::debug!("file read error: {}", err);

src/filters/sse.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ use http::header::{HeaderValue, CACHE_CONTROL, CONTENT_TYPE};
5454
use hyper::Body;
5555
use pin_project::pin_project;
5656
use serde_json::{self, Error};
57-
use tokio::time::{self, Delay};
57+
use tokio::time::{self, Sleep};
5858

5959
use self::sealed::SseError;
6060
use super::header;
@@ -386,7 +386,7 @@ impl KeepAlive {
386386
S: TryStream<Ok = Event> + Send + 'static,
387387
S::Error: StdError + Send + Sync + 'static,
388388
{
389-
let alive_timer = time::delay_for(self.max_interval);
389+
let alive_timer = time::sleep(self.max_interval);
390390
SseKeepAlive {
391391
event_stream,
392392
comment_text: self.comment_text,
@@ -403,7 +403,8 @@ struct SseKeepAlive<S> {
403403
event_stream: S,
404404
comment_text: Cow<'static, str>,
405405
max_interval: Duration,
406-
alive_timer: Delay,
406+
#[pin]
407+
alive_timer: Sleep,
407408
}
408409

409410
/// Keeps event source connection alive when no events sent over a some time.
@@ -421,6 +422,7 @@ struct SseKeepAlive<S> {
421422
/// use std::convert::Infallible;
422423
/// use futures::StreamExt;
423424
/// use tokio::time::interval;
425+
/// use tokio_stream::wrappers::IntervalStream;
424426
/// use warp::{Filter, Stream, sse::Event};
425427
///
426428
/// // create server-sent event
@@ -433,7 +435,9 @@ struct SseKeepAlive<S> {
433435
/// .and(warp::get())
434436
/// .map(|| {
435437
/// let mut counter: u64 = 0;
436-
/// let event_stream = interval(Duration::from_secs(15)).map(move |_| {
438+
/// let interval = interval(Duration::from_secs(15));
439+
/// let stream = IntervalStream::new(interval);
440+
/// let event_stream = stream.map(move |_| {
437441
/// counter += 1;
438442
/// sse_counter(counter)
439443
/// });

src/filters/ws.rs

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ use std::future::Future;
66
use std::pin::Pin;
77
use std::task::{Context, Poll};
88

9-
use super::{body, header};
10-
use crate::filter::{Filter, One};
9+
use super::header;
10+
use crate::filter::{filter_fn_one, Filter, One};
1111
use crate::reject::Rejection;
1212
use crate::reply::{Reply, Response};
1313
use futures::{future, ready, FutureExt, Sink, Stream, TryFutureExt};
1414
use headers::{Connection, HeaderMapExt, SecWebsocketAccept, SecWebsocketKey, Upgrade};
1515
use http;
16+
use hyper::upgrade::OnUpgrade;
1617
use tokio_tungstenite::{
1718
tungstenite::protocol::{self, WebSocketConfig},
1819
WebSocketStream,
@@ -57,19 +58,21 @@ pub fn ws() -> impl Filter<Extract = One<Ws>, Error = Rejection> + Copy {
5758
//.and(header::exact2(Upgrade::websocket()))
5859
//.and(header::exact2(SecWebsocketVersion::V13))
5960
.and(header::header2::<SecWebsocketKey>())
60-
.and(body::body())
61-
.map(move |key: SecWebsocketKey, body: ::hyper::Body| Ws {
62-
body,
63-
config: None,
64-
key,
65-
})
61+
.and(on_upgrade())
62+
.map(
63+
move |key: SecWebsocketKey, on_upgrade: Option<OnUpgrade>| Ws {
64+
config: None,
65+
key,
66+
on_upgrade,
67+
},
68+
)
6669
}
6770

6871
/// Extracted by the [`ws`](ws) filter, and used to finish an upgrade.
6972
pub struct Ws {
70-
body: ::hyper::Body,
7173
config: Option<WebSocketConfig>,
7274
key: SecWebsocketKey,
75+
on_upgrade: Option<OnUpgrade>,
7376
}
7477

7578
impl Ws {
@@ -132,23 +135,24 @@ where
132135
U: Future<Output = ()> + Send + 'static,
133136
{
134137
fn into_response(self) -> Response {
135-
let on_upgrade = self.on_upgrade;
136-
let config = self.ws.config;
137-
let fut = self
138-
.ws
139-
.body
140-
.on_upgrade()
141-
.and_then(move |upgraded| {
142-
tracing::trace!("websocket upgrade complete");
143-
WebSocket::from_raw_socket(upgraded, protocol::Role::Server, config).map(Ok)
144-
})
145-
.and_then(move |socket| on_upgrade(socket).map(Ok))
146-
.map(|result| {
147-
if let Err(err) = result {
148-
tracing::debug!("ws upgrade error: {}", err);
149-
}
150-
});
151-
::tokio::task::spawn(fut);
138+
if let Some(on_upgrade) = self.ws.on_upgrade {
139+
let on_upgrade_cb = self.on_upgrade;
140+
let config = self.ws.config;
141+
let fut = on_upgrade
142+
.and_then(move |upgraded| {
143+
tracing::trace!("websocket upgrade complete");
144+
WebSocket::from_raw_socket(upgraded, protocol::Role::Server, config).map(Ok)
145+
})
146+
.and_then(move |socket| on_upgrade_cb(socket).map(Ok))
147+
.map(|result| {
148+
if let Err(err) = result {
149+
tracing::debug!("ws upgrade error: {}", err);
150+
}
151+
});
152+
::tokio::task::spawn(fut);
153+
} else {
154+
tracing::debug!("ws couldn't be upgraded since no upgrade state was present");
155+
}
152156

153157
let mut res = http::Response::default();
154158

@@ -163,6 +167,11 @@ where
163167
}
164168
}
165169

170+
// Extracts OnUpgrade state from the route.
171+
fn on_upgrade() -> impl Filter<Extract = (Option<OnUpgrade>,), Error = Rejection> + Copy {
172+
filter_fn_one(|route| future::ready(Ok(route.extensions_mut().remove::<OnUpgrade>())))
173+
}
174+
166175
/// A websocket `Stream` and `Sink`, provided to `ws` filters.
167176
///
168177
/// Ping messages sent from the client will be handled internally by replying with a Pong message.

src/route.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,10 @@ impl Route {
7575
self.req.extensions()
7676
}
7777

78-
/*
78+
#[cfg(feature = "websocket")]
7979
pub(crate) fn extensions_mut(&mut self) -> &mut http::Extensions {
8080
self.req.extensions_mut()
8181
}
82-
*/
8382

8483
pub(crate) fn uri(&self) -> &http::Uri {
8584
self.req.uri()

0 commit comments

Comments
 (0)