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}