h3/client/builder.rs
1//! HTTP/3 client builder
2
3use std::{
4 marker::PhantomData,
5 sync::{atomic::AtomicUsize, Arc},
6};
7
8use bytes::{Buf, Bytes};
9
10use crate::{
11 config::Config,
12 connection::ConnectionInner,
13 error::ConnectionError,
14 quic::{self},
15 shared_state::SharedState,
16};
17
18use super::connection::{Connection, SendRequest};
19
20/// Start building a new HTTP/3 client
21pub fn builder() -> Builder {
22 Builder::new()
23}
24
25/// Create a new HTTP/3 client with default settings
26pub async fn new<C, O>(
27 conn: C,
28) -> Result<(Connection<C, Bytes>, SendRequest<O, Bytes>), ConnectionError>
29where
30 C: quic::Connection<Bytes, OpenStreams = O>,
31 O: quic::OpenStreams<Bytes>,
32{
33 //= https://www.rfc-editor.org/rfc/rfc9114#section-3.3
34 //= type=implication
35 //# Clients SHOULD NOT open more than one HTTP/3 connection to a given IP
36 //# address and UDP port, where the IP address and port might be derived
37 //# from a URI, a selected alternative service ([ALTSVC]), a configured
38 //# proxy, or name resolution of any of these.
39 Builder::new().build(conn).await
40}
41
42/// HTTP/3 client builder
43///
44/// Set the configuration for a new client.
45///
46/// # Examples
47/// ```rust
48/// # use h3::quic;
49/// # async fn doc<C, O, B>(quic: C)
50/// # where
51/// # C: quic::Connection<B, OpenStreams = O>,
52/// # O: quic::OpenStreams<B>,
53/// # B: bytes::Buf,
54/// # {
55/// let h3_conn = h3::client::builder()
56/// .max_field_section_size(8192)
57/// .build(quic)
58/// .await
59/// .expect("Failed to build connection");
60/// # }
61/// ```
62pub struct Builder {
63 config: Config,
64}
65
66impl Builder {
67 pub(super) fn new() -> Self {
68 Builder {
69 config: Default::default(),
70 }
71 }
72
73 // Not public API, just used in unit tests
74 #[doc(hidden)]
75 #[cfg(test)]
76 pub fn send_settings(&mut self, value: bool) -> &mut Self {
77 self.config.send_settings = value;
78 self
79 }
80
81 /// Set the maximum header size this client is willing to accept
82 ///
83 /// See [header size constraints] section of the specification for details.
84 ///
85 /// [header size constraints]: https://www.rfc-editor.org/rfc/rfc9114.html#name-header-size-constraints
86 pub fn max_field_section_size(&mut self, value: u64) -> &mut Self {
87 self.config.settings.max_field_section_size = value;
88 self
89 }
90
91 /// Just like in HTTP/2, HTTP/3 also uses the concept of "grease"
92 /// to prevent potential interoperability issues in the future.
93 /// In HTTP/3, the concept of grease is used to ensure that the protocol can evolve
94 /// and accommodate future changes without breaking existing implementations.
95 pub fn send_grease(&mut self, enabled: bool) -> &mut Self {
96 self.config.send_grease = enabled;
97 self
98 }
99
100 /// Indicates that the client supports HTTP/3 datagrams
101 ///
102 /// See: <https://www.rfc-editor.org/rfc/rfc9297#section-2.1.1>
103 pub fn enable_datagram(&mut self, enabled: bool) -> &mut Self {
104 self.config.settings.enable_datagram = enabled;
105 self
106 }
107
108 /// Enables the extended CONNECT protocol required for various HTTP/3 extensions.
109 pub fn enable_extended_connect(&mut self, value: bool) -> &mut Self {
110 self.config.settings.enable_extended_connect = value;
111 self
112 }
113
114 /// Create a new HTTP/3 client from a `quic` connection
115 pub async fn build<C, O, B>(
116 &mut self,
117 quic: C,
118 ) -> Result<(Connection<C, B>, SendRequest<O, B>), ConnectionError>
119 where
120 C: quic::Connection<B, OpenStreams = O>,
121 O: quic::OpenStreams<B>,
122 B: Buf,
123 {
124 let open = quic.opener();
125 let shared = SharedState::default();
126
127 let conn_state = Arc::new(shared);
128
129 let inner = ConnectionInner::new(quic, conn_state.clone(), self.config).await?;
130 let send_request = SendRequest {
131 open,
132 conn_state,
133 max_field_section_size: self.config.settings.max_field_section_size,
134 sender_count: Arc::new(AtomicUsize::new(1)),
135 send_grease_frame: self.config.send_grease,
136 _buf: PhantomData,
137 };
138
139 Ok((
140 Connection {
141 inner,
142 sent_closing: None,
143 recv_closing: None,
144 },
145 send_request,
146 ))
147 }
148}