silk.http.redirect.
Follow HTTP redirects with a Policy: which statuses to follow, how the method and the body
change, which origins are allowed, and which headers are kept.
When to use#
Most programs set a Policy in FetchOptions of silk.http.fetch. Use the with*Response
functions to follow redirects with your own AttemptClient. Use statusDecision,
transition, resolveLocation, admitOrigin, History, and sanitizeHeaders to
build your own redirect loop.
Details#
For each response, statusDecision decides if it is a redirect. transition selects the
next method and whether the body is sent again:
303 changes the method to GET, or keeps HEAD, and drops the body.
301 and 302 change POST to GET and drop the body when
post301302isToGet.All other cases keep the method and the body.
resolveLocation reads the Location field. admitOrigin applies the cross-origin and
downgrade rules. History finds loops. sanitizeHeaders removes headers that must not go
to the next request.
The suffix of a with*Response function tells what the request body is, as in
silk.http.fetch: Empty, Bytes, OneShot, or Replay. The Hybrid forms take a client
that can connect through a proxy route or directly.
Errors#
RedirectErrortells the part, the reason, and the URIs and status, when they are known. It holds no credentials or body.
Gotchas#
The default Policy does not follow redirects. It denies a change of origin and a change from
HTTPS to HTTP. A OneShot body cannot be sent again, so a redirect that keeps the body fails
with ReplayUnavailable.
Examples#
Apply redirect rules#
import silk.http.message { Method, Status, ValueError }
import silk.http.origin { Origin, OriginError }
import silk.http.redirect {
BodyDecision,
CrossOriginPolicy,
DowngradePolicy,
Mode,
NameList,
Policy,
Post301302Policy,
PreviousResponsePolicy,
RedirectError,
RedirectReason,
StatusDecision,
Transition,
admitOrigin,
statusDecision,
transition
}
import silk.core.result { Result }
import silk.uri.uri { Uri }
import silk.uri.reference { ParseError }
fn status(code: u16) -> Status {
return match Status.fromCode(code) {
Result<Status, ValueError>.Success { value } => value
Result<Status, ValueError>.Failure { error: _ } => {
Intrinsic.trap("unexpected failure")
return status(code)
}
}
}
fn origin(text: string<'static>) -> Origin {
let uri = match Uri.parse(text) {
Result<Uri, ParseError>.Success { value } => value
Result<Uri, ParseError>.Failure { error: _ } => {
Intrinsic.trap("unexpected failure")
return origin(text)
}
}
return match Origin.fromUri(&uri) {
Result<Origin, OriginError>.Success { value } => value
Result<Origin, OriginError>.Failure { error: _ } => {
Intrinsic.trap("unexpected failure")
return origin(text)
}
}
}
pub fn main() -> i32 {
let defaults = Policy.defaults()
let policy = match Policy.make(
Mode.Follow,
Policy.historyLimits(&defaults),
CrossOriginPolicy.Allow,
DowngradePolicy.Deny,
Post301302Policy.ToGet,
PreviousResponsePolicy.Close,
NameList.empty(),
NameList.empty(),
) {
Result<Policy, RedirectError>.Success { value } => move value
Result<Policy, RedirectError>.Failure { error: _ } => {
return 1
}
}
// 303 is a redirect. It changes POST to GET and drops the body.
let decision = match statusDecision(&policy, status(303), 0) {
Result<StatusDecision, RedirectError>.Success { value } => value
Result<StatusDecision, RedirectError>.Failure { error: _ } => {
return 1
}
}
let seeOther = transition(&policy, status(303), Method.post())
if decision != StatusDecision.Redirect || Method.format(&seeOther.method) != "GET"
|| seeOther.body != BodyDecision.Drop {
return 1
}
// 307 keeps the method and the body.
let temporary = transition(&policy, status(307), Method.post())
if Method.format(&temporary.method) != "POST" || temporary.body != BodyDecision.Retain {
return 1
}
// A redirect from HTTPS to HTTP fails.
let downgrade = match admitOrigin(
&policy,
&origin("https://example.com/"),
&origin("http://example.com/"),
0,
status(302),
) {
Result<bool, RedirectError>.Success { value: _ } => false
Result<bool, RedirectError>.Failure { error } => match error.reason {
RedirectReason.DowngradeDenied => true
_ => false
}
}
if !downgrade {
return 1
}
return 0
}Import as Redirect with import silk.http.redirect as Redirect.
Public declarations: 48.
Mode#
pub enum ModeWhether to follow redirects.
Manual#
ManualReturn the first response. Location is not read.
Follow#
FollowFollow redirects by the policy.
CrossOriginPolicy#
pub enum CrossOriginPolicyWhether a redirect can go to another origin.
Deny#
DenyA redirect to another origin fails with RedirectOriginDenied.
Allow#
AllowA redirect to another origin is followed. Sensitive headers are removed first.
DowngradePolicy#
pub enum DowngradePolicyWhether a redirect can go from HTTPS to HTTP.
Deny#
DenyA redirect from HTTPS to HTTP fails with DowngradeDenied.
Allow#
AllowA redirect from HTTPS to HTTP is followed, if the cross-origin policy allows it.
Post301302Policy#
pub enum Post301302PolicyWhat a 301 or 302 redirect does with a POST request.
Preserve#
PreserveSend POST again, with the body.
ToGet#
ToGetSend GET without the body, as browsers do.
PreviousResponsePolicy#
pub union PreviousResponsePolicyWhat to do with the body of a redirect response before the next request.
Close#
CloseDo not read it. The connection closes if the body is not complete.
Drain#
DrainRead and drop the body, up to a limit, so that the connection can be used again.
Field maxDiscardWireBytes#
pub maxDiscardWireBytes: u64The maximum bytes to read.
Field deadline#
pub deadline: InstantThe deadline of the drain on the MonotonicClock. The deadline of the operation also
applies.
NameListLimits#
pub struct NameListLimitsThe limits of a NameList.
Field maxNames#
pub maxNames: usizeThe maximum number of names.
Field maxNameBytes#
pub maxNameBytes: usizeThe maximum length of one name.
Field maxOwnedBytes#
pub maxOwnedBytes: usizeThe maximum memory of the list, in bytes.
Implementation Copy for NameListLimits#
impl Copy for NameListLimitsNameList#
pub struct NameListA list of header names, compared without case.
HistoryLimits#
pub struct HistoryLimitsThe limits of a redirect operation.
Field maxHops#
pub maxHops: usizeThe maximum number of redirects to follow.
Field maxUriBytes#
pub maxUriBytes: usizeThe maximum length of a Location value and of a resolved URI.
Field maxHistoryBytes#
pub maxHistoryBytes: usizeThe maximum memory of the History, in bytes.
Implementation Copy for HistoryLimits#
impl Copy for HistoryLimitsPolicy#
pub struct PolicyThe redirect rules: which statuses to follow, how the method and the body change, which origins
are allowed, and which headers are kept. Start from Policy.defaults, or make one with
Policy.make.
Details#
A 303 changes the method to GET, or keeps HEAD, and drops the body. A 301 or 302 changes POST to
GET and drops the body when post301302 is ToGet. All other cases keep the method and the
body.
Gotchas#
The default policy does not follow redirects. It denies a change of origin and a change from HTTPS to HTTP.
RedirectComponent#
pub enum RedirectComponentThe part of a redirect where an error occurred.
Policy#
PolicyThe policy.
Location#
LocationThe Location field.
Uri#
UriThe next URI.
Origin#
OriginThe next origin.
History#
HistoryThe redirect history.
Body#
BodyThe request body.
Implementation Debug for RedirectComponent#
impl Debug for RedirectComponentOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as Policy.
RedirectLimit#
pub enum RedirectLimitThe limit that was exceeded.
PolicyNames#
PolicyNamesmaxNames of a name list.
PolicyNameBytes#
PolicyNameBytesmaxNameBytes of a name list.
PolicyOwnedBytes#
PolicyOwnedBytesmaxOwnedBytes of a name list.
UriBytes#
UriBytesmaxUriBytes.
HistoryEntries#
HistoryEntriesThe number of history entries, maxHops plus 1.
HistoryBytes#
HistoryBytesmaxHistoryBytes.
Implementation Debug for RedirectLimit#
impl Debug for RedirectLimitOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as PolicyNames.
RedirectReason#
pub union RedirectReasonThe reason of a RedirectError.
InvalidPolicy#
InvalidPolicyThe policy is not valid, for example maxHops plus 1 overflows.
NameListOverlap#
NameListOverlapA name is in both the safe list and the sensitive list.
SizeOverflow#
SizeOverflowA size does not fit in usize.
LimitExceeded#
LimitExceededA limit was exceeded.
Field limit#
pub limit: RedirectLimitThe limit.
Field allowed#
pub allowed: usizeThe value of the limit.
Field attempted#
pub attempted: usizeThe value that was found.
LocationMissing#
LocationMissingThe redirect has no Location field.
LocationAmbiguous#
LocationAmbiguousThe redirect has more than one Location field.
LocationInvalid#
LocationInvalidThe Location value is not UTF-8, or is not a valid URI reference.
RedirectSchemeDenied#
RedirectSchemeDeniedThe next URI is not http or https, or has no host or has user information.
RedirectOriginDenied#
RedirectOriginDeniedThe policy does not allow a change of origin.
DowngradeDenied#
DowngradeDeniedThe policy does not allow a change from HTTPS to HTTP.
HopLimit#
HopLimitThere are more redirects than maxHops.
RedirectLoop#
RedirectLoopThe next request has the same method and URI as an earlier request.
ReplayUnavailable#
ReplayUnavailableThe redirect keeps the body, but the body cannot be sent again.
ReplayContractMismatch#
ReplayContractMismatchA body producer sent another length or framing than its mode said.
Implementation Copy for RedirectReason#
impl Copy for RedirectReasonImplementation Debug for RedirectReason#
impl Debug for RedirectReasonOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant and its fields, such as InvalidPolicy.
RedirectContext#
pub struct RedirectContextThe context of a RedirectError. It owns its data.
Field hop#
pub hop: usizeThe number of the attempt, from 0.
Field status#
pub status: Option<Status>The status of the response, when it is known.
Field currentUri#
pub currentUri: Option<OwnedUri>A copy of the current URI, when it is known.
Field nextUri#
pub nextUri: Option<OwnedUri>A copy of the next URI, when it is known.
Implementation Debug for RedirectContext#
impl Debug for RedirectContextOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the fields, as RedirectContext { hop: ..., status: ..., ... }.
RedirectError#
pub struct RedirectErrorThe error from a redirect. It holds no response, credentials, or body.
Details#
It tells the part, the reason, and the URIs and status, when they are known.
Field component#
pub component: RedirectComponentThe part where the error occurred.
Field reason#
pub reason: RedirectReasonThe reason.
Field context#
pub context: RedirectContextThe URIs and the status.
Implementation Debug for RedirectError#
impl Debug for RedirectErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the fields, as RedirectError { component: ..., reason: ..., ... }.
Request#
pub struct Request<'uri, 'method, 'headers, 'policy>A request that can be built again for each redirect. It does not hold the body.
Field uri#
pub uri: Uri<'uri>The first URI. Its fragment is kept for later URIs that have none.
Field method#
pub method: Method<'method>The first method.
Field headers#
pub headers: Headers<'headers>Your headers, without the fields that the policy and the body make.
Field headerPolicy#
pub headerPolicy: HeaderPolicy<'policy>The policy for the fields that the request adds, and the credentials.
Field version#
pub version: VersionThe HTTP version of all attempts.
Field continuePolicy#
pub continuePolicy: ContinuePolicyWhether all attempts wait for 100 Continue.
Field limits#
pub limits: HeaderLimitsThe limits of the values and fields.
Field maxHeadBytes#
pub maxHeadBytes: usizeThe maximum size of each request head.
Field maxCredentialBytes#
pub maxCredentialBytes: usizeThe maximum size of the credentials in each request head.
AttemptRequest#
pub struct AttemptRequest<'policy>The request for one attempt, which an AttemptClient prepares and sends.
Details#
The client borrows from this value only in its handler call. It must prepare a new request after it selects the route, and never send the bytes of an earlier request to another origin.
Field uri#
pub uri: OwnedUriThe URI of this attempt. The fragment is not sent.
Field method#
pub method: StringThe method of this attempt.
Field headers#
pub headers: OwnedHeadersThe headers, after sanitizeHeaders.
Field headerPolicy#
pub headerPolicy: HeaderPolicy<'policy>The policy for the fields that the request adds, and the credentials. See
crossOriginHeaderPolicy.
Field version#
pub version: VersionThe HTTP version.
Field continuePolicy#
pub continuePolicy: ContinuePolicyWhether to wait for 100 Continue.
Field requestLimits#
pub requestLimits: HeaderLimitsThe limits of the values and fields.
Field maxHeadBytes#
pub maxHeadBytes: usizeThe maximum size of the request head.
Field maxCredentialBytes#
pub maxCredentialBytes: usizeThe maximum size of the credentials in the request head.
Field bodyMode#
pub bodyMode: BodyModeThe framing of the body of this attempt.
crossOriginHeaderPolicy#
pub fn crossOriginHeaderPolicy<'value>(policy: HeaderPolicy<'value>) -> HeaderPolicy<'value>Returns the header policy for a request to another origin, without credentials.
When to use#
Use it when admitOrigin returns true, before you prepare the request.
Details#
Host is made for the new origin, and Authorization is removed. User-Agent, Accept, the
Basic security, and the HTTP/1.0 keep-alive setting stay.
BodyChunk#
pub struct BodyChunkThe result of BodyProducer.pull.
Field length#
pub length: usizeThe number of bytes written at the start of the output.
Field end#
pub end: booltrue when there are no more bytes.
Implementation Copy for BodyChunk#
impl Copy for BodyChunkBodyProducer#
pub interface BodyProducer<E, ?R>A source of request body bytes.
Operation mode#
fn mode(producer: &Self) -> BodyModeReturns the framing of the body, before the head is sent.
Operation pull#
effect fn pull(producer: &mut Self, output: &mut [u8]) -> BodyChunk ! E ? RWrites the next bytes of the body to the start of output. It does not keep output.
ReplayFactory#
pub interface ReplayFactory<P, FactoryError, ?FactoryRequirements>Makes a new BodyProducer for each attempt that sends the body.
Details#
Each producer is released after its attempt, also after an error or a cancel. release cannot
fail or wait.
Operation acquire#
effect fn acquire(factory: &mut Self) -> P ! FactoryError ? FactoryRequirementsReturns a new producer for the next attempt.
Operation release#
fn release(factory: &mut Self, producer: &mut P) -> ()Releases a producer after its attempt.
AttemptBody#
pub union AttemptBody<'bytes, 'oneShot, 'replay, OneShot, ReplayProducer>The body of one attempt, as given to writeBody.
Empty#
EmptyNo body.
RepeatableBytes#
RepeatableBytesBytes that can be sent again from the start.
OneShot#
OneShotA producer that can run only one time.
ReplayFactory#
ReplayFactoryA new producer from a ReplayFactory.
BodyWriteOutcome#
pub union BodyWriteOutcomeThe result of writeBody.
Completed#
CompletedThe body was sent, and a final response arrived.
Field status#
pub status: u16The status of the final response.
EarlyFinal#
EarlyFinalWith Require100, a final response arrived before the body was sent.
Field status#
pub status: u16The status of the final response.
Attempt#
pub service Attempt<'policy, P, A, E, ?R>The service that an AttemptClient calls with the exchange of one attempt.
Operation handle#
effect<'call> fn handle<
'call,
'exchangeView: 'call,
'transport: 'exchangeView,
'provider: 'transport,
'tunnel: 'provider,
>(
request: &'call AttemptRequest<'policy>,
method: Method<'call>,
exchange: &'call mut Exchange<'exchangeView, RouteTransport<'transport, 'provider, 'tunnel, P>>,
) -> A ! E ? R | &mut Attempt<'policy, P, A, E, R> where
&mut P provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut P provides &HttpTransport from &mut HttpTransport,
&mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut P provides &ByteDuplex from &mut ByteDuplexHandles one live routed exchange inside its acquisition bracket.
AttemptClient#
pub interface AttemptClient<
'policy,
P,
A,
HandlerError,
AcquisitionError,
?AcquisitionRequirements,
?HandlerRequirements,
>Connects and runs one attempt of a redirect operation.
When to use#
Implement it to give your own connections to the with*Response functions. It hides the
sockets, TLS, proxy credentials, and pools from the redirect code.
Details#
withAttempt selects the route for the URI of request, prepares a new request, connects
before the deadline, and runs one withExchange of silk.http.exchange. It gives the exchange
to the redirect code through Attempt. Errors from the connection come back as
AcquisitionError.
Gotchas#
The implementation must close or release its transport after the handler returns, fails, or is cancelled. It must not keep the request, the transport, or the exchange.
Operation withAttempt#
effect fn withAttempt(
client: &mut Self,
request: AttemptRequest<'policy>,
deadline: Option<Instant>,
) -> A ! HandlerError | AcquisitionError ? HandlerRequirements | AcquisitionRequirements | &mut Attempt<'policy, P, A, HandlerError ? HandlerRequirements> where
HandlerRequirements in Without<HandlerRequirements, ByteDuplex>,
HandlerRequirements in Without<HandlerRequirements, HttpTransport>Rebuilds, acquires, and drives one scoped request while preserving both channel families.
HybridAttempt#
pub service HybridAttempt<'policy, RoutedP, DirectP, A, E, ?R>The service that a HybridAttemptClient calls with the exchange of one attempt.
Details#
A routed client calls handleRouted, and a direct client calls handleDirect. The exchange
cannot be kept after the call.
Operation handleRouted#
effect<'call> fn handleRouted<
'call,
'exchangeView: 'call,
'transport: 'exchangeView,
'provider: 'transport,
'tunnel: 'provider,
>(
request: &'call AttemptRequest<'policy>,
method: Method<'call>,
exchange: &'call mut Exchange<
'exchangeView,
RouteTransport<'transport, 'provider, 'tunnel, RoutedP>,
>,
) -> A ! E ? R | &mut HybridAttempt<'policy, RoutedP, DirectP, A, E, R> where
&mut RoutedP provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut RoutedP provides &HttpTransport from &mut HttpTransport,
&mut RoutedP provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut RoutedP provides &ByteDuplex from &mut ByteDuplexHandles the exchange of one attempt over a route.
Operation handleDirect#
effect<'call> fn handleDirect<'call, 'exchangeView: 'call>(
request: &'call AttemptRequest<'policy>,
method: Method<'call>,
exchange: &'call mut Exchange<'exchangeView, DirectP>,
) -> A ! E ? R | &mut HybridAttempt<'policy, RoutedP, DirectP, A, E, R> where
&mut DirectP provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut DirectP provides &HttpTransport from &mut HttpTransportHandles the exchange of one attempt over a direct connection.
HybridAttemptClient#
pub interface HybridAttemptClient<
'policy,
RoutedP,
DirectP,
A,
HandlerError,
AcquisitionError,
?AcquisitionRequirements,
?HandlerRequirements,
>Connects and runs one attempt of a redirect operation, over a proxy route or a direct
connection. Implement it to give your own connections to the with*HybridResponse functions.
Details#
The client selects the form before it connects, and calls one handler. A direct connection
cannot open a CONNECT tunnel.
Operation withAttempt#
effect fn withAttempt(
client: &mut Self,
request: AttemptRequest<'policy>,
deadline: Option<Instant>,
) -> A ! HandlerError | AcquisitionError ? HandlerRequirements | AcquisitionRequirements | &mut HybridAttempt<'policy, RoutedP, DirectP, A, HandlerError ? HandlerRequirements> where
HandlerRequirements in Without<HandlerRequirements, ByteDuplex>,
HandlerRequirements in Without<HandlerRequirements, HttpTransport>Rebuilds, acquires, and drives one routed or direct scoped request.
ResponseHandler#
pub interface ResponseHandler<P, A, E, ?R>Handles the final response of a redirect operation.
When to use#
Give it to a with*Response function. It reads the final response while the exchange is open.
Details#
uri is the final URI, and hop the number of redirects. The URI and the exchange cannot be
kept after the call.
Operation handle#
effect<'call> fn handle<
'call,
'exchangeView: 'call,
'transport: 'exchangeView,
'provider: 'transport,
'tunnel: 'provider,
>(
handler: &mut Self,
uri: Uri<'call>,
hop: usize,
exchange: &'call mut Exchange<'exchangeView, RouteTransport<'transport, 'provider, 'tunnel, P>>,
) -> A ! E ? R where
&mut P provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut P provides &HttpTransport from &mut HttpTransport,
&mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut P provides &ByteDuplex from &mut ByteDuplexHandles the final response.
HybridResponseHandler#
pub interface HybridResponseHandler<RoutedP, DirectP, A, E, ?R>Handles the final response of a redirect operation, over a proxy route or a direct connection. It reads the final response while the exchange is open. The URI and the exchange cannot be kept after the call.
When to use#
Give it to a with*HybridResponse function.
Operation handleRouted#
effect<'call> fn handleRouted<
'call,
'exchangeView: 'call,
'transport: 'exchangeView,
'provider: 'transport,
'tunnel: 'provider,
>(
handler: &mut Self,
uri: Uri<'call>,
hop: usize,
exchange: &'call mut Exchange<
'exchangeView,
RouteTransport<'transport, 'provider, 'tunnel, RoutedP>,
>,
) -> A ! E ? R where
&mut RoutedP provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut RoutedP provides &HttpTransport from &mut HttpTransport,
&mut RoutedP provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut RoutedP provides &ByteDuplex from &mut ByteDuplexHandles the final response over a route.
Operation handleDirect#
effect<'call> fn handleDirect<'call, 'exchangeView: 'call>(
handler: &mut Self,
uri: Uri<'call>,
hop: usize,
exchange: &'call mut Exchange<'exchangeView, DirectP>,
) -> A ! E ? R where
&mut DirectP provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut DirectP provides &HttpTransport from &mut HttpTransportHandles the final response over a direct connection.
SelectedBody#
pub service SelectedBody<E, ?R>The body of the current attempt. It exists only during the attempt.
Operation pull#
effect fn pull(output: &mut [u8]) -> BodyChunk ! E ? R | &mut SelectedBody<E, R>Writes the next bytes of the body to the start of output.
AttemptStep#
pub union AttemptStep<'policy, A>The result of one attempt. Only the redirect code makes and reads it.
Final#
FinalRedirect#
RedirectwithEmptyResponse#
pub effect<'env> fn withEmptyResponse<
'client,
'uri,
'method,
'headers,
'policy,
'scratch,
P,
A,
CallbackError,
AcquisitionError,
?CallbackRequirements,
?AcquisitionRequirements,
H: ResponseHandler<P, A, CallbackError ? CallbackRequirements> + 'env,
C: AttemptClient<'policy, P, AttemptStep<'policy, A>, RedirectError | ValueError | CallbackError | ExchangeError | OutOfMemoryError, AcquisitionError, AcquisitionRequirements ? CallbackRequirements | &mut SelectedBody<
never,
never,
> | &mut MonotonicClock | &mut Allocator | &mut Random>,
'env,
>(
client: &'client mut C,
request: Request<'uri, 'method, 'headers, 'policy>,
policy: &'policy Policy,
deadline: Option<Instant>,
scratch: &'scratch mut [u8],
handler: H,
) -> A
! RedirectError | ValueError | CallbackError | ExchangeError | OutOfMemoryError | AcquisitionError
? CallbackRequirements | AcquisitionRequirements | &mut MonotonicClock | &mut Allocator | &mut Random
where
&mut P provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut P provides &HttpTransport from &mut HttpTransport,
&mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut P provides &ByteDuplex from &mut ByteDuplex,
CallbackRequirements in Without<CallbackRequirements, ByteDuplex>,
CallbackRequirements in Without<CallbackRequirements, HttpTransport>,
AcquisitionRequirements in Without<AcquisitionRequirements, ByteDuplex>,
AcquisitionRequirements in Without<AcquisitionRequirements, HttpTransport>Follows redirects for a request without a body, and gives the final response to handler.
Details#
Each attempt is a new request with the same deadline. The body of each redirect response is
closed or drained as policy says. handler runs one time, and only if a final response
arrives.
withEmptyHybridResponse#
pub effect<'env> fn withEmptyHybridResponse<
'client,
'uri,
'method,
'headers,
'policy,
'scratch,
RoutedP,
DirectP,
A,
CallbackError,
AcquisitionError,
?CallbackRequirements,
?AcquisitionRequirements,
H: HybridResponseHandler<RoutedP, DirectP, A, CallbackError ? CallbackRequirements> + 'env,
C: HybridAttemptClient<'policy, RoutedP, DirectP, AttemptStep<'policy, A>, RedirectError | ValueError | CallbackError | ExchangeError | OutOfMemoryError, AcquisitionError, AcquisitionRequirements ? CallbackRequirements | &mut SelectedBody<
never,
never,
> | &mut MonotonicClock | &mut Allocator | &mut Random>,
'env,
>(
client: &'client mut C,
request: Request<'uri, 'method, 'headers, 'policy>,
policy: &'policy Policy,
deadline: Option<Instant>,
scratch: &'scratch mut [u8],
handler: H,
) -> A
! RedirectError | ValueError | CallbackError | ExchangeError | OutOfMemoryError | AcquisitionError
? CallbackRequirements | AcquisitionRequirements | &mut MonotonicClock | &mut Allocator | &mut Random
where
&mut RoutedP provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut RoutedP provides &HttpTransport from &mut HttpTransport,
&mut RoutedP provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut RoutedP provides &ByteDuplex from &mut ByteDuplex,
&mut DirectP provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut DirectP provides &HttpTransport from &mut HttpTransport,
CallbackRequirements in Without<CallbackRequirements, ByteDuplex>,
CallbackRequirements in Without<CallbackRequirements, HttpTransport>,
AcquisitionRequirements in Without<AcquisitionRequirements, ByteDuplex>,
AcquisitionRequirements in Without<AcquisitionRequirements, HttpTransport>Follows redirects for a request without a body, and gives the final response to handler, with
a client that can use a proxy route or a direct connection.
Details#
Each attempt is a new request with the same deadline. The body of each redirect response is
closed or drained as policy says. handler runs one time, and only if a final response
arrives.
withBytesResponse#
pub effect<'env> fn withBytesResponse<
'client,
'uri,
'method,
'headers,
'policy,
'bytes,
'scratch,
P,
A,
CallbackError,
AcquisitionError,
?CallbackRequirements,
?AcquisitionRequirements,
H: ResponseHandler<P, A, CallbackError ? CallbackRequirements> + 'env,
C: AttemptClient<'policy, P, AttemptStep<'policy, A>, RedirectError | ValueError | CallbackError | ExchangeError | OutOfMemoryError, AcquisitionError, AcquisitionRequirements ? CallbackRequirements | &mut SelectedBody<
never,
never,
> | &mut MonotonicClock | &mut Allocator | &mut Random>,
'env,
>(
client: &'client mut C,
request: Request<'uri, 'method, 'headers, 'policy>,
policy: &'policy Policy,
bytes: &'bytes [u8],
deadline: Option<Instant>,
scratch: &'scratch mut [u8],
handler: H,
) -> A
! RedirectError | ValueError | CallbackError | ExchangeError | OutOfMemoryError | AcquisitionError
? CallbackRequirements | AcquisitionRequirements | &mut MonotonicClock | &mut Allocator | &mut Random
where
&mut P provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut P provides &HttpTransport from &mut HttpTransport,
&mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut P provides &ByteDuplex from &mut ByteDuplex,
CallbackRequirements in Without<CallbackRequirements, ByteDuplex>,
CallbackRequirements in Without<CallbackRequirements, HttpTransport>,
AcquisitionRequirements in Without<AcquisitionRequirements, ByteDuplex>,
AcquisitionRequirements in Without<AcquisitionRequirements, HttpTransport>Follows redirects for a request with the body bytes, and gives the final response to
handler.
Details#
Each attempt that keeps the body sends bytes from the start. After a redirect that drops the
body, all later attempts have no body. A body that is not empty needs a scratch buffer that is
not empty.
withBytesHybridResponse#
pub effect<'env> fn withBytesHybridResponse<
'client,
'uri,
'method,
'headers,
'policy,
'bytes,
'scratch,
RoutedP,
DirectP,
A,
CallbackError,
AcquisitionError,
?CallbackRequirements,
?AcquisitionRequirements,
H: HybridResponseHandler<RoutedP, DirectP, A, CallbackError ? CallbackRequirements> + 'env,
C: HybridAttemptClient<'policy, RoutedP, DirectP, AttemptStep<'policy, A>, RedirectError | ValueError | CallbackError | ExchangeError | OutOfMemoryError, AcquisitionError, AcquisitionRequirements ? CallbackRequirements | &mut SelectedBody<
never,
never,
> | &mut MonotonicClock | &mut Allocator | &mut Random>,
'env,
>(
client: &'client mut C,
request: Request<'uri, 'method, 'headers, 'policy>,
policy: &'policy Policy,
bytes: &'bytes [u8],
deadline: Option<Instant>,
scratch: &'scratch mut [u8],
handler: H,
) -> A
! RedirectError | ValueError | CallbackError | ExchangeError | OutOfMemoryError | AcquisitionError
? CallbackRequirements | AcquisitionRequirements | &mut MonotonicClock | &mut Allocator | &mut Random
where
&mut RoutedP provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut RoutedP provides &HttpTransport from &mut HttpTransport,
&mut RoutedP provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut RoutedP provides &ByteDuplex from &mut ByteDuplex,
&mut DirectP provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut DirectP provides &HttpTransport from &mut HttpTransport,
CallbackRequirements in Without<CallbackRequirements, ByteDuplex>,
CallbackRequirements in Without<CallbackRequirements, HttpTransport>,
AcquisitionRequirements in Without<AcquisitionRequirements, ByteDuplex>,
AcquisitionRequirements in Without<AcquisitionRequirements, HttpTransport>Follows redirects for a request with the body bytes, and gives the final response to
handler, with a client that can use a proxy route or a direct connection.
Details#
Each attempt that keeps the body sends bytes from the start. After a redirect that drops the
body, all later attempts have no body. A body that is not empty needs a scratch buffer that is
not empty.
withOneShotResponse#
pub effect<'env> fn withOneShotResponse<
'client,
'uri,
'method,
'headers,
'policy,
'scratch,
P,
A,
ProducerError,
CallbackError,
AcquisitionError,
?ProducerRequirements,
?CallbackRequirements,
?AcquisitionRequirements,
Producer: BodyProducer<ProducerError ? ProducerRequirements> + 'env,
H: ResponseHandler<P, A, CallbackError ? CallbackRequirements> + 'env,
C: AttemptClient<'policy, P, AttemptStep<'policy, A>, RedirectError | ValueError | ProducerError | CallbackError | ExchangeError | OutOfMemoryError, AcquisitionError, AcquisitionRequirements ? ProducerRequirements | CallbackRequirements | &mut SelectedBody<
ProducerError,
ProducerRequirements,
> | &mut MonotonicClock | &mut Allocator | &mut Random>,
'env,
>(
client: &'client mut C,
request: Request<'uri, 'method, 'headers, 'policy>,
policy: &'policy Policy,
producer: Producer,
deadline: Option<Instant>,
scratch: &'scratch mut [u8],
handler: H,
) -> A
! RedirectError | ValueError | ProducerError | CallbackError | ExchangeError | OutOfMemoryError | AcquisitionError
? ProducerRequirements | CallbackRequirements | AcquisitionRequirements | &mut MonotonicClock | &mut Allocator | &mut Random
where
&mut P provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut P provides &HttpTransport from &mut HttpTransport,
&mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut P provides &ByteDuplex from &mut ByteDuplex,
ProducerRequirements in Without<ProducerRequirements, ByteDuplex>,
ProducerRequirements in Without<ProducerRequirements, HttpTransport>,
CallbackRequirements in Without<CallbackRequirements, ByteDuplex>,
CallbackRequirements in Without<CallbackRequirements, HttpTransport>,
AcquisitionRequirements in Without<AcquisitionRequirements, ByteDuplex>,
AcquisitionRequirements in Without<AcquisitionRequirements, HttpTransport>Follows redirects for a request whose body comes from a producer that runs one time.
When to use#
Use it when the body cannot be made again, for example a stream.
Details#
The first attempt uses the producer, also when Require100 gets an early final response. A
later redirect that keeps the body fails with ReplayUnavailable. A redirect that drops the
body continues without it.
withOneShotHybridResponse#
pub effect<'env> fn withOneShotHybridResponse<
'client,
'uri,
'method,
'headers,
'policy,
'scratch,
RoutedP,
DirectP,
A,
ProducerError,
CallbackError,
AcquisitionError,
?ProducerRequirements,
?CallbackRequirements,
?AcquisitionRequirements,
Producer: BodyProducer<ProducerError ? ProducerRequirements> + 'env,
H: HybridResponseHandler<RoutedP, DirectP, A, CallbackError ? CallbackRequirements> + 'env,
C: HybridAttemptClient<'policy, RoutedP, DirectP, AttemptStep<'policy, A>, RedirectError | ValueError | ProducerError | CallbackError | ExchangeError | OutOfMemoryError, AcquisitionError, AcquisitionRequirements ? ProducerRequirements | CallbackRequirements | &mut SelectedBody<
ProducerError,
ProducerRequirements,
> | &mut MonotonicClock | &mut Allocator | &mut Random>,
'env,
>(
client: &'client mut C,
request: Request<'uri, 'method, 'headers, 'policy>,
policy: &'policy Policy,
producer: Producer,
deadline: Option<Instant>,
scratch: &'scratch mut [u8],
handler: H,
) -> A
! RedirectError | ValueError | ProducerError | CallbackError | ExchangeError | OutOfMemoryError | AcquisitionError
? ProducerRequirements | CallbackRequirements | AcquisitionRequirements | &mut MonotonicClock | &mut Allocator | &mut Random
where
&mut RoutedP provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut RoutedP provides &HttpTransport from &mut HttpTransport,
&mut RoutedP provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut RoutedP provides &ByteDuplex from &mut ByteDuplex,
&mut DirectP provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut DirectP provides &HttpTransport from &mut HttpTransport,
ProducerRequirements in Without<ProducerRequirements, ByteDuplex>,
ProducerRequirements in Without<ProducerRequirements, HttpTransport>,
CallbackRequirements in Without<CallbackRequirements, ByteDuplex>,
CallbackRequirements in Without<CallbackRequirements, HttpTransport>,
AcquisitionRequirements in Without<AcquisitionRequirements, ByteDuplex>,
AcquisitionRequirements in Without<AcquisitionRequirements, HttpTransport>Follows redirects for a request whose body comes from a producer that runs one time, with a client that can use a proxy route or a direct connection.
When to use#
Use it when the body cannot be made again, for example a stream.
Details#
The first attempt uses the producer, also when Require100 gets an early final response. A
later redirect that keeps the body fails with ReplayUnavailable. A redirect that drops the
body continues without it.
withReplayResponse#
pub effect<'env> fn withReplayResponse<
'client,
'uri,
'method,
'headers,
'policy,
'scratch,
P,
A,
FactoryError,
ProducerError,
CallbackError,
AcquisitionError,
?FactoryRequirements,
?ProducerRequirements,
?CallbackRequirements,
?AcquisitionRequirements,
Producer: BodyProducer<ProducerError ? ProducerRequirements>,
H: ResponseHandler<P, A, CallbackError ? CallbackRequirements> + 'env,
C: AttemptClient<'policy, P, AttemptStep<'policy, A>, RedirectError | ValueError | ProducerError | CallbackError | ExchangeError | OutOfMemoryError, AcquisitionError, AcquisitionRequirements ? ProducerRequirements | CallbackRequirements | &mut SelectedBody<
ProducerError,
ProducerRequirements,
> | &mut MonotonicClock | &mut Allocator | &mut Random>,
Factory: ReplayFactory<Producer, FactoryError, FactoryRequirements> + 'env,
'env,
>(
client: &'client mut C,
request: Request<'uri, 'method, 'headers, 'policy>,
policy: &'policy Policy,
factory: Factory,
deadline: Option<Instant>,
scratch: &'scratch mut [u8],
handler: H,
) -> A
! RedirectError | ValueError | FactoryError | ProducerError | CallbackError | ExchangeError | OutOfMemoryError | AcquisitionError
? FactoryRequirements | ProducerRequirements | CallbackRequirements | AcquisitionRequirements | &mut MonotonicClock | &mut Allocator | &mut Random
where
&mut P provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut P provides &HttpTransport from &mut HttpTransport,
&mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut P provides &ByteDuplex from &mut ByteDuplex,
FactoryRequirements in Without<FactoryRequirements, ByteDuplex>,
FactoryRequirements in Without<FactoryRequirements, HttpTransport>,
ProducerRequirements in Without<ProducerRequirements, ByteDuplex>,
ProducerRequirements in Without<ProducerRequirements, HttpTransport>,
CallbackRequirements in Without<CallbackRequirements, ByteDuplex>,
CallbackRequirements in Without<CallbackRequirements, HttpTransport>,
AcquisitionRequirements in Without<AcquisitionRequirements, ByteDuplex>,
AcquisitionRequirements in Without<AcquisitionRequirements, HttpTransport>Follows redirects for a request whose body comes from a new producer for each attempt.
When to use#
Use it for a body that you can read again, such as a file, with a ReplayFactory.
Details#
Each producer lives for one attempt. After a redirect that drops the body, the factory is not used again.
withReplayHybridResponse#
pub effect<'env> fn withReplayHybridResponse<
'client,
'uri,
'method,
'headers,
'policy,
'scratch,
RoutedP,
DirectP,
A,
FactoryError,
ProducerError,
CallbackError,
AcquisitionError,
?FactoryRequirements,
?ProducerRequirements,
?CallbackRequirements,
?AcquisitionRequirements,
Producer: BodyProducer<ProducerError ? ProducerRequirements>,
H: HybridResponseHandler<RoutedP, DirectP, A, CallbackError ? CallbackRequirements> + 'env,
C: HybridAttemptClient<'policy, RoutedP, DirectP, AttemptStep<'policy, A>, RedirectError | ValueError | ProducerError | CallbackError | ExchangeError | OutOfMemoryError, AcquisitionError, AcquisitionRequirements ? ProducerRequirements | CallbackRequirements | &mut SelectedBody<
ProducerError,
ProducerRequirements,
> | &mut MonotonicClock | &mut Allocator | &mut Random>,
Factory: ReplayFactory<Producer, FactoryError, FactoryRequirements> + 'env,
'env,
>(
client: &'client mut C,
request: Request<'uri, 'method, 'headers, 'policy>,
policy: &'policy Policy,
factory: Factory,
deadline: Option<Instant>,
scratch: &'scratch mut [u8],
handler: H,
) -> A
! RedirectError | ValueError | FactoryError | ProducerError | CallbackError | ExchangeError | OutOfMemoryError | AcquisitionError
? FactoryRequirements | ProducerRequirements | CallbackRequirements | AcquisitionRequirements | &mut MonotonicClock | &mut Allocator | &mut Random
where
&mut RoutedP provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut RoutedP provides &HttpTransport from &mut HttpTransport,
&mut RoutedP provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut RoutedP provides &ByteDuplex from &mut ByteDuplex,
&mut DirectP provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut Random,
&mut DirectP provides &HttpTransport from &mut HttpTransport,
FactoryRequirements in Without<FactoryRequirements, ByteDuplex>,
FactoryRequirements in Without<FactoryRequirements, HttpTransport>,
ProducerRequirements in Without<ProducerRequirements, ByteDuplex>,
ProducerRequirements in Without<ProducerRequirements, HttpTransport>,
CallbackRequirements in Without<CallbackRequirements, ByteDuplex>,
CallbackRequirements in Without<CallbackRequirements, HttpTransport>,
AcquisitionRequirements in Without<AcquisitionRequirements, ByteDuplex>,
AcquisitionRequirements in Without<AcquisitionRequirements, HttpTransport>Follows redirects for a request whose body comes from a new producer for each attempt, with a client that can use a proxy route or a direct connection.
When to use#
Use it for a body that you can read again, such as a file, with a ReplayFactory.
Details#
Each producer lives for one attempt. After a redirect that drops the body, the factory is not used again.
writeBody#
pub effect<'env> fn writeBody<
'bytes,
'oneShot,
'replay,
'exchange,
P,
OneShotError,
ReplayError,
?OneShotRequirements,
?ReplayRequirements,
OneShot: BodyProducer<OneShotError ? OneShotRequirements> + 'env,
ReplayProducer: BodyProducer<ReplayError ? ReplayRequirements> + 'env,
'env,
>(
exchange: &mut Exchange<'exchange, P>,
current: &Uri,
expected: BodyMode,
body: AttemptBody<'bytes, 'oneShot, 'replay, OneShot, ReplayProducer>,
scratch: &mut [u8],
trailers: &Headers,
hop: usize,
) -> BodyWriteOutcome
! RedirectError | OneShotError | ReplayError | ExchangeError | OutOfMemoryError
? OneShotRequirements | ReplayRequirements | &mut MonotonicClock | &mut Allocator | &mut Random
where
&mut P provides &HttpTransport from &mut HttpTransport | &mut MonotonicClock | &mut Allocator | &mut RandomSends the head and the body of one attempt, and reads until the first final response.
When to use#
Use it in the exchange callback of an attempt client, with the AttemptBody of the attempt.
Details#
The framing of the body is checked before the head is sent. With Require100, 1xx responses are
read until 100 Continue, or until a final response, which returns EarlyFinal. Redirected
requests cannot have trailers, so trailers must be empty. Each chunk must fit in scratch.
Gotchas#
scratch must not be empty for a body with a length or chunks. A pull that returns 0 bytes and
not end fails. An early final response uses up a OneShot producer, also when it was never
pulled.
StatusDecision#
pub enum StatusDecisionThe result of statusDecision.
Final#
FinalReturn this response. Location is not read.
Redirect#
RedirectFollow the redirect.
BodyDecision#
pub enum BodyDecisionWhether the next request sends the body again.
Retain#
RetainSend the body again. The body must be repeatable.
Drop#
DropDo not send the body, and remove the content headers.
Transition#
pub struct Transition<'method>The method and the body of the next request, from transition.
Field method#
pub method: Method<'method>The next method: the same method, or GET.
Field body#
pub body: BodyDecisionWhether the body is sent again.
Implementation Copy for Transition<'method>#
impl<'method> Copy for Transition<'method>Implementation NameList#
impl NameListAssociated function empty#
pub fn empty() -> NameListReturns an empty list. It does not allocate.
Associated function copy#
pub effect fn copy(names: &[string], limits: NameListLimits) -> Result<NameList, RedirectError>
! OutOfMemoryError
? &mut AllocatorChecks and copies names into a new list. Each name must be a valid field name.
Method contains#
pub fn contains(self: &Self, name: string) -> boolReturns true if the list has name, compared without case.
Method count#
pub fn count(self: &Self) -> usizeReturns the number of names.
Method ownedBytes#
pub fn ownedBytes(self: &Self) -> usizeReturns the memory of the list, in bytes.
Implementation Policy#
impl PolicyAssociated function defaults#
pub fn defaults() -> PolicyReturns a policy that does not follow redirects.
Details#
It allows 10 redirects, URIs of 8192 bytes, and a history of 90112 bytes, if you change the
mode to Follow. It denies a change of origin and a change from HTTPS to HTTP, keeps POST for
301 and 302, and closes redirect responses. The name lists are empty.
Associated function make#
pub fn make(
mode: Mode,
history: HistoryLimits,
crossOrigin: CrossOriginPolicy,
downgrade: DowngradePolicy,
post301302: Post301302Policy,
previousResponse: PreviousResponsePolicy,
safeCustom: NameList,
sensitive: NameList,
) -> Result<Policy, RedirectError>Returns a policy.
safeCustom names extra headers that can go to another origin. sensitive names headers that
never go to another origin.
Errors#
NameListOverlapif a name is in both lists.InvalidPolicyifmaxHopsplus 1 overflows.
Method mode#
pub fn mode(self: &Self) -> ModeReturns whether redirects are followed.
Method historyLimits#
pub fn historyLimits(self: &Self) -> HistoryLimitsReturns the limits.
Method crossOrigin#
pub fn crossOrigin(self: &Self) -> CrossOriginPolicyReturns whether a redirect can go to another origin.
Method downgrade#
pub fn downgrade(self: &Self) -> DowngradePolicyReturns whether a redirect can go from HTTPS to HTTP.
Method post301302#
pub fn post301302(self: &Self) -> Post301302PolicyReturns what 301 and 302 do with POST.
Method previousResponse#
pub fn previousResponse(self: &Self) -> &PreviousResponsePolicyReturns what to do with the body of a redirect response.
Method safeCustom#
pub fn safeCustom(self: &Self) -> &NameListReturns the extra headers that can go to another origin.
Method sensitive#
pub fn sensitive(self: &Self) -> &NameListReturns the headers that never go to another origin.
statusDecision#
pub fn statusDecision(policy: &Policy, status: Status, followedHops: usize) -> Result<
StatusDecision,
RedirectError,
>Returns whether a response with status is a redirect to follow. It does not read Location.
The statuses 301, 302, 303, 307, and 308 are followed in Follow mode. Fails with HopLimit if
followedHops is already maxHops.
transition#
pub fn transition<'method>(policy: &Policy, status: Status, method: Method<'method>) -> Transition<
'method,
>Returns the method and the body of the next request, by the rules of RFC 9110 and the policy.
resolveLocation#
pub effect fn resolveLocation<'head>(
current: &Uri,
headers: &Headers<'head>,
limits: HistoryLimits,
hop: usize,
status: Status,
) -> Result<OwnedUri, RedirectError> ! OutOfMemoryError ? &mut AllocatorReturns the next URI, from the Location field of the response.
When to use#
Use it while the response head is still available, before you connect to the next origin.
Details#
There must be exactly one Location field. Its value is resolved against current by RFC 3986,
and must be an http or https URI with a host and without user information. If it has no
fragment, it gets the fragment of current.
Gotchas#
An empty fragment, as in /a#, replaces the fragment of current.
admitOrigin#
pub fn admitOrigin(policy: &Policy, current: &Origin, next: &Origin, hop: usize, status: Status) -> Result<
bool,
RedirectError,
>Checks the cross-origin and downgrade rules for a redirect from current to next. Returns
true if the origin changes, so that the next request must use crossOriginHeaderPolicy and
sanitizeHeaders.
History#
pub struct HistoryThe requests of a redirect operation, to find loops. It allocates its memory one time.
Implementation History#
impl HistoryAssociated function make#
pub effect fn make(limits: HistoryLimits) -> Result<History, RedirectError>
! OutOfMemoryError
? &mut AllocatorReturns an empty history, and allocates all its memory before any network I/O.
Method insert#
pub effect fn insert<'method>(self: &mut Self, method: Method<'method>, origin: Origin, uri: &Uri) -> Result<
(),
RedirectError,
> ! OutOfMemoryError ? &mut AllocatorAdds a request, by its method, origin, path, and query. Fails with RedirectLoop if the same
request is already in the history.
Method count#
pub fn count(self: &Self) -> usizeReturns the number of requests in the history.
Method ownedBytes#
pub fn ownedBytes(self: &Self) -> usizeReturns the bytes of the history that are used.
sanitizeHeaders#
pub effect fn sanitizeHeaders<'value>(
headers: &Headers<'value>,
policy: &Policy,
crossOrigin: bool,
body: BodyDecision,
limits: HeaderLimits,
) -> Result<OwnedHeaders, ValueError> ! OutOfMemoryError ? &mut AllocatorReturns a copy of headers without the headers that must not go to the next request.
When to use#
Use it before you prepare the request of each redirect.
Details#
It removes Host, Connection, Keep-Alive, TE, Trailer, Transfer-Encoding, Upgrade,
Proxy-Connection, Proxy-Authorization, Content-Length, Expect, and the fields that
Connection names. When the body is dropped, it also removes the content headers. For another
origin, it keeps only Accept, Accept-Encoding, Accept-Language, User-Agent, the safe
names of the policy, and the content headers of a kept body. Then Authorization, Cookie,
Origin, Referer, and the sensitive names of the policy are always removed.
Gotchas#
The request preparation makes Host, the framing fields, Expect, and Proxy-Authorization
again for the next request. A bad Connection value fails with its ValueError.
Category: HTTP.
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2.