NAME
Langertha::HTTP::Redirect - The redirect policy both HTTP backends follow: credentials stay on their origin
VERSION
version 0.505
SYNOPSIS
use Langertha::HTTP::Redirect;
# Net::Async::HTTP, one hop at a time (max_redirects => 0):
my $next = Langertha::HTTP::Redirect::next_request( $request, $response );
return $response unless $next; # not followed: the caller sees the 3xx
# LWP (Langertha::HTTP::UserAgent::redirect_ok), on the referral LWP built:
return 0 unless Langertha::HTTP::Redirect::guard_referral( $referral, $response );
DESCRIPTION
Internal module. Its interface may change without notice.
An engine puts its credential on each request for its own origin: an Authorization or x-api-key header, a ?key= query parameter. Neither HTTP client keeps it there on a redirect. LWP::UserAgent clones the request with every header (it drops only Authorization, and only since 6.83), so an x-api-key reached whatever host the server named; Net::Async::HTTP keeps the Location's query, so a server echoing the request URI (return 301 https://new.example$request_uri) sent Gemini's ?key= along (karr k374).
This module is the one policy both backends follow (Langertha::HTTP::UserAgent for LWP, Langertha::Role::AsyncHTTP for Net::Async::HTTP):
Only
GETandHEADare followed, on 301, 302, 303, 307 and 308 with aLocation— what both clients follow by default. APOST(chat, embeddings, a key in the body) is never re-sent anywhere, even through an agent whoserequests_redirectablelists it.Only to
httporhttps, and never fromhttpsdown tohttp.On the same origin (scheme, host and port) the request goes on unchanged, credential included.
CookieandHostare never carried over.http://hosttohttps://hostis another origin (the scheme differs): the credential is dropped, so a keyed GET behind an http-to-https redirect gets a 401 from the https side. Configure the engine with thehttpsURL.To another origin only the representation headers go along (
Accept,Accept-Charset,Accept-Encoding,Accept-Language,Content-Type,Content-Language,User-Agent) — every other header is dropped, so an auth header of any name stays behind without a list of names to keep up to date. Userinfo is dropped from the new URL. Every query parameter whose value is a credential the chain of requests carried (a query value under a credential-like name such askey, or a credential-like header's value, without itsBearer/Basicscheme) is removed; the target's own query is otherwise kept byte for byte. If such a credential would still be in the new URL (in its path, say), the redirect is not followed.
A redirect that is not followed leaves the 3xx response to the caller, which then fails with its status line like any other non-success response. When this policy refused it, the response carries a Client-Warning header saying why (redirect not followed: Langertha::HTTP::Redirect: ...); so does the last 3xx when the hop limit ran out on Net::Async::HTTP.
same_origin
Langertha::HTTP::Redirect::same_origin( $uri_a, $uri_b ); # 1 or 0
True when both URLs have the same scheme, host and port (compared case-insensitively, a default port equal to its explicit number).
next_request
my $next = Langertha::HTTP::Redirect::next_request( $request, $response );
my $next = Langertha::HTTP::Redirect::next_request( $request, $response, $pinned_host );
The request to send for the redirect $response to $request, or undef when it is not followed. $request is not modified. The chain of earlier responses ($response->previous) is searched for credentials too. $pinned_host is passed on to "guard_referral".
guard_referral
my $follow = Langertha::HTTP::Redirect::guard_referral( $referral, $response );
my $follow = Langertha::HTTP::Redirect::guard_referral( $referral, $response, $pinned_host );
Applies the policy to $referral, the request about to be sent for the redirect $response (whose request is the hop it answers). Returns false when the redirect must not be followed, and then adds a Client-Warning header naming the reason to $response (redirect not followed: Langertha::HTTP::Redirect: ...); otherwise strips $referral in place if it goes to another origin and returns true. The method checked is the one of $response->request, so a POST is refused even when an agent's requests_redirectable would allow it.
When $pinned_host is given (the host of an engine's "connect_address" in Langertha::Role::HTTP), a redirect from that host to any other host is refused too (connect_address pins ...; not to another host): the pinned address was checked for that host only. A redirect staying on the host, on any port, is decided as usual and connects to the pinned address again.
SUPPORT
Issues
Please report bugs and feature requests at https://github.com/Getty/langertha/issues.
IRC
Join #langertha on irc.perl.org or message Getty directly.
CONTRIBUTING
Contributions are welcome! Please fork the repository and submit a pull request.
AUTHOR
Torsten Raudssus <getty@cpan.org>
COPYRIGHT AND LICENSE
This software is copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.