mirror of
https://github.com/kennethreitz/responder.git
synced 2026-07-21 18:39:29 +00:00
ea5ba0d26b
The first 8.0 sweep. Flagship: responder.Router records route declarations without an API instance (Flask-blueprint style) and api.include_router() replays them with prefix/tags/dependencies/auth composition, nesting, and conflict guards. Correctness: lifespan= now composes with on_event (background draining runs again), view-style default routes dispatch instead of 500ing, CBV HEAD falls back to on_get, tolerant cookie parsing, case-insensitive resp.headers, async background tasks, async GraphQL resolvers, Jinja builtins survive context assignment, identity-based dependency cycle detection, WSGI mounts wrap once, WebSocket crashes send a 1011 close frame, and dependency metadata matches actual imports. Security: Content-Disposition filename escaping in resp.download(); bounded, lock-guarded MemorySessionBackend with expiry-first eviction. 8.0 behavior changes: no implicit static/ mkdir, url_for raises RouteNotFoundError and percent-encodes values, redirect() defaults to 307 (permanent=True for 308), charset= on encoded text responses (no more fake 'Encoding' header), and RFC 9512 application/yaml. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
71 lines
1.9 KiB
Python
71 lines
1.9 KiB
Python
"""Response.redirect() defaults to 307, with permanent=True selecting 308."""
|
|
|
|
|
|
def test_redirect_defaults_to_temporary_307(api):
|
|
@api.route("/old")
|
|
def old(req, resp):
|
|
resp.redirect("/new")
|
|
|
|
r = api.requests.get("/old", follow_redirects=False)
|
|
assert r.status_code == 307
|
|
assert r.headers["Location"] == "/new"
|
|
|
|
|
|
def test_redirect_permanent_selects_308(api):
|
|
@api.route("/old")
|
|
def old(req, resp):
|
|
resp.redirect("/new", permanent=True)
|
|
|
|
r = api.requests.get("/old", follow_redirects=False)
|
|
assert r.status_code == 308
|
|
assert r.headers["Location"] == "/new"
|
|
|
|
|
|
def test_explicit_status_code_still_wins(api):
|
|
@api.route("/moved")
|
|
def moved(req, resp):
|
|
resp.redirect("/new", status_code=301)
|
|
|
|
@api.route("/found")
|
|
def found(req, resp):
|
|
resp.redirect("/new", status_code=302, permanent=True)
|
|
|
|
assert api.requests.get("/moved", follow_redirects=False).status_code == 301
|
|
# An explicit status_code takes precedence over permanent=.
|
|
assert api.requests.get("/found", follow_redirects=False).status_code == 302
|
|
|
|
|
|
def test_api_redirect_helper_matches_new_default(api):
|
|
@api.route("/a")
|
|
def a(req, resp):
|
|
api.redirect(resp, location="/b")
|
|
|
|
@api.route("/p")
|
|
def p(req, resp):
|
|
api.redirect(resp, location="/b", permanent=True)
|
|
|
|
assert api.requests.get("/a", follow_redirects=False).status_code == 307
|
|
assert api.requests.get("/p", follow_redirects=False).status_code == 308
|
|
|
|
|
|
def test_redirect_still_follows(api, session):
|
|
@api.route("/2")
|
|
def two(req, resp):
|
|
resp.redirect("/1")
|
|
|
|
@api.route("/1")
|
|
def one(req, resp):
|
|
resp.text = "redirected"
|
|
|
|
r = session.get("/2")
|
|
assert r.text == "redirected"
|
|
|
|
|
|
def test_redirect_sets_body_text(api):
|
|
@api.route("/old")
|
|
def old(req, resp):
|
|
resp.redirect("/new")
|
|
|
|
r = api.requests.get("/old", follow_redirects=False)
|
|
assert r.text == "Redirecting to: /new"
|