feat(http1): ClientHTTP1::Fetch follows redirects by the RFC, on a URL type
One request to an http(s) URL with redirects followed by RFC 9110 §15.4: 301, 302, 303, 307 and 308 for every method; a 303 makes the request a GET without its body and content headers, a 301 or 302 does so for a POST alone, a 307 or 308 keeps the method and the body. The Location is resolved against the sending URL by RFC 3986, a hop between http and https is allowed, Authorization, Proxy-Authorization and Cookie are dropped on a change of origin, and each hop is a client of its own, since one ClientHTTP1 is one origin. A redirect without a usable Location, to another scheme, back to a URL already visited or past maxRedirects comes back as the response, with `stop` saying why. The new :URL partition is the URL type behind it, exported: Parse, Resolve (RFC 3986 §5.2; its §5.4 examples are the test), ToString, and the pieces a request is built from. This replaces the FetchHTTP1 free function, which followed redirects the way Python's urllib did (its repeat limit, its quoting of the Location, a POST turned back on a 307) for a port that no longer needs the fidelity. Breaking: FetchHTTP1, FetchOptionsHTTP1 and FetchResultHTTP1 are gone; use ClientHTTP1::Fetch, FetchOptions and FetchResult, whose `url` is a URL and whose `limited` became `stop`.
This commit is contained in:
parent
e86c3b70a0
commit
7ee938c98e
10 changed files with 596 additions and 372 deletions
|
|
@ -8,7 +8,7 @@ using namespace Crafter;
|
|||
|
||||
extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> args) {
|
||||
// TCP, HTTP/1.1 and TLS: what every native build has.
|
||||
constexpr std::array<std::string_view, 9> networkInterfaces = {
|
||||
constexpr std::array<std::string_view, 10> networkInterfaces = {
|
||||
"interfaces/Crafter.Network",
|
||||
"interfaces/Crafter.Network-ClientTCP",
|
||||
"interfaces/Crafter.Network-ListenerTCP",
|
||||
|
|
@ -16,6 +16,7 @@ extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> a
|
|||
"interfaces/Crafter.Network-HTTP1",
|
||||
"interfaces/Crafter.Network-Stream",
|
||||
"interfaces/Crafter.Network-TLS",
|
||||
"interfaces/Crafter.Network-URL",
|
||||
"interfaces/Crafter.Network-ClientHTTP1",
|
||||
"interfaces/Crafter.Network-ListenerHTTP1",
|
||||
};
|
||||
|
|
@ -180,6 +181,7 @@ extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> a
|
|||
cfg.AddTest("ShouldBindLoopbackEphemeral").Dependencies({ &cfg });
|
||||
cfg.AddTest("ShouldTimeoutSilentHTTP1").Dependencies({ &cfg });
|
||||
cfg.AddTest("ShouldFollowRedirectsHTTP1").Dependencies({ &cfg });
|
||||
cfg.AddTest("ShouldParseURLs").Dependencies({ &cfg });
|
||||
cfg.AddTest("ShouldInteropCurlHTTP1").Dependencies({ &cfg });
|
||||
cfg.AddTest("ShouldInteropCurlHTTPS1").Dependencies({ &cfg });
|
||||
cfg.AddTest("ShouldParseHTTP1").Dependencies({ &cfg });
|
||||
|
|
|
|||
Loading…
Reference in a new issue