Skip to content

Commit 42f57b4

Browse files
authored
Fix panic in building h3 client when udp is forbidden (#1945)
Fixed #1942 Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
1 parent 4aa8516 commit 42f57b4

File tree

2 files changed

+90
-60
lines changed

2 files changed

+90
-60
lines changed

src/async_impl/client.rs

Lines changed: 87 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,55 @@ impl ClientBuilder {
281281
}
282282
let http = HttpConnector::new_with_resolver(DynResolver::new(resolver.clone()));
283283

284+
#[cfg(all(feature = "http3", feature = "__rustls"))]
285+
let build_h3_connector =
286+
|resolver,
287+
tls,
288+
quic_max_idle_timeout: Option<Duration>,
289+
quic_stream_receive_window,
290+
quic_receive_window,
291+
quic_send_window,
292+
local_address,
293+
http_version_pref: &HttpVersionPref| {
294+
let mut transport_config = TransportConfig::default();
295+
296+
if let Some(max_idle_timeout) = quic_max_idle_timeout {
297+
transport_config.max_idle_timeout(Some(
298+
max_idle_timeout.try_into().map_err(error::builder)?,
299+
));
300+
}
301+
302+
if let Some(stream_receive_window) = quic_stream_receive_window {
303+
transport_config.stream_receive_window(stream_receive_window);
304+
}
305+
306+
if let Some(receive_window) = quic_receive_window {
307+
transport_config.receive_window(receive_window);
308+
}
309+
310+
if let Some(send_window) = quic_send_window {
311+
transport_config.send_window(send_window);
312+
}
313+
314+
let res = H3Connector::new(
315+
DynResolver::new(resolver),
316+
tls,
317+
local_address,
318+
transport_config,
319+
);
320+
321+
match res {
322+
Ok(connector) => Ok(Some(connector)),
323+
Err(err) => {
324+
if let HttpVersionPref::Http3 = http_version_pref {
325+
Err(error::builder(err))
326+
} else {
327+
Ok(None)
328+
}
329+
}
330+
}
331+
};
332+
284333
#[cfg(feature = "__tls")]
285334
match config.tls {
286335
#[cfg(feature = "default-tls")]
@@ -367,32 +416,16 @@ impl ClientBuilder {
367416
TlsBackend::BuiltRustls(conn) => {
368417
#[cfg(feature = "http3")]
369418
{
370-
let mut transport_config = TransportConfig::default();
371-
372-
if let Some(max_idle_timeout) = config.quic_max_idle_timeout {
373-
transport_config.max_idle_timeout(Some(
374-
max_idle_timeout.try_into().map_err(error::builder)?,
375-
));
376-
}
377-
378-
if let Some(stream_receive_window) = config.quic_stream_receive_window {
379-
transport_config.stream_receive_window(stream_receive_window);
380-
}
381-
382-
if let Some(receive_window) = config.quic_receive_window {
383-
transport_config.receive_window(receive_window);
384-
}
385-
386-
if let Some(send_window) = config.quic_send_window {
387-
transport_config.send_window(send_window);
388-
}
389-
390-
h3_connector = Some(H3Connector::new(
391-
DynResolver::new(resolver),
419+
h3_connector = build_h3_connector(
420+
resolver,
392421
conn.clone(),
422+
config.quic_max_idle_timeout,
423+
config.quic_stream_receive_window,
424+
config.quic_receive_window,
425+
config.quic_send_window,
393426
config.local_address,
394-
transport_config,
395-
));
427+
&config.http_version_pref,
428+
)?;
396429
}
397430

398431
Connector::new_rustls_tls(
@@ -527,32 +560,16 @@ impl ClientBuilder {
527560
{
528561
tls.enable_early_data = config.tls_enable_early_data;
529562

530-
let mut transport_config = TransportConfig::default();
531-
532-
if let Some(max_idle_timeout) = config.quic_max_idle_timeout {
533-
transport_config.max_idle_timeout(Some(
534-
max_idle_timeout.try_into().map_err(error::builder)?,
535-
));
536-
}
537-
538-
if let Some(stream_receive_window) = config.quic_stream_receive_window {
539-
transport_config.stream_receive_window(stream_receive_window);
540-
}
541-
542-
if let Some(receive_window) = config.quic_receive_window {
543-
transport_config.receive_window(receive_window);
544-
}
545-
546-
if let Some(send_window) = config.quic_send_window {
547-
transport_config.send_window(send_window);
548-
}
549-
550-
h3_connector = Some(H3Connector::new(
551-
DynResolver::new(resolver),
563+
h3_connector = build_h3_connector(
564+
resolver,
552565
tls.clone(),
566+
config.quic_max_idle_timeout,
567+
config.quic_stream_receive_window,
568+
config.quic_receive_window,
569+
config.quic_send_window,
553570
config.local_address,
554-
transport_config,
555-
));
571+
&config.http_version_pref,
572+
)?;
556573
}
557574

558575
Connector::new_rustls_tls(
@@ -639,11 +656,15 @@ impl ClientBuilder {
639656
accepts: config.accepts,
640657
#[cfg(feature = "cookies")]
641658
cookie_store: config.cookie_store,
659+
// Use match instead of map since config is partially moved
660+
// and it cannot be used in closure
642661
#[cfg(feature = "http3")]
643-
h3_client: H3Client::new(
644-
h3_connector.expect("missing HTTP/3 connector"),
645-
config.pool_idle_timeout,
646-
),
662+
h3_client: match h3_connector {
663+
Some(h3_connector) => {
664+
Some(H3Client::new(h3_connector, config.pool_idle_timeout))
665+
}
666+
None => None,
667+
},
647668
hyper: builder.build(connector),
648669
headers: config.headers,
649670
redirect_policy: config.redirect_policy,
@@ -1759,10 +1780,10 @@ impl Client {
17591780

17601781
let in_flight = match version {
17611782
#[cfg(feature = "http3")]
1762-
http::Version::HTTP_3 => {
1783+
http::Version::HTTP_3 if self.inner.h3_client.is_some() => {
17631784
let mut req = builder.body(body).expect("valid request parts");
17641785
*req.headers_mut() = headers.clone();
1765-
ResponseFuture::H3(self.inner.h3_client.request(req))
1786+
ResponseFuture::H3(self.inner.h3_client.as_ref().unwrap().request(req))
17661787
}
17671788
_ => {
17681789
let mut req = builder
@@ -1986,7 +2007,7 @@ struct ClientRef {
19862007
headers: HeaderMap,
19872008
hyper: HyperClient,
19882009
#[cfg(feature = "http3")]
1989-
h3_client: H3Client,
2010+
h3_client: Option<H3Client>,
19902011
redirect_policy: redirect::Policy,
19912012
referer: bool,
19922013
request_timeout: Option<Duration>,
@@ -2117,7 +2138,13 @@ impl PendingRequest {
21172138
.body(body)
21182139
.expect("valid request parts");
21192140
*req.headers_mut() = self.headers.clone();
2120-
ResponseFuture::H3(self.client.h3_client.request(req))
2141+
ResponseFuture::H3(
2142+
self.client
2143+
.h3_client
2144+
.as_ref()
2145+
.expect("H3 client must exists, otherwise we can't have a h3 request here")
2146+
.request(req),
2147+
)
21212148
}
21222149
_ => {
21232150
let mut req = hyper::Request::builder()
@@ -2339,7 +2366,10 @@ impl Future for PendingRequest {
23392366
.expect("valid request parts");
23402367
*req.headers_mut() = headers.clone();
23412368
std::mem::swap(self.as_mut().headers(), &mut headers);
2342-
ResponseFuture::H3(self.client.h3_client.request(req))
2369+
ResponseFuture::H3(self.client.h3_client
2370+
.as_ref()
2371+
.expect("H3 client must exists, otherwise we can't have a h3 request here")
2372+
.request(req))
23432373
}
23442374
_ => {
23452375
let mut req = hyper::Request::builder()

src/async_impl/h3_client/connect.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ impl H3Connector {
2828
tls: rustls::ClientConfig,
2929
local_addr: Option<IpAddr>,
3030
transport_config: TransportConfig,
31-
) -> H3Connector {
31+
) -> Result<H3Connector, BoxError> {
3232
let mut config = ClientConfig::new(Arc::new(tls));
3333
// FIXME: Replace this when there is a setter.
3434
config.transport_config(Arc::new(transport_config));
@@ -38,10 +38,10 @@ impl H3Connector {
3838
None => "[::]:0".parse::<SocketAddr>().unwrap(),
3939
};
4040

41-
let mut endpoint = Endpoint::client(socket_addr).expect("unable to create QUIC endpoint");
41+
let mut endpoint = Endpoint::client(socket_addr)?;
4242
endpoint.set_default_client_config(config);
4343

44-
Self { resolver, endpoint }
44+
Ok(Self { resolver, endpoint })
4545
}
4646

4747
pub async fn connect(&mut self, dest: Uri) -> Result<H3Connection, BoxError> {

0 commit comments

Comments
 (0)