root: fix IP detection in ASGI logger, attempt to fix out of order issues

This commit is contained in:
Jens Langhammer 2020-09-10 16:58:25 +02:00
parent b3468bc265
commit 8a07b349ee
2 changed files with 31 additions and 19 deletions

View File

@ -18,3 +18,9 @@ lint:
gen: coverage gen: coverage
./manage.py generate_swagger -o swagger.yaml -f yaml ./manage.py generate_swagger -o swagger.yaml -f yaml
local-stack:
export PASSBOOK_TAG=testing
docker build -t beryju/passbook:testng .
docker-compose up -d
docker-compose run --rm server migrate

View File

@ -32,6 +32,11 @@ Send = typing.Callable[[Message], typing.Awaitable[None]]
ASGIApp = typing.Callable[[Scope, Receive, Send], typing.Awaitable[None]] ASGIApp = typing.Callable[[Scope, Receive, Send], typing.Awaitable[None]]
ASGI_IP_HEADERS = (
b"x-forwarded-for",
b"x-real-ip",
)
LOGGER = get_logger("passbook.asgi") LOGGER = get_logger("passbook.asgi")
@ -51,7 +56,6 @@ class ASGILogger:
"""ASGI Logger, instantiated for each request""" """ASGI Logger, instantiated for each request"""
app: ASGIApp app: ASGIApp
send: Send
scope: Scope scope: Scope
headers: Dict[ByteString, Any] headers: Dict[ByteString, Any]
@ -64,11 +68,26 @@ class ASGILogger:
self.app = app self.app = app
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
self.send = send
self.scope = scope self.scope = scope
self.content_length = 0 self.content_length = 0
self.headers = dict(scope.get("headers", [])) self.headers = dict(scope.get("headers", []))
async def send_hooked(message: Message) -> None:
"""Hooked send method, which records status code and content-length, and for the final
requests logs it"""
headers = dict(message.get("headers", []))
if "status" in message:
self.status_code = message["status"]
if b"Content-Length" in headers:
self.content_length += int(headers.get(b"Content-Length", b"0"))
if message["type"] == "http.response.body" and not message["more_body"]:
runtime = int((time() - self.start) * 10 ** 6)
self.log(runtime)
await send(message)
if self.headers.get(b"host", b"") == b"kubernetes-healthcheck-host": if self.headers.get(b"host", b"") == b"kubernetes-healthcheck-host":
# Don't log kubernetes health/readiness requests # Don't log kubernetes health/readiness requests
await send({"type": "http.response.start", "status": 204, "headers": []}) await send({"type": "http.response.start", "status": 204, "headers": []})
@ -80,25 +99,12 @@ class ASGILogger:
# https://code.djangoproject.com/ticket/31508 # https://code.djangoproject.com/ticket/31508
# https://github.com/encode/uvicorn/issues/266 # https://github.com/encode/uvicorn/issues/266
return return
await self.app(scope, receive, self.send_hooked) await self.app(scope, receive, send_hooked)
async def send_hooked(self, message: Message) -> None:
"""Hooked send method, which records status code and content-length, and for the final
requests logs it"""
headers = dict(message.get("headers", []))
if "status" in message:
self.status_code = message["status"]
if b"Content-Length" in headers:
self.content_length += int(headers.get(b"Content-Length", b"0"))
if message["type"] == "http.response.body" and not message["more_body"]:
runtime = int((time() - self.start) * 10 ** 6)
self.log(runtime)
return await self.send(message)
def _get_ip(self) -> str: def _get_ip(self) -> str:
for header in ASGI_IP_HEADERS:
if header in self.headers:
return self.headers[header].decode()
client_ip, _ = self.scope.get("client", ("", 0)) client_ip, _ = self.scope.get("client", ("", 0))
return client_ip return client_ip