add aurweb.asgi.id_redirect_middleware

A new middleware which redirects requests going to '/route?id=some_id'
to '/route/some_id'. In the FastAPI application, we'll prefer using
restful layouts where possible where resource-based ids are
parameters of the request uri: '/route/{resource_id}'.

Signed-off-by: Kevin Morris <kevr@0cost.org>
This commit is contained in:
Kevin Morris 2021-06-19 01:10:53 -07:00
parent e534704a98
commit dc4cc9b604
2 changed files with 32 additions and 0 deletions

View file

@ -2,6 +2,8 @@ import asyncio
import http import http
import typing import typing
from urllib.parse import quote_plus
from fastapi import FastAPI, HTTPException, Request from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
@ -120,3 +122,23 @@ async def check_terms_of_service(request: Request, call_next: typing.Callable):
task = asyncio.create_task(call_next(request)) task = asyncio.create_task(call_next(request))
await asyncio.wait({task}, return_when=asyncio.FIRST_COMPLETED) await asyncio.wait({task}, return_when=asyncio.FIRST_COMPLETED)
return task.result() return task.result()
@app.middleware("http")
async def id_redirect_middleware(request: Request, call_next: typing.Callable):
id = request.query_params.get("id")
if id is not None:
# Preserve query string.
qs = []
for k, v in request.query_params.items():
if k != "id":
qs.append(f"{k}={quote_plus(str(v))}")
qs = str() if not qs else '?' + '&'.join(qs)
path = request.url.path.rstrip('/')
return RedirectResponse(f"{path}/{id}{qs}")
task = asyncio.create_task(call_next(request))
await asyncio.wait({task}, return_when=asyncio.FIRST_COMPLETED)
return task.result()

View file

@ -148,3 +148,13 @@ def test_nonce_csp():
if not (nonce_verified := (script.get("nonce") == nonce)): if not (nonce_verified := (script.get("nonce") == nonce)):
break break
assert nonce_verified is True assert nonce_verified is True
def test_id_redirect():
with client as request:
response = request.get("/", params={
"id": "test", # This param will be rewritten into Location.
"key": "value", # Test that this param persists.
"key2": "value2" # And this one.
}, allow_redirects=False)
assert response.headers.get("location") == "/test?key=value&key2=value2"