Skip to content
This repository was archived by the owner on Sep 22, 2023. It is now read-only.

Commit a67cdeb

Browse files
authored
fix: CORS error in the proxy command due to missing request headers (#176)
* fix: Preserve all client HTTP request headers * fix: minor reformat * fix: Exclude "Host" header to prevent CORS error due to proxying * docs: Add news fragment * fix: Better host header control * refactor: Extract header translation and reuse it in websocket handler
1 parent e3b7892 commit a67cdeb

File tree

2 files changed

+19
-6
lines changed

2 files changed

+19
-6
lines changed

changes/176.fix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix CORS errors when running `backend.ai proxy` in a non-localhost IP address due to missing HTTP headers in the upstream API requests

src/ai/backend/client/cli/proxy.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,19 +107,29 @@ async def close_upstream(self):
107107
await self.up_conn.close()
108108

109109

110+
def _translate_headers(upstream_request: Request, client_request: Request) -> None:
111+
for k, v in client_request.headers.items():
112+
upstream_request.headers[k] = v
113+
api_endpoint = upstream_request.config.endpoint
114+
assert api_endpoint.host is not None
115+
if api_endpoint.is_default_port():
116+
upstream_request.headers['Host'] = api_endpoint.host
117+
else:
118+
upstream_request.headers['Host'] = f"{api_endpoint.host}:{api_endpoint.port}"
119+
120+
110121
async def web_handler(request):
111122
path = re.sub(r'^/?v(\d+)/', '/', request.path)
112123
try:
113124
# We treat all requests and responses as streaming universally
114125
# to be a transparent proxy.
115126
api_rqst = Request(
116127
request.method, path, request.content,
117-
params=request.query)
128+
params=request.query,
129+
)
130+
_translate_headers(api_rqst, request)
118131
if 'Content-Type' in request.headers:
119-
api_rqst.content_type = request.content_type # set for signing
120-
api_rqst.headers['Content-Type'] = request.headers['Content-Type'] # preserve raw value
121-
if 'Content-Length' in request.headers:
122-
api_rqst.headers['Content-Length'] = request.headers['Content-Length']
132+
api_rqst.content_type = request.content_type # set for signing
123133
# Uploading request body happens at the entering of the block,
124134
# and downloading response body happens in the read loop inside.
125135
async with api_rqst.fetch() as up_resp:
@@ -161,7 +171,9 @@ async def websocket_handler(request):
161171
api_rqst = Request(
162172
request.method, path, request.content,
163173
params=request.query,
164-
content_type=request.content_type)
174+
content_type=request.content_type,
175+
)
176+
_translate_headers(api_rqst, request)
165177
async with api_rqst.connect_websocket() as up_conn:
166178
down_conn = web.WebSocketResponse()
167179
await down_conn.prepare(request)

0 commit comments

Comments
 (0)