Comments (15)
I wanted to experiment, so I've landed experimental HTTP/3 support based on s2n-quic
and a patched version of h3
.
It works!
> cd examples/tls
> cargo run
...
🚀 Rocket has launched on https://127.0.0.1:8000 (TLS + MTLS)
curl -k --http3-only -v https://127.0.0.1:8000 master ●
* Trying 127.0.0.1:8000...
* Skipped certificate verification
* Connected to 127.0.0.1 (127.0.0.1) port 8000
* using HTTP/3
* [HTTP/3] [0] OPENED stream for https://127.0.0.1:8000/
* [HTTP/3] [0] [:method: GET]
* [HTTP/3] [0] [:scheme: https]
* [HTTP/3] [0] [:authority: 127.0.0.1:8000]
* [HTTP/3] [0] [:path: /]
* [HTTP/3] [0] [user-agent: curl/8.6.0]
* [HTTP/3] [0] [accept: */*]
> GET / HTTP/3
> Host: 127.0.0.1:8000
> User-Agent: curl/8.6.0
> Accept: */*
>
< HTTP/3 200
< content-type: text/plain; charset=utf-8
< server: Rocket
< x-frame-options: SAMEORIGIN
< x-content-type-options: nosniff
< permissions-policy: interest-cohort=()
< content-length: 13
<
* Connection #0 to host 127.0.0.1 left intact
Hello, world!%
In this h3
branch, only the quic/http3 server runs when the http3
feature is enabled. The idea would be to spawn both the http1/http2 server and the http3 server and respond with an alt-svc: h3
header in the former. Nevertheless, this shows that Rocket's internal architecture allow us to implement and ship some kind of http3 support without too much trouble.
from rocket.
I'd like nothing more than for Rocket to support HTTP/3, but doing so without having support in upstream hyper
would require a considerable amount of work.
As far as I can tell, quiche is the only mature HTTP/3 implementation in Rust. It's not clear to me whether the library can correctly be used in an async
server, however, as its docs don't state whether methods like poll
block.
Aside from quiche
, the only other viable alternative I'm aware of is h3
, which would become hyper's HTTP/3 backend. According to the README, it is "still very experimental", and the report indicates there's still quite a road to be compliant. Nevertheless, it seems viable to integrate into Rocket as a sort of "draft" or "preview" of HTTP/3 support. If there is some way to integrate h3
into Rocket in such a way that doesn't require drastically changing the existing codebase, I'd be all for it. Otherwise, we'll just have to wait for hyper
to gain support or some other library to pop up.
from rocket.
@SergioBenitez is that h3 branch something that development should be continued on? I would love to continue work on this.
from rocket.
@amyipdev Yes. I'll continue to push commits to the branch. I've just now pushed a nearly "complete" version. It's likely that we'll need to rewrite/significantly improve the h3
integration for s2n
as well as h3
itself. This is because at the moment, there's no way to get an AsyncRead
and AsyncWrite
stream to the client once the HTTP3 request has been received. This means we can't directly integrate with the existing Listener
/Connection
APIs, which means we don't get graceful shutdown for "free".
In short, we need to really implement Listener
for some H3Quic
type and get rid of Void
here:
Rocket/core/lib/src/listener/quic.rs
Lines 84 to 107 in b2378ab
from rocket.
I'll look into it and see if there's any way I can help.
from rocket.
Please let us (the s2n team) know if you need anything to make the integration easier. Ideally we can get the s2n-quic-h3 crate published so you're not having to maintain a fork.
from rocket.
Currently compiling the most recent commit, noticed I had to manually enable rocket_dyn_templates/tera
. Didn't come up before - possible regression?
from rocket.
Currently compiling the most recent commit, noticed I had to manually enable
rocket_dyn_templates/tera
. Didn't come up before - possible regression?
What are you running? You'll only need to do that if you're trying to compile the dyn_templates
crate. If you want to test the crate, run ./script/test.sh
. If you want to just work on core
, then run your cargo
commands inside core/lib
.
from rocket.
Please let us (the s2n team) know if you need anything to make the integration easier. Ideally we can get the s2n-quic-h3 crate published so you're not having to maintain a fork.
Really appreciate the comment! Thank you!
At the moment, aside from aws/s2n-quic#2055, the biggest issues are:
-
The server's
accept()
method requires an&mut
reference. This means that we can't accept from multiple threads without synchronization. This is probably fine, but it deviates from existing connection-like interfaces such asTcpListener::accept()
. This is also the case on theh3
side, so improving this only on thes2n
will unfortunately be insufficient. -
This is mostly on the
h3
side, but the lack ofStream
andAsyncWrite
implementations on the "fully accepted HTTP3 stream." In other words, we'd really like to have a read/write stream to the HTTP3 body once an HTTP3 request has been parsed out, but that's not currently possible because h3::server::RequestStream doesn't implementAsyncRead
/AsyncWrite
, and an efficient implementation outside ofh3
isn't possible due to the use of theBuf
trait. We end up with:pub struct QuicRx(h3::RequestStream<quic_h3::RecvStream, Bytes>); pub struct QuicTx(h3::RequestStream<quic_h3::SendStream<Bytes>, Bytes>); impl Stream for QuicRx { type Item = io::Result<Bytes>; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { use bytes::Buf; match ready!(self.0.poll_recv_data(cx)) { Ok(Some(mut buf)) => Poll::Ready(Some(Ok(buf.copy_to_bytes(buf.remaining())))), Ok(None) => Poll::Ready(None), Err(e) => Poll::Ready(Some(Err(io::Error::other(e)))), } } } impl AsyncWrite for QuicTx { fn poll_write( mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll<io::Result<usize>> { let len = buf.len(); let result = ready!(self.0.poll_send_data(cx, Bytes::copy_from_slice(buf))); result.map_err(io::Error::other)?; Poll::Ready(Ok(len)) } fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> { Poll::Ready(Ok(())) } fn poll_shutdown(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> { Poll::Ready(Ok(())) } }
The simplest way to resolve this would likely be for
h3
to implementStream
andAsyncWrite
if the underlying streams do, which in this case would mean that s2n'sRecvStream
andSendStream
would need the appropriate implementations.
In general, it seems that most if not all of the issues I've encountered are due to h3
.
from rocket.
The server's accept() method requires an &mut reference. This means that we can't accept from multiple threads without synchronization. This is probably fine, but it deviates from existing connection-like interfaces such as TcpListener::accept(). This is also the case on the h3 side, so improving this only on the s2n will unfortunately be insufficient.
Can you open an issue for this? I understand the ask but we'll need to figure what it looks like in practice. This would end up being essentially a "spmc channel". A naive distribution strategy for new connections could just maintain a queue and round robin. But if one of those acceptors is too slow then the load wouldn't be well-distributed and could lead to poor performance.
In general, it seems that most if not all of the issues I've encountered are due to h3.
Yes it's still very much an early implementation... Definitely still some issues with the underlying interface that haven't been solved, too: hyperium/h3#78
from rocket.
Here's something that might be able to help on the s2n
side.
The Listener
interface we have is as follows:
-
We start with something we can
bind()
to. This is usually aSocketAddr
, reified asBindable
. Callingbind()
returns aListener
. -
The listener
accept
s connections in two phases:accept()
andconnect()
.The contract is such that
accept()
must do as little work as possible as it is intended to be used in an accept-loop.connect()
on the other hand is expected to be called in a separate task and can do whatever work is needed to prepare the connection for reading/writing. This is where the TLS handshake occurs, for example. -
An HTTP request is read from the connection.
Mapping this to HTTP3/quic with the current implementations is proving to be challenging because accepting a connection and reading an HTTP request is currently interleaved in a difficult-to-compose manner. As it stands, we go quic -> HTTP3 -> connection. In other words, we need to do some work with HTTP3 before we can get our hands on a valid peer connection.
This doesn't seem endemic to the design, however. If we instead reverse the arrows (quic -> connection -> HTTP3), then we recover the previous design. Concretely, this would mean that s2n_quic_h3
has some type T
that implements h3::quic::Connection while also being AsyncRead
and AsyncWrite
. I believe that type is PeerStream
.
Do you think it's possible to implement h3::Connection
for PeerStream
, or some other type that would provide the sought-after behavior?
from rocket.
The h3
branch now implements complete support for HTTP3. There's still a lot of polish necessary, but I foresee it going into mainline very soon.
from rocket.
@SergioBenitez good to hear, keep me posted! And if I can help in any way with polishing please let me know
from rocket.
Support is ready to land on master! One key missing bit is support for mTLS over QUIC. s2n-quic makes this a bit difficult to do at the moment (aws/s2n-quic#1957). @amyipdev Can you keep tabs on the rustls update in aws/s2n-quic#2143 and mTLS in aws/s2n-quic#2129 and perhaps update our QUIC integration to 1) expose mTLS certificates and 2) not create a second rustls
config once aws/s2n-quic#2143 lands?
from rocket.
@SergioBenitez I'll do my best!
from rocket.
Related Issues (20)
- Possible Incompleteness HOT 1
- Possible Incompleteness HOT 1
- doc: change `&ContentType` with `&Accept` in the list of implementations of `FromRequest` HOT 1
- [Feature]: Enhanced State Mutation for Effortless Handling of Shared Resources HOT 5
- Guide navigation causes relative links inside articles to 404 HOT 1
- Redirection to a route which takes a vector parameter results in an error HOT 1
- Allow users to create of Data<'r> objects HOT 5
- Validation not invoked on Json HOT 6
- Implement `FromForm` for `Range` HOT 1
- Missing license files in rocket_codegen-0.5.0.crate HOT 2
- Add SQLite extensions HOT 2
- Middleware that handles requests for static resources HOT 2
- Unable to build: no `Serialize` in `de` HOT 3
- Add default content_type for TempFile uploads HOT 2
- Could not find `json` in `serde` HOT 1
- Can't change IP that Rocket starts from. HOT 1
- Clippy lint: temporary with significant `Drop` can be early dropped HOT 1
- Rocket sometimes resets connection instead of responding with 413 error response HOT 2
- MiniJinja can't be used for templates HOT 1
- Routing by hostname HOT 8
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rocket.