CORS headers for write APIs, refs #1922

This commit is contained in:
Simon Willison 2022-11-30 09:26:59 -08:00
commit 48725bb4ea
2 changed files with 29 additions and 10 deletions

View file

@ -73,13 +73,20 @@ class BaseView:
request.path.endswith(".json") request.path.endswith(".json")
or request.headers.get("content-type") == "application/json" or request.headers.get("content-type") == "application/json"
): ):
return Response.json( response = Response.json(
{"ok": False, "error": "Method not allowed"}, status=405 {"ok": False, "error": "Method not allowed"}, status=405
) )
return Response.text("Method not allowed", status=405) else:
response = Response.text("Method not allowed", status=405)
if self.ds.cors:
add_cors_headers(response.headers)
return response
async def options(self, request, *args, **kwargs): async def options(self, request, *args, **kwargs):
return await self.method_not_allowed(request) r = Response.text("ok")
if self.ds.cors:
add_cors_headers(r.headers)
return r
async def get(self, request, *args, **kwargs): async def get(self, request, *args, **kwargs):
return await self.method_not_allowed(request) return await self.method_not_allowed(request)
@ -155,12 +162,6 @@ class BaseView:
class DataView(BaseView): class DataView(BaseView):
name = "" name = ""
async def options(self, request, *args, **kwargs):
r = Response.text("ok")
if self.ds.cors:
add_cors_headers(r.headers)
return r
def redirect(self, request, path, forward_querystring=True, remove_args=None): def redirect(self, request, path, forward_querystring=True, remove_args=None):
if request.query_string and "?" not in path and forward_querystring: if request.query_string and "?" not in path and forward_querystring:
path = f"{path}?{request.query_string}" path = f"{path}?{request.query_string}"

View file

@ -897,14 +897,32 @@ def test_config_force_https_urls():
("/fixtures/no_primary_key.json", 200), ("/fixtures/no_primary_key.json", 200),
# A 400 invalid SQL query should still have the header: # A 400 invalid SQL query should still have the header:
("/fixtures.json?sql=select+blah", 400), ("/fixtures.json?sql=select+blah", 400),
# Write APIs
("/fixtures/-/create", 405),
("/fixtures/facetable/-/insert", 405),
("/fixtures/facetable/-/drop", 405),
], ],
) )
def test_cors(app_client_with_cors, path, status_code): def test_cors(
app_client_with_cors,
app_client_two_attached_databases_one_immutable,
path,
status_code,
):
response = app_client_with_cors.get(path) response = app_client_with_cors.get(path)
assert response.status == status_code assert response.status == status_code
assert response.headers["Access-Control-Allow-Origin"] == "*" assert response.headers["Access-Control-Allow-Origin"] == "*"
assert response.headers["Access-Control-Allow-Headers"] == "Authorization" assert response.headers["Access-Control-Allow-Headers"] == "Authorization"
assert response.headers["Access-Control-Expose-Headers"] == "Link" assert response.headers["Access-Control-Expose-Headers"] == "Link"
# Same request to app_client_two_attached_databases_one_immutable
# should not have those headers - I'm using that fixture because
# regular app_client doesn't have immutable fixtures.db which means
# the test for /fixtures.db returns a 403 error
response = app_client_two_attached_databases_one_immutable.get(path)
assert response.status == status_code
assert "Access-Control-Allow-Origin" not in response.headers
assert "Access-Control-Allow-Headers" not in response.headers
assert "Access-Control-Expose-Headers" not in response.headers
@pytest.mark.parametrize( @pytest.mark.parametrize(