1#![deny(missing_docs)]
5
6use std::{
7 convert::TryInto,
8 future::Future,
9 pin::Pin,
10 sync::Arc,
11 task::{self, Poll, ready},
12};
13
14use bytes::{Buf, Bytes};
15use futures_util::{
16 Stream, StreamExt,
17 stream::{self},
18};
19use http3::{
20 error::Code,
21 quic::{self, ConnectionErrorIncoming, StreamErrorIncoming, StreamId, WriteBuf},
22};
23
24#[cfg(all(feature = "quinn", not(feature = "quic")))]
25pub use quinn::{self as quic_impl, AcceptBi, AcceptUni, Endpoint, OpenBi, OpenUni, VarInt};
26
27#[cfg(all(feature = "quic", not(feature = "quinn")))]
28pub use ::quic::{self as quic_impl, AcceptBi, AcceptUni, Endpoint, OpenBi, OpenUni, VarInt};
29
30use quic_impl::ReadError;
31use tokio_util::sync::ReusableBoxFuture;
32
33#[cfg(feature = "tracing")]
34use tracing::instrument;
35
36#[cfg(feature = "datagram")]
37pub mod datagram;
38
39type BoxStreamSync<'a, T> = Pin<Box<dyn Stream<Item = T> + Sync + Send + 'a>>;
41
42pub struct Connection {
46 conn: quic_impl::Connection,
47 incoming_bi: BoxStreamSync<'static, <AcceptBi<'static> as Future>::Output>,
48 opening_bi: Option<BoxStreamSync<'static, <OpenBi<'static> as Future>::Output>>,
49 incoming_uni: BoxStreamSync<'static, <AcceptUni<'static> as Future>::Output>,
50 opening_uni: Option<BoxStreamSync<'static, <OpenUni<'static> as Future>::Output>>,
51}
52
53impl Connection {
54 pub fn new(conn: quic_impl::Connection) -> Self {
56 Self {
57 conn: conn.clone(),
58 incoming_bi: Box::pin(stream::unfold(conn.clone(), |conn| async {
59 Some((conn.accept_bi().await, conn))
60 })),
61 opening_bi: None,
62 incoming_uni: Box::pin(stream::unfold(conn.clone(), |conn| async {
63 Some((conn.accept_uni().await, conn))
64 })),
65 opening_uni: None,
66 }
67 }
68}
69
70impl<B> quic::Connection<B> for Connection
71where
72 B: Buf,
73{
74 type RecvStream = RecvStream;
75 type OpenStreams = OpenStreams;
76
77 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
78 fn poll_accept_bidi(
79 &mut self,
80 cx: &mut task::Context<'_>,
81 ) -> Poll<Result<Self::BidiStream, ConnectionErrorIncoming>> {
82 let (send, recv) = ready!(self.incoming_bi.poll_next_unpin(cx))
83 .expect("self.incoming_bi BoxStream never returns None")
84 .map_err(convert_connection_error)?;
85 Poll::Ready(Ok(Self::BidiStream {
86 send: Self::SendStream::new(send),
87 recv: Self::RecvStream::new(recv),
88 }))
89 }
90
91 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
92 fn poll_accept_recv(
93 &mut self,
94 cx: &mut task::Context<'_>,
95 ) -> Poll<Result<Self::RecvStream, ConnectionErrorIncoming>> {
96 let recv = ready!(self.incoming_uni.poll_next_unpin(cx))
97 .expect("self.incoming_uni BoxStream never returns None")
98 .map_err(convert_connection_error)?;
99 Poll::Ready(Ok(Self::RecvStream::new(recv)))
100 }
101
102 fn opener(&self) -> Self::OpenStreams {
103 OpenStreams {
104 conn: self.conn.clone(),
105 opening_bi: None,
106 opening_uni: None,
107 }
108 }
109}
110
111fn convert_connection_error(e: quic_impl::ConnectionError) -> http3::quic::ConnectionErrorIncoming {
112 match e {
113 quic_impl::ConnectionError::ApplicationClosed(application_close) => {
114 ConnectionErrorIncoming::ApplicationClose {
115 error_code: application_close.error_code.into(),
116 }
117 }
118 quic_impl::ConnectionError::TimedOut => ConnectionErrorIncoming::Timeout,
119
120 error @ quic_impl::ConnectionError::VersionMismatch
121 | error @ quic_impl::ConnectionError::Reset
122 | error @ quic_impl::ConnectionError::LocallyClosed
123 | error @ quic_impl::ConnectionError::CidsExhausted
124 | error @ quic_impl::ConnectionError::TransportError(_)
125 | error @ quic_impl::ConnectionError::ConnectionClosed(_) => {
126 ConnectionErrorIncoming::Undefined(Arc::new(error))
127 }
128 }
129}
130
131impl<B> quic::OpenStreams<B> for Connection
132where
133 B: Buf,
134{
135 type SendStream = SendStream<B>;
136 type BidiStream = BidiStream<B>;
137
138 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
139 fn poll_open_bidi(
140 &mut self,
141 cx: &mut task::Context<'_>,
142 ) -> Poll<Result<Self::BidiStream, StreamErrorIncoming>> {
143 let bi = self.opening_bi.get_or_insert_with(|| {
144 Box::pin(stream::unfold(self.conn.clone(), |conn| async {
145 Some((conn.open_bi().await, conn))
146 }))
147 });
148 let (send, recv) = ready!(bi.poll_next_unpin(cx))
149 .expect("BoxStream does not return None")
150 .map_err(|e| StreamErrorIncoming::ConnectionErrorIncoming {
151 connection_error: convert_connection_error(e),
152 })?;
153 Poll::Ready(Ok(Self::BidiStream {
154 send: Self::SendStream::new(send),
155 recv: RecvStream::new(recv),
156 }))
157 }
158
159 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
160 fn poll_open_send(
161 &mut self,
162 cx: &mut task::Context<'_>,
163 ) -> Poll<Result<Self::SendStream, StreamErrorIncoming>> {
164 let uni = self.opening_uni.get_or_insert_with(|| {
165 Box::pin(stream::unfold(self.conn.clone(), |conn| async {
166 Some((conn.open_uni().await, conn))
167 }))
168 });
169
170 let send = ready!(uni.poll_next_unpin(cx))
171 .expect("BoxStream does not return None")
172 .map_err(|e| StreamErrorIncoming::ConnectionErrorIncoming {
173 connection_error: convert_connection_error(e),
174 })?;
175 Poll::Ready(Ok(Self::SendStream::new(send)))
176 }
177
178 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
179 fn close(&mut self, code: Code, reason: &[u8]) {
180 self.conn.close(
181 VarInt::from_u64(code.value()).expect("error code VarInt"),
182 reason,
183 );
184 }
185}
186
187pub struct OpenStreams {
192 conn: quic_impl::Connection,
193 opening_bi: Option<BoxStreamSync<'static, <OpenBi<'static> as Future>::Output>>,
194 opening_uni: Option<BoxStreamSync<'static, <OpenUni<'static> as Future>::Output>>,
195}
196
197impl<B> quic::OpenStreams<B> for OpenStreams
198where
199 B: Buf,
200{
201 type SendStream = SendStream<B>;
202 type BidiStream = BidiStream<B>;
203
204 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
205 fn poll_open_bidi(
206 &mut self,
207 cx: &mut task::Context<'_>,
208 ) -> Poll<Result<Self::BidiStream, StreamErrorIncoming>> {
209 let bi = self.opening_bi.get_or_insert_with(|| {
210 Box::pin(stream::unfold(self.conn.clone(), |conn| async {
211 Some((conn.open_bi().await, conn))
212 }))
213 });
214
215 let (send, recv) = ready!(bi.poll_next_unpin(cx))
216 .expect("BoxStream does not return None")
217 .map_err(|e| StreamErrorIncoming::ConnectionErrorIncoming {
218 connection_error: convert_connection_error(e),
219 })?;
220 Poll::Ready(Ok(Self::BidiStream {
221 send: Self::SendStream::new(send),
222 recv: RecvStream::new(recv),
223 }))
224 }
225
226 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
227 fn poll_open_send(
228 &mut self,
229 cx: &mut task::Context<'_>,
230 ) -> Poll<Result<Self::SendStream, StreamErrorIncoming>> {
231 let uni = self.opening_uni.get_or_insert_with(|| {
232 Box::pin(stream::unfold(self.conn.clone(), |conn| async {
233 Some((conn.open_uni().await, conn))
234 }))
235 });
236
237 let send = ready!(uni.poll_next_unpin(cx))
238 .expect("BoxStream does not return None")
239 .map_err(|e| StreamErrorIncoming::ConnectionErrorIncoming {
240 connection_error: convert_connection_error(e),
241 })?;
242 Poll::Ready(Ok(Self::SendStream::new(send)))
243 }
244
245 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
246 fn close(&mut self, code: Code, reason: &[u8]) {
247 self.conn.close(
248 VarInt::from_u64(code.value()).expect("error code VarInt"),
249 reason,
250 );
251 }
252}
253
254impl Clone for OpenStreams {
255 fn clone(&self) -> Self {
256 Self {
257 conn: self.conn.clone(),
258 opening_bi: None,
259 opening_uni: None,
260 }
261 }
262}
263
264pub struct BidiStream<B>
269where
270 B: Buf,
271{
272 send: SendStream<B>,
273 recv: RecvStream,
274}
275
276impl<B> quic::BidiStream<B> for BidiStream<B>
277where
278 B: Buf,
279{
280 type SendStream = SendStream<B>;
281 type RecvStream = RecvStream;
282
283 fn split(self) -> (Self::SendStream, Self::RecvStream) {
284 (self.send, self.recv)
285 }
286}
287
288impl<B: Buf> quic::RecvStream for BidiStream<B> {
289 type Buf = Bytes;
290
291 fn poll_data(
292 &mut self,
293 cx: &mut task::Context<'_>,
294 ) -> Poll<Result<Option<Self::Buf>, StreamErrorIncoming>> {
295 self.recv.poll_data(cx)
296 }
297
298 fn stop_sending(&mut self, error_code: u64) {
299 self.recv.stop_sending(error_code)
300 }
301
302 fn recv_id(&self) -> StreamId {
303 self.recv.recv_id()
304 }
305}
306
307impl<B> quic::SendStream<B> for BidiStream<B>
308where
309 B: Buf,
310{
311 fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), StreamErrorIncoming>> {
312 self.send.poll_ready(cx)
313 }
314
315 fn poll_finish(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), StreamErrorIncoming>> {
316 self.send.poll_finish(cx)
317 }
318
319 fn reset(&mut self, reset_code: u64) {
320 self.send.reset(reset_code)
321 }
322
323 fn send_data<D: Into<WriteBuf<B>>>(&mut self, data: D) -> Result<(), StreamErrorIncoming> {
324 self.send.send_data(data)
325 }
326
327 fn send_id(&self) -> StreamId {
328 self.send.send_id()
329 }
330}
331impl<B> quic::SendStreamUnframed<B> for BidiStream<B>
332where
333 B: Buf,
334{
335 fn poll_send<D: Buf>(
336 &mut self,
337 cx: &mut task::Context<'_>,
338 buf: &mut D,
339 ) -> Poll<Result<usize, StreamErrorIncoming>> {
340 self.send.poll_send(cx, buf)
341 }
342}
343
344impl<B> quic::Is0rtt for BidiStream<B>
345where
346 B: Buf,
347{
348 fn is_0rtt(&self) -> bool {
349 self.recv.is_0rtt()
350 }
351}
352
353pub struct RecvStream {
357 stream: Option<quic_impl::RecvStream>,
358 read_chunk_fut: ReadChunkFuture,
359 is_0rtt: bool,
360 pending_stop: Option<VarInt>,
361}
362
363type ReadChunkFuture = ReusableBoxFuture<
364 'static,
365 (
366 quic_impl::RecvStream,
367 Result<Option<quic_impl::Chunk>, quic_impl::ReadError>,
368 ),
369>;
370
371impl RecvStream {
372 fn new(stream: quic_impl::RecvStream) -> Self {
373 let is_0rtt = stream.is_0rtt();
374 Self {
375 stream: Some(stream),
376 read_chunk_fut: ReusableBoxFuture::new(async { unreachable!() }),
378 is_0rtt,
379 pending_stop: None,
380 }
381 }
382}
383
384impl quic::RecvStream for RecvStream {
385 type Buf = Bytes;
386
387 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
388 fn poll_data(
389 &mut self,
390 cx: &mut task::Context<'_>,
391 ) -> Poll<Result<Option<Self::Buf>, StreamErrorIncoming>> {
392 if let Some(mut stream) = self.stream.take() {
393 self.read_chunk_fut.set(async move {
394 let chunk = stream.read_chunk(usize::MAX, true).await;
395 (stream, chunk)
396 })
397 };
398
399 let (mut stream, chunk) = ready!(self.read_chunk_fut.poll(cx));
400 if let Some(error_code) = self.pending_stop.take() {
401 let _ = stream.stop(error_code);
402 }
403 self.stream = Some(stream);
404 Poll::Ready(Ok(chunk
405 .map_err(convert_read_error_to_stream_error)?
406 .map(|c| c.bytes)))
407 }
408
409 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
410 fn stop_sending(&mut self, error_code: u64) {
411 let error_code = VarInt::from_u64(error_code).expect("invalid error_code");
412 if let Some(stream) = self.stream.as_mut() {
413 let _ = stream.stop(error_code);
414 } else {
415 self.pending_stop = Some(error_code);
416 }
417 }
418
419 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
420 fn recv_id(&self) -> StreamId {
421 let num: u64 = self.stream.as_ref().unwrap().id().into();
422
423 num.try_into().expect("invalid stream id")
424 }
425}
426
427impl quic::Is0rtt for RecvStream {
428 fn is_0rtt(&self) -> bool {
433 self.is_0rtt
434 }
435}
436
437fn convert_read_error_to_stream_error(error: ReadError) -> StreamErrorIncoming {
438 match error {
439 ReadError::Reset(var_int) => StreamErrorIncoming::StreamTerminated {
440 error_code: var_int.into_inner(),
441 },
442 ReadError::ConnectionLost(connection_error) => {
443 StreamErrorIncoming::ConnectionErrorIncoming {
444 connection_error: convert_connection_error(connection_error),
445 }
446 }
447 error @ ReadError::ClosedStream => StreamErrorIncoming::Unknown(Box::new(error)),
448 ReadError::IllegalOrderedRead => panic!("http3-quic only performs ordered reads"),
449 error @ ReadError::ZeroRttRejected => StreamErrorIncoming::Unknown(Box::new(error)),
450 }
451}
452
453fn convert_write_error_to_stream_error(error: quic_impl::WriteError) -> StreamErrorIncoming {
454 match error {
455 quic_impl::WriteError::Stopped(var_int) => StreamErrorIncoming::StreamTerminated {
456 error_code: var_int.into_inner(),
457 },
458 quic_impl::WriteError::ConnectionLost(connection_error) => {
459 StreamErrorIncoming::ConnectionErrorIncoming {
460 connection_error: convert_connection_error(connection_error),
461 }
462 }
463 error @ quic_impl::WriteError::ClosedStream
464 | error @ quic_impl::WriteError::ZeroRttRejected => {
465 StreamErrorIncoming::Unknown(Box::new(error))
466 }
467 }
468}
469
470pub struct SendStream<B: Buf> {
474 stream: quic_impl::SendStream,
475 writing: Option<WriteBuf<B>>,
476}
477
478impl<B> SendStream<B>
479where
480 B: Buf,
481{
482 fn new(stream: quic_impl::SendStream) -> SendStream<B> {
483 Self {
484 stream,
485 writing: None,
486 }
487 }
488}
489
490impl<B> quic::SendStream<B> for SendStream<B>
491where
492 B: Buf,
493{
494 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
495 fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), StreamErrorIncoming>> {
496 if let Some(ref mut data) = self.writing {
497 while data.has_remaining() {
498 let stream = Pin::new(&mut self.stream);
499 let written = ready!(stream.poll_write(cx, data.chunk()))
500 .map_err(convert_write_error_to_stream_error)?;
501 data.advance(written);
502 }
503 }
504 self.writing = None;
506 Poll::Ready(Ok(()))
507 }
508
509 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
510 fn poll_finish(
511 &mut self,
512 _cx: &mut task::Context<'_>,
513 ) -> Poll<Result<(), StreamErrorIncoming>> {
514 Poll::Ready(
515 self.stream
516 .finish()
517 .map_err(|e| StreamErrorIncoming::Unknown(Box::new(e))),
518 )
519 }
520
521 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
522 fn reset(&mut self, reset_code: u64) {
523 let _ = self
524 .stream
525 .reset(VarInt::from_u64(reset_code).unwrap_or(VarInt::MAX));
526 }
527
528 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
529 fn send_data<D: Into<WriteBuf<B>>>(&mut self, data: D) -> Result<(), StreamErrorIncoming> {
530 if self.writing.is_some() {
531 #[cfg(feature = "tracing")]
535 tracing::error!("send_data called while send stream is not ready");
536 return Err(StreamErrorIncoming::ConnectionErrorIncoming {
537 connection_error: ConnectionErrorIncoming::InternalError(
538 "internal error in the http stack".to_string(),
539 ),
540 });
541 }
542 self.writing = Some(data.into());
543 Ok(())
544 }
545
546 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
547 fn send_id(&self) -> StreamId {
548 let num: u64 = self.stream.id().into();
549 num.try_into().expect("invalid stream id")
550 }
551}
552
553impl<B> quic::SendStreamUnframed<B> for SendStream<B>
554where
555 B: Buf,
556{
557 #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))]
558 fn poll_send<D: Buf>(
559 &mut self,
560 cx: &mut task::Context<'_>,
561 buf: &mut D,
562 ) -> Poll<Result<usize, StreamErrorIncoming>> {
563 if self.writing.is_some() {
564 panic!("poll_send called while send stream is not ready")
566 }
567
568 let s = Pin::new(&mut self.stream);
569
570 let res = ready!(s.poll_write(cx, buf.chunk()));
571 match res {
572 Ok(written) => {
573 buf.advance(written);
574 Poll::Ready(Ok(written))
575 }
576 Err(err) => Poll::Ready(Err(convert_write_error_to_stream_error(err))),
577 }
578 }
579}