re-implement simple CORS middleware for blackd (#2500)

* re-implement simple CORS middleware for blackd
* remove aiohttp-cors from setup.py
* Remove aiohttp-cors from Pipfile.lock

Co-authored-by: Richard Si <63936253+ichard26@users.noreply.github.com>
This commit is contained in:
Zsolt Dollenstein 2021-09-25 12:58:44 +01:00 committed by GitHub
parent 7b15393658
commit a5381ba764
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 91 additions and 34 deletions

View File

@ -1,5 +1,11 @@
# Change Log
## Unreleased
### _Blackd_
- Remove dependency on aiohttp-cors (#2500)
## 21.9b0
### Packaging

View File

@ -41,7 +41,6 @@ black = {editable = true, extras = ["d", "jupyter"], path = "."}
[packages]
aiohttp = ">=3.6.0"
aiohttp-cors = ">=0.4.0"
platformdirs= ">=2"
click = ">=8.0.0"
mypy_extensions = ">=0.4.3"

42
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "ebf216584cfb2c962a1792d0682f3c08b44c7ae27305a03a54eacd6f42df27db"
"sha256": "8b28e41c5a63f0c30361d2a0ed29dc1e3f0468223ef150ae68586839e2ccf1c9"
},
"pipfile-spec": 6,
"requires": {},
@ -57,14 +57,6 @@
"index": "pypi",
"version": "==3.7.4.post0"
},
"aiohttp-cors": {
"hashes": [
"sha256:0451ba59fdf6909d0e2cd21e4c0a43752bc0703d33fc78ae94d9d9321710193e",
"sha256:4d39c6d7100fd9764ed1caf8cebf0eb01bf5e3f24e2e073fda6234bc48b19f5d"
],
"index": "pypi",
"version": "==0.7.0"
},
"async-timeout": {
"hashes": [
"sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f",
@ -188,6 +180,14 @@
"index": "pypi",
"version": "==0.4.3"
},
"packaging": {
"hashes": [
"sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7",
"sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"
],
"markers": "python_version >= '3.6'",
"version": "==21.0"
},
"pathspec": {
"hashes": [
"sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a",
@ -204,6 +204,14 @@
"index": "pypi",
"version": "==2.2.0"
},
"pyparsing": {
"hashes": [
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.4.7"
},
"regex": {
"hashes": [
"sha256:03840a07a402576b8e3a6261f17eb88abd653ad4e18ec46ef10c9a63f8c99ebd",
@ -252,6 +260,9 @@
"version": "==2021.8.21"
},
"setuptools-scm": {
"extras": [
"toml"
],
"hashes": [
"sha256:c3bd5f701c8def44a5c0bfe8d407bef3f80342217ef3492b951f3777bd2d915c",
"sha256:d1925a69cb07e9b29416a275b9fadb009a23c148ace905b2fb220649a6c18e92"
@ -410,14 +421,6 @@
"index": "pypi",
"version": "==3.7.4.post0"
},
"aiohttp-cors": {
"hashes": [
"sha256:0451ba59fdf6909d0e2cd21e4c0a43752bc0703d33fc78ae94d9d9321710193e",
"sha256:4d39c6d7100fd9764ed1caf8cebf0eb01bf5e3f24e2e073fda6234bc48b19f5d"
],
"index": "pypi",
"version": "==0.7.0"
},
"alabaster": {
"hashes": [
"sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359",
@ -769,7 +772,7 @@
"sha256:2480d8e07d1890056cb53c96e3de44fead9c62f2ba949b0f2e4c4345f4afa977",
"sha256:a65882a4d0fe5fbf702273456ba2ce74fe44892c25e42e057aca526b702a6d4b"
],
"markers": "python_version < '3.7' and python_version < '3.7'",
"markers": "python_version < '3.7'",
"version": "==5.2.2"
},
"iniconfig": {
@ -1336,6 +1339,9 @@
"version": "==3.3.1"
},
"setuptools-scm": {
"extras": [
"toml"
],
"hashes": [
"sha256:c3bd5f701c8def44a5c0bfe8d407bef3f80342217ef3492b951f3777bd2d915c",
"sha256:d1925a69cb07e9b29416a275b9fadb009a23c148ace905b2fb220649a6c18e92"

View File

@ -86,7 +86,7 @@ def get_long_description() -> str:
"mypy_extensions>=0.4.3",
],
extras_require={
"d": ["aiohttp>=3.6.0", "aiohttp-cors>=0.4.0"],
"d": ["aiohttp>=3.6.0"],
"colorama": ["colorama>=0.4.3"],
"python2": ["typed-ast>=1.4.2"],
"uvloop": ["uvloop>=0.15.2"],

View File

@ -8,7 +8,7 @@
try:
from aiohttp import web
import aiohttp_cors
from .middlewares import cors
except ImportError as ie:
raise ImportError(
f"aiohttp dependency is not installed: {ie}. "
@ -67,20 +67,11 @@ def main(bind_host: str, bind_port: int) -> None:
def make_app() -> web.Application:
app = web.Application()
executor = ProcessPoolExecutor()
cors = aiohttp_cors.setup(app)
resource = cors.add(app.router.add_resource("/"))
cors.add(
resource.add_route("POST", partial(handle, executor=executor)),
{
"*": aiohttp_cors.ResourceOptions(
allow_headers=(*BLACK_HEADERS, "Content-Type"), expose_headers="*"
)
},
app = web.Application(
middlewares=[cors(allow_headers=(*BLACK_HEADERS, "Content-Type"))]
)
executor = ProcessPoolExecutor()
app.add_routes([web.post("/", partial(handle, executor=executor))])
return app

34
src/blackd/middlewares.py Normal file
View File

@ -0,0 +1,34 @@
from typing import Iterable, Awaitable, Callable
from aiohttp.web_response import StreamResponse
from aiohttp.web_request import Request
from aiohttp.web_middlewares import middleware
Handler = Callable[[Request], Awaitable[StreamResponse]]
Middleware = Callable[[Request, Handler], Awaitable[StreamResponse]]
def cors(allow_headers: Iterable[str]) -> Middleware:
@middleware
async def impl(request: Request, handler: Handler) -> StreamResponse:
is_options = request.method == "OPTIONS"
is_preflight = is_options and "Access-Control-Request-Method" in request.headers
if is_preflight:
resp = StreamResponse()
else:
resp = await handler(request)
origin = request.headers.get("Origin")
if not origin:
return resp
resp.headers["Access-Control-Allow-Origin"] = "*"
resp.headers["Access-Control-Expose-Headers"] = "*"
if is_options:
resp.headers["Access-Control-Allow-Headers"] = ", ".join(allow_headers)
resp.headers["Access-Control-Allow-Methods"] = ", ".join(
("OPTIONS", "POST")
)
return resp
return impl # type: ignore

View File

@ -164,3 +164,24 @@ async def test_blackd_invalid_line_length(self) -> None:
async def test_blackd_response_black_version_header(self) -> None:
response = await self.client.post("/")
self.assertIsNotNone(response.headers.get(blackd.BLACK_VERSION_HEADER))
@unittest_run_loop
async def test_cors_preflight(self) -> None:
response = await self.client.options(
"/",
headers={
"Access-Control-Request-Method": "POST",
"Origin": "*",
"Access-Control-Request-Headers": "Content-Type",
},
)
self.assertEqual(response.status, 200)
self.assertIsNotNone(response.headers.get("Access-Control-Allow-Origin"))
self.assertIsNotNone(response.headers.get("Access-Control-Allow-Headers"))
self.assertIsNotNone(response.headers.get("Access-Control-Allow-Methods"))
@unittest_run_loop
async def test_cors_headers_present(self) -> None:
response = await self.client.post("/", headers={"Origin": "*"})
self.assertIsNotNone(response.headers.get("Access-Control-Allow-Origin"))
self.assertIsNotNone(response.headers.get("Access-Control-Expose-Headers"))