webtrans_quinn/
connect.rs1use webtrans_proto::{ConnectRequest, ConnectResponse, VarInt};
4
5use thiserror::Error;
6use url::Url;
7
8#[derive(Error, Debug, Clone)]
9pub enum ConnectError {
10 #[error("quic stream was closed early")]
11 UnexpectedEnd,
12
13 #[error("protocol error: {0}")]
14 ProtoError(#[from] webtrans_proto::ConnectError),
15
16 #[error("connection error")]
17 ConnectionError(#[from] quinn::ConnectionError),
18
19 #[error("read error")]
20 ReadError(#[from] quinn::ReadError),
21
22 #[error("write error")]
23 WriteError(#[from] quinn::WriteError),
24
25 #[error("http error status: {0}")]
26 ErrorStatus(http::StatusCode),
27}
28
29pub struct Connect {
30 request: ConnectRequest,
32
33 send: quinn::SendStream,
35
36 #[allow(dead_code)]
37 recv: quinn::RecvStream,
38}
39
40impl Connect {
41 pub async fn accept(conn: &quinn::Connection) -> Result<Self, ConnectError> {
42 let (send, mut recv) = conn.accept_bi().await?;
45
46 let request = webtrans_proto::ConnectRequest::read(&mut recv).await?;
47 tracing::debug!("received CONNECT request: {request:?}");
48
49 Ok(Self {
51 request,
52 send,
53 recv,
54 })
55 }
56
57 pub async fn respond(&mut self, status: http::StatusCode) -> Result<(), ConnectError> {
59 let resp = ConnectResponse { status };
60
61 tracing::debug!("sending CONNECT response: {resp:?}");
62 resp.write(&mut self.send).await?;
63
64 Ok(())
65 }
66
67 pub async fn reject(&mut self, status: http::StatusCode) -> Result<(), ConnectError> {
68 self.respond(status).await?;
69 self.send
70 .finish()
71 .map_err(|_| ConnectError::UnexpectedEnd)?;
72 let _ = self.send.stopped().await;
77 Ok(())
78 }
79
80 pub async fn open(conn: &quinn::Connection, url: Url) -> Result<Self, ConnectError> {
81 let (mut send, mut recv) = conn.open_bi().await?;
83
84 let request = ConnectRequest { url };
86
87 tracing::debug!("sending CONNECT request: {request:?}");
88 request.write(&mut send).await?;
89
90 let response = webtrans_proto::ConnectResponse::read(&mut recv).await?;
91 tracing::debug!("received CONNECT response: {response:?}");
92
93 if response.status != http::StatusCode::OK {
95 return Err(ConnectError::ErrorStatus(response.status));
96 }
97
98 Ok(Self {
99 request,
100 send,
101 recv,
102 })
103 }
104
105 pub fn session_id(&self) -> VarInt {
107 let stream_id = quinn::VarInt::from(self.send.id());
109 VarInt::try_from(stream_id.into_inner()).unwrap()
110 }
111
112 pub fn url(&self) -> &Url {
114 &self.request.url
115 }
116
117 pub(super) fn into_inner(self) -> (quinn::SendStream, quinn::RecvStream) {
118 (self.send, self.recv)
119 }
120}