Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Redirects and cookies

Redirects

RouteBehaviour
GET /redirect/{n}A chain of n relative 302 redirects (1 to 20) ending at /echo; the query string is carried along
GET /absolute-redirect/{n}The same with absolute URLs on the request's own origin (1 to 10): https on the HTTPS listener, and the proxy's Forwarded / X-Forwarded-* scheme and host with RUSTYBIN_TRUST_FORWARD=true
ANY /redirect-to?url=&status_code=One redirect to url with status_code 300, 301, 302 (default), 303, 307 or 308

/redirect-to is not an open redirect: url must be a path starting with a single /, or an http(s) URL whose host:port equals the request's Host. Anything else (other hosts, //host, credentials, whitespace, backslashes) is refused with 400, so a public instance cannot be abused for phishing redirects.

GET {{base_url}}/redirect/3?from=docs
HTTP 302
[Asserts]
header "Location" == "/redirect/2?from=docs"

# Follow the whole chain: it ends at /echo with the query string kept.
GET {{base_url}}/redirect/3?from=docs
[Options]
location: true
HTTP 200
[Asserts]
url endsWith "/echo?from=docs"
jsonpath "$.query_params.from" == "docs"
redirects count == 3
GET {{base_url}}/redirect-to?url=/status/201&status_code=307
HTTP 307
[Asserts]
header "Location" == "/status/201"
# Other hosts are refused: no open redirect.
GET {{base_url}}/redirect-to?url=https://example.com/
HTTP 400
[Asserts]
jsonpath "$.error" == "redirect target refused"
GET {{base_url}}/absolute-redirect/2
HTTP 302
[Asserts]
header "Location" == "{{base_url}}/absolute-redirect/1"

Cookies

RouteBehaviour
GET /cookiesThe request's cookies as JSON ({"cookies": {...}})
GET /cookies/set?name=value&...Sets each pair, then 302 to /cookies
GET /cookies/set/{name}/{value}Sets one cookie (Path=/), then 302 to /cookies
GET /cookies/delete?name&...Expires the named cookies (Max-Age=0 and a 1970 Expires), then 302

Attributes for /cookies/set are query parameters starting with _: _path (default /), _domain, _secure, _httponly, _samesite (Strict, Lax or None; None forces Secure, as browsers require) and _maxage (seconds). For /cookies/delete, _path and _domain must match how the cookie was set. Names must be RFC 6265 tokens (else 400), values are percent-encoded where needed so they can never inject attributes, and at most 20 cookies are handled per request.

GET {{base_url}}/cookies/set?session=abc123&theme=dark&_httponly=true&_maxage=3600
HTTP 302
[Asserts]
header "Location" == "/cookies"
header "Set-Cookie" count == 2
header "Set-Cookie" contains "session=abc123; Path=/; Max-Age=3600; HttpOnly"
GET {{base_url}}/cookies/set/theme/dark
HTTP 302
[Asserts]
header "Set-Cookie" == "theme=dark; Path=/"

GET {{base_url}}/cookies/set?tracking=1&_samesite=None
HTTP 302
[Asserts]
header "Set-Cookie" contains "SameSite=None"
header "Set-Cookie" contains "Secure"
GET {{base_url}}/cookies
Cookie: session=abc123; theme=dark
HTTP 200
[Asserts]
jsonpath "$.cookies.session" == "abc123"
jsonpath "$.cookies.theme" == "dark"
GET {{base_url}}/cookies/delete?session&theme
HTTP 302
[Asserts]
header "Set-Cookie" count == 2
header "Set-Cookie" contains "session=; Path=/; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT"