Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,22 @@ Platform support: the Apple (`NSURLSession`) and Linux (`libcurl`) backends popu
these accessors today; the Windows and Android backends currently always report
empty/zero (contributions welcome — the plumbing in `UrlRequest_Base.h` is shared).

## HTTP versions

`UrlRequest` opts each backend into the newest HTTP version the platform stack supports,
negotiating downward automatically — application code never has to care, and plain
`http://` / `file://` requests are unaffected.

| Platform | Backend | HTTP/2 | HTTP/3 (QUIC) |
|---|---|---|---|
| macOS / iOS | `NSURLSession` | automatic (ALPN) since macOS 10.11 / iOS 9 | attempted per request via `assumesHTTP3Capable` on macOS 11.3+ / iOS 14.5+; races QUIC vs TCP with fallback |
| Linux | libcurl | `CURL_HTTP_VERSION_2TLS` when the runtime curl has nghttp2 (all mainstream distros) | `CURL_HTTP_VERSION_3` (with fallback) when the runtime curl ≥ 8.0 reports `CURL_VERSION_HTTP3` (e.g. Fedora today; other distros as they enable it) |
| Windows (Win32 + UWP) | `Windows.Web.Http` | `HttpBaseProtocolFilter.MaxVersion = Http20`, negotiated via ALPN; requires Windows 10 1607+ | not exposed by `Windows.Web.Http` (`HttpVersion` caps at `Http20`); planned via a WinHTTP-based backend, which no-ops the h3 flag before Windows 11 and negotiates down |
| Android | `java.net.HttpURLConnection` | not supported by the platform stack (HTTP/1.1 only) | planned via embedded Cronet (h2 + h3 + Brotli); Quest 1 (Android 10) and Pico 4 (Android 10) clear Cronet's Android 8 minimum |

The Linux detection is at runtime, so the same binary lights up h3 when the system curl
gains it. No UrlLib build options are required.

## Contributing

Please read [CONTRIBUTING.md](./CONTRIBUTING.md) for details on our code of conduct, and
Expand Down
22 changes: 22 additions & 0 deletions Source/UrlRequest_Apple.mm
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,28 @@ void Open(UrlMethod method, const std::string& url)
mutableRequest.HTTPBody = requestBodyData;
}

// HTTP/3 (QUIC) is TLS-only, so restrict the opt-in to https:// (app:// has been
// rewritten to file:// by now, and file:///http:// gain nothing). HTTP/2 has been
// automatic via ALPN since iOS 9 / macOS 10.11 and needs no opt-in.
//
// The #if guards compilation on the *SDK* version: assumesHTTP3Capable was added in
// the macOS 11.3 / iOS 14.5 SDKs, and @available only gates the runtime deployment
// target -- referencing the property against an older SDK is a hard compile error.
// Together: #if keeps it out of older-SDK builds, @available keeps it off older OSes.
if ([m_url.scheme caseInsensitiveCompare:@"https"] == NSOrderedSame)
{
#if (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 110300) || \
(defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140500)
if (@available(macOS 11.3, iOS 14.5, *))
{
// Attempt h3 for this request directly rather than waiting to learn support
// from a prior response's Alt-Svc header; the stack races QUIC against TCP
// and falls back to h2/h1.1 when the server lacks h3.
mutableRequest.assumesHTTP3Capable = YES;
}
#endif
}

request = [mutableRequest copy];

__block arcana::task_completion_source<void, std::exception_ptr> taskCompletionSource{};
Expand Down
37 changes: 37 additions & 0 deletions Source/UrlRequest_Unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,43 @@ namespace UrlLib
// Request-specific failure detail (host/port/path specifics) lands here during
// the transfer; see the error handling in PerformAsync.
curl_check(curl_easy_setopt(m_curl, CURLOPT_ERRORBUFFER, m_curlErrorBuffer.data()));

// HTTP/2 and HTTP/3 are TLS-only, so only opt https:// transfers into a newer
// version; file://, app:// (rewritten to file above), and plain http:// keep
// libcurl's default. The version this build supports is detected at runtime so
// the same binary upgrades transparently with the system curl, and every value
// negotiates downward when the server or transport lacks support.
//
// The compile-time guards below key off LIBCURL_VERSION_NUM (a real macro from
// curlver.h) rather than the CURL_HTTP_VERSION_* constants: those are enum
// values, invisible to the preprocessor, so `#if defined(CURL_HTTP_VERSION_3)`
// would silently always be false. CURL_HTTP_VERSION_2TLS arrived in 7.47.0 and
// CURL_HTTP_VERSION_3 in 7.66.0.
if (scheme != nullptr && std::strcmp(scheme, "https") == 0)
{
const auto* versionInfo = curl_version_info(CURLVERSION_NOW);
long httpVersion = CURL_HTTP_VERSION_NONE;
#if LIBCURL_VERSION_NUM >= 0x074200 /* 7.66.0 */
// HTTP/3 with fallback. The runtime >= 8.0.0 gate matters because earlier
// curls treat CURL_HTTP_VERSION_3 as h3-or-fail instead of h3-with-fallback.
if ((versionInfo->features & CURL_VERSION_HTTP3) && versionInfo->version_num >= 0x080000)
{
httpVersion = CURL_HTTP_VERSION_3;
}
else
#endif
#if LIBCURL_VERSION_NUM >= 0x072F00 /* 7.47.0 */
if (versionInfo->features & CURL_VERSION_HTTP2)
{
// HTTP/2 over TLS via ALPN, HTTP/1.1 otherwise.
httpVersion = CURL_HTTP_VERSION_2TLS;
}
#endif
if (httpVersion != CURL_HTTP_VERSION_NONE)
{
curl_check(curl_easy_setopt(m_curl, CURLOPT_HTTP_VERSION, httpVersion));
}
}
}
}

Expand Down
9 changes: 8 additions & 1 deletion Source/UrlRequest_Windows_Shared.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <robuffer.h>
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Windows.Web.Http.h>
#include <winrt/Windows.Web.Http.Filters.h>
#include <winrt/Windows.ApplicationModel.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Web.Http.Headers.h>
Expand Down Expand Up @@ -95,7 +96,13 @@ namespace UrlLib
);
}

Web::Http::HttpClient client;
// Explicitly allow HTTP/2 (negotiated via ALPN for https, supported since
// Windows 10 1607) rather than relying on the OS-build default for MaxVersion.
// HTTP/3 has no knob in Windows.Web.Http -- HttpVersion caps at Http20; it
// arrives with a WinHTTP-based backend (see the Readme's HTTP versions matrix).
Web::Http::Filters::HttpBaseProtocolFilter filter;
filter.MaxVersion(Web::Http::HttpVersion::Http20);
Web::Http::HttpClient client{filter};
return arcana::create_task<std::exception_ptr>(client.SendRequestAsync(requestMessage))
.then(arcana::inline_scheduler, m_cancellationSource, [this](Web::Http::HttpResponseMessage responseMessage)
{
Expand Down