mirror of
https://github.com/rwf2/Rocket.git
synced 2025-02-01 14:22:05 +00:00
fd294049c7
This commit completely rewrites Rocket's HTTP serving. In addition to significant internal cleanup, this commit introduces the following major features: * Support for custom, external listeners in the `listener` module. The new `listener` module contains new `Bindable`, `Listener`, and `Connection` traits which enable composable, external implementations of connection listeners. Rocket can launch on any `Listener`, or anything that can be used to create a listener (`Bindable`), via a new `launch_on()` method. * Support for Unix domain socket listeners out of the box. The default listener backwards compatibly supports listening on Unix domain sockets. To do so, configure an `address` of `unix:path/to/socket` and optional set `reuse` to `true` (the default) or `false` which controls whether Rocket will handle creating and deleting the unix domain socket. In addition to these new features, this commit makes the following major improvements: * Rocket now depends on hyper 1. * Rocket no longer depends on hyper to handle connections. This allows us to handle more connection failure conditions which results in an overall more robust server with fewer dependencies. * Logic to work around hyper's inability to reference incoming request data in the response results in a 15% performance improvement. * `Client`s can be marked secure with `Client::{un}tracked_secure()`, allowing Rocket to treat local connections as running under TLS. * The `macros` feature of `tokio` is no longer used by Rocket itself. Dependencies can take advantage of this reduction in compile-time cost by disabling the new default feature `tokio-macros`. * A new `TlsConfig::validate()` method allows checking a TLS config. * New `TlsConfig::{certs,key}_reader()`, `MtlsConfig::ca_certs_reader()` methods return `BufReader`s, which allow reading the configured certs and key directly. * A new `NamedFile::open_with()` constructor allows specifying `OpenOptions`. These improvements resulted in the following breaking changes: * The MSRV is now 1.74. * `hyper` is no longer exported from `rocket::http`. * `IoHandler::io` takes `Box<Self>` instead of `Pin<Box<Self>>`. - Use `Box::into_pin(self)` to recover the previous type. * `Response::upgrade()` now returns an `&mut dyn IoHandler`, not `Pin<& mut _>`. * `Config::{address,port,tls,mtls}` methods have been removed. - Use methods on `Rocket::endpoint()` instead. * `TlsConfig` was moved to `tls::TlsConfig`. * `MutualTls` was renamed and moved to `mtls::MtlsConfig`. * `ErrorKind::TlsBind` was removed. * The second field of `ErrorKind::Shutdown` was removed. * `{Local}Request::{set_}remote()` methods take/return an `Endpoint`. * `Client::new()` was removed; it was previously deprecated. Internally, the following major changes were made: * A new `async_bound` attribute macro was introduced to allow setting bounds on futures returned by `async fn`s in traits while maintaining good docs. * All utility functionality was moved to a new `util` module. Resolves #2671. Resolves #1070.
90 lines
2.7 KiB
Rust
90 lines
2.7 KiB
Rust
use std::pin::Pin;
|
|
use std::task::{Context, Poll};
|
|
|
|
use rocket::data::IoStream;
|
|
use rocket::futures::{StreamExt, SinkExt, Sink};
|
|
use rocket::futures::stream::{Stream, FusedStream};
|
|
|
|
use crate::frame::{Message, CloseFrame};
|
|
use crate::result::{Result, Error};
|
|
|
|
/// A readable and writeable WebSocket [`Message`] `async` stream.
|
|
///
|
|
/// This struct implements [`Stream`] and [`Sink`], allowing for `async` reading
|
|
/// and writing of [`Message`]s. The [`StreamExt`] and [`SinkExt`] traits can be
|
|
/// imported to provide additional functionality for streams and sinks:
|
|
///
|
|
/// ```rust
|
|
/// # use rocket::get;
|
|
/// # use rocket_ws as ws;
|
|
/// use rocket::futures::{SinkExt, StreamExt};
|
|
///
|
|
/// #[get("/echo/manual")]
|
|
/// fn echo_manual<'r>(ws: ws::WebSocket) -> ws::Channel<'r> {
|
|
/// ws.channel(move |mut stream| Box::pin(async move {
|
|
/// while let Some(message) = stream.next().await {
|
|
/// let _ = stream.send(message?).await;
|
|
/// }
|
|
///
|
|
/// Ok(())
|
|
/// }))
|
|
/// }
|
|
/// ```
|
|
///
|
|
/// [`StreamExt`]: rocket::futures::StreamExt
|
|
/// [`SinkExt`]: rocket::futures::SinkExt
|
|
pub struct DuplexStream(tokio_tungstenite::WebSocketStream<IoStream>);
|
|
|
|
impl DuplexStream {
|
|
pub(crate) async fn new(stream: IoStream, config: crate::Config) -> Self {
|
|
use tokio_tungstenite::WebSocketStream;
|
|
use crate::tungstenite::protocol::Role;
|
|
|
|
let inner = WebSocketStream::from_raw_socket(stream, Role::Server, Some(config));
|
|
DuplexStream(inner.await)
|
|
}
|
|
|
|
/// Close the stream now. This does not typically need to be called.
|
|
pub async fn close(&mut self, msg: Option<CloseFrame<'_>>) -> Result<()> {
|
|
self.0.close(msg).await
|
|
}
|
|
}
|
|
|
|
impl Stream for DuplexStream {
|
|
type Item = Result<Message>;
|
|
|
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
|
self.get_mut().0.poll_next_unpin(cx)
|
|
}
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
self.0.size_hint()
|
|
}
|
|
}
|
|
|
|
impl FusedStream for DuplexStream {
|
|
fn is_terminated(&self) -> bool {
|
|
self.0.is_terminated()
|
|
}
|
|
}
|
|
|
|
impl Sink<Message> for DuplexStream {
|
|
type Error = Error;
|
|
|
|
fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
self.get_mut().0.poll_ready_unpin(cx)
|
|
}
|
|
|
|
fn start_send(self: Pin<&mut Self>, item: Message) -> Result<(), Self::Error> {
|
|
self.get_mut().0.start_send_unpin(item)
|
|
}
|
|
|
|
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
self.get_mut().0.poll_flush_unpin(cx)
|
|
}
|
|
|
|
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
self.get_mut().0.poll_close_unpin(cx)
|
|
}
|
|
}
|