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