1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//! Utilities for networking.

use std::task::Poll;

pub mod http;
pub mod proxy;
pub mod retry;
pub mod sleep;

pub trait PollExt<T> {
    fn expect(self, msg: &str) -> T;
}

impl<T> PollExt<T> for Poll<T> {
    #[track_caller]
    fn expect(self, msg: &str) -> T {
        match self {
            Poll::Ready(val) => val,
            Poll::Pending => panic!("{}", msg),
        }
    }
}

/// When dynamically linked against libcurl, we want to ignore some failures
/// when using old versions that don't support certain features.
#[macro_export]
macro_rules! try_old_curl {
    ($e:expr, $msg:expr) => {
        let result = $e;
        if cfg!(target_os = "macos") {
            if let Err(e) = result {
                ::tracing::warn!(target: "network", "ignoring libcurl {} error: {}", $msg, e);
            }
        } else {
            use ::anyhow::Context;
            result.with_context(|| {
                ::anyhow::format_err!("failed to enable {}, is curl not built right?", $msg)
            })?;
        }
    };
}

/// Enable HTTP/2 and pipewait to be used as it'll allow true multiplexing
/// which makes downloads much faster.
///
/// Currently Cargo requests the `http2` feature of the `curl` crate which
/// means it should always be built in. On OSX, however, we ship cargo still
/// linked against the system libcurl. Building curl with ALPN support for
/// HTTP/2 requires newer versions of OSX (the SecureTransport API) than we
/// want to ship Cargo for. By linking Cargo against the system libcurl then
/// older curl installations won't use HTTP/2 but newer ones will. All that to
/// basically say we ignore errors here on OSX, but consider this a fatal error
/// to not activate HTTP/2 on all other platforms.
///
/// `pipewait` is an option which indicates that if there's a bunch of parallel
/// requests to the same host they all wait until the pipelining status of the
/// host is known. This means that we won't initiate dozens of connections but
/// rather only one. Once the main one is opened we realized that pipelining is
/// possible and multiplexing is possible. All in all this reduces the number
/// of connections down to a more manageable state.
#[macro_export]
macro_rules! try_old_curl_http2_pipewait {
    ($multiplexing:expr, $handle:expr) => {
        if $multiplexing {
            $crate::try_old_curl!($handle.http_version(curl::easy::HttpVersion::V2), "HTTP/2");
        } else {
            $handle.http_version(curl::easy::HttpVersion::V11)?;
        }
        $crate::try_old_curl!($handle.pipewait(true), "pipewait");
    };
}