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