Redirects and cookies
Redirects
| Route | Behaviour |
|---|---|
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
| Route | Behaviour |
|---|---|
GET /cookies | The 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"