Reference · Requests and pages

redirect

signature
redirect(str, int=) -> response

What it does

A response that sends the browser to another address: a status of 303 unless one is given, and a location header with the URL. A route returns it as its answer, usually after a form has been handled, so that a reload of the page does not post the form again. The status is 301, 302, 303, 307 or 308, and the URL no javascript:, vbscript: or data: one. The location is written as a URL holds it, percent-encoded where it must be. The value can be looked at: status, headers and body (always null) are its fields.

It makes an answer; it does not leave. With more code after it, as in if no_user { redirect("/login") }, the route goes on and shows the page: write reply 303 redirect("/login"). quillo check warns of one nothing takes.

Examples

let r = redirect("/")print(r)print(r.status, r.headers, r.body)print(redirect("https://example.com/", 301).status)
output
<response 303>303 { location: "/" } null301
in a program
route POST /login { form: { email: str, password: str } } {    let user = db.one("select * from users where email = ?", email)    let hash = user.password_hash ?? crypto.hash_password("not anyone's")    if user == null || !crypto.verify_password(password, hash) { reply 401 "Wrong email or password" }    set_session({ user: user.id })    redirect("/")}route GET /old-page = redirect("/new-page", 301)

Edge cases

print(redirect("next").headers, redirect("").headers)print(redirect(`/login?next=${url_encode("/orders?page=2")}`).headers)print(redirect("/x") == redirect("/x"))print(redirect("/a b/é").headers, redirect("https://bücher.de/").headers)print(redirect("/\\evil.com").headers, redirect("/p/../../admin").headers)
output
{ location: "next" } { location: "" }{ location: "/login?next=%2Forders%3Fpage%3D2" }false{ location: "/a%20b/%C3%A9" } { location: "https://xn--bcher-kva.de/" }{ location: "/%5Cevil.com" } { location: "/admin" }

Errors

A status other than 301, 302, 303, 307 and 308 is a runtime error, as is a URL with a line break, a tab or another control character (text from a request cannot add headers of its own), a javascript:, vbscript: or data: URL, or a URL that is not a string. None of these is an error value; the refusal names the scheme it was given. A host IDNA cannot write (https://ü%.com/) gives an error value, which a route answers with a 500.

this one fails
print(redirect("/", 200))
output
line 1: `redirect` status is 301, 302, 303, 307 or 308, got 200
this one fails
print(redirect("/a\nb"))
output
line 1: `redirect` URL cannot contain line breaks, tabs or other control characters
this one fails
print(redirect("JavaScript:alert(1)"))
output
line 1: `redirect` is not given a javascript: URL
this one fails
print(redirect("data:text/html,<script>alert(1)</script>"))
output
line 1: `redirect` is not given a data: URL

Chaining

A redirect ends a request from inside a helper with reply: reply 303 redirect(url) sends it from wherever the helper is called, so one me_or_login serves every page that needs a visitor (see Requiring a session).

in a program
fn me_or_login(back: str) = me() ?? reply 303 redirect(`/login?next=${url_encode(back)}`)route GET /account = <AccountPage me={me_or_login("/account")}/>
print("/dashboard" | redirect(302) | (r) => r.status)
output
302

See also

respond, url_encode, set_session, navigate

Thread
8Useful? Like it, or add to its thread below.

Thread 0 posts

On redirect(): questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.

    Edit this page on GitHub · every example's output was made by running it (tools/refcheck.mjs) · questions on Discord or r/quillo