mirror of
https://github.com/kennethreitz/responder.git
synced 2026-07-21 18:39:29 +00:00
9735659d4b
Correctness fixes: - Type-driven OpenAPI now hoists nested-model $defs into top-level components and rewrites $ref, so nested models resolve (Swagger/ReDoc/ codegen). Output is also down-converted to the declared dialect: under 3.0.x, Optional fields become `nullable` and `examples` is singularized. - Query/Header/Cookie/Path markers now enforce their constraints (min_length/gt/... via Annotated+Field) and 422 on violation; a typo'd kwarg raises TypeError instead of silently making the param required; description/deprecated now reach the spec. - enable_hsts now sends a real Strict-Transport-Security header (new responder.middleware.HSTSMiddleware), not just the HTTP->HTTPS redirect; docstrings and tour.rst corrected. Additive ergonomics: - HTTP verb decorators (@api.get/post/put/patch/delete) + @api.websocket_route, on API and route groups; same-path routes allowed when methods are disjoint. - resp.delete_cookie() and resp.vary(); opt-in API(auto_vary=True) emits Vary: Accept on negotiated responses (off by default). All backwards-compatible. 473 tests pass; ruff + mypy clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
48 lines
1.3 KiB
Python
48 lines
1.3 KiB
Python
"""v5.1: enable_hsts emits a real Strict-Transport-Security header."""
|
|
|
|
from starlette.testclient import TestClient
|
|
|
|
import responder
|
|
from responder.middleware import HSTSMiddleware
|
|
|
|
KEY = "a-real-private-secret-key-32chars!"
|
|
|
|
|
|
def _app(**kwargs):
|
|
api = responder.API(allowed_hosts=[";"], secret_key=KEY, **kwargs)
|
|
|
|
@api.route("/")
|
|
def home(req, resp):
|
|
resp.text = "ok"
|
|
|
|
return api
|
|
|
|
|
|
def test_hsts_header_sent_when_enabled():
|
|
api = _app(enable_hsts=True)
|
|
r = TestClient(api, base_url="https://;").get("/")
|
|
assert r.status_code == 200
|
|
assert r.headers["strict-transport-security"] == "max-age=31536000; includeSubDomains"
|
|
|
|
|
|
def test_hsts_still_redirects_http_to_https():
|
|
api = _app(enable_hsts=True)
|
|
r = TestClient(api, base_url="http://;").get("/", follow_redirects=False)
|
|
assert r.status_code == 307
|
|
assert r.headers["location"].startswith("https://")
|
|
|
|
|
|
def test_no_hsts_header_by_default():
|
|
api = _app()
|
|
r = TestClient(api, base_url="https://;").get("/")
|
|
assert "strict-transport-security" not in r.headers
|
|
|
|
|
|
def test_hsts_middleware_is_configurable():
|
|
api = _app()
|
|
api.add_middleware(HSTSMiddleware, max_age=63072000, preload=True)
|
|
r = TestClient(api, base_url="https://;").get("/")
|
|
assert r.headers["strict-transport-security"] == (
|
|
"max-age=63072000; includeSubDomains; preload"
|
|
)
|