admin-panel-backend/apps/proxy/views.py

77 lines
2.5 KiB
Python

import requests
from django.conf import settings
from django.http import HttpResponse
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.csrf import csrf_exempt
# Headers that must not be copied verbatim between hops (RFC 7230 6.1) plus
# framing headers that HttpResponse recomputes itself.
HOP_BY_HOP_HEADERS = {
"connection",
"keep-alive",
"proxy-authenticate",
"proxy-authorization",
"te",
"trailers",
"transfer-encoding",
"upgrade",
"content-encoding",
"content-length",
}
def _incoming_headers(request):
headers = {}
for key, value in request.META.items():
if key.startswith("HTTP_"):
name = key[5:].replace("_", "-").title()
elif key in ("CONTENT_TYPE", "CONTENT_LENGTH") and value:
name = key.replace("_", "-").title()
else:
continue
headers[name] = value
headers.pop("Host", None)
return headers
@method_decorator(csrf_exempt, name="dispatch")
class ServiceProxyView(View):
"""Forwards `/<service>/<rest>` to the configured base URL for `service`."""
def dispatch(self, request, service, rest="", *args, **kwargs):
base_url = settings.PROXY_SERVICE_BASE_URLS.get(service)
if not base_url:
return HttpResponse(
f'Unknown or unconfigured service "{service}".',
status=404,
content_type="text/plain",
)
target_url = f"{base_url.rstrip('/')}/{rest.lstrip('/')}"
query_string = request.META.get("QUERY_STRING", "")
if query_string:
target_url = f"{target_url}?{query_string}"
try:
upstream = requests.request(
method=request.method,
url=target_url,
headers=_incoming_headers(request),
data=request.body,
timeout=settings.SERVICE_REQUEST_TIMEOUT,
allow_redirects=False,
)
except requests.RequestException as exc:
return HttpResponse(
f'Error contacting upstream service "{service}": {exc}',
status=502,
content_type="text/plain",
)
response = HttpResponse(content=upstream.content, status=upstream.status_code)
for name, value in upstream.headers.items():
if name.lower() in HOP_BY_HOP_HEADERS:
continue
response[name] = value
return response