55
66import logging
77from typing import Any , Final , NamedTuple
8+ from urllib .parse import quote
89
910from aiohttp import ClientTimeout , web
1011from models_library .api_schemas_storage import (
@@ -67,14 +68,21 @@ def _to_storage_url(request: web.Request) -> URL:
6768 )
6869
6970
70- def _from_storage_url (request : web .Request , storage_url : AnyUrl ) -> AnyUrl :
71+ def _from_storage_url (
72+ request : web .Request , storage_url : AnyUrl , url_encode : str | None
73+ ) -> AnyUrl :
7174 """Converts storage-api url to web-api url"""
7275 assert storage_url .path # nosec
7376
7477 prefix = f"/{ _get_storage_vtag (request .app )} "
75- converted_url = request .url .with_path (
76- f"/v0/storage{ storage_url .path .removeprefix (prefix )} " , encoded = True
77- ).with_scheme (request .headers .get (X_FORWARDED_PROTO , request .url .scheme ))
78+ converted_url = str (
79+ request .url .with_path (
80+ f"/v0/storage{ storage_url .path .removeprefix (prefix )} "
81+ ).with_scheme (request .headers .get (X_FORWARDED_PROTO , request .url .scheme ))
82+ )
83+
84+ if url_encode :
85+ converted_url = converted_url .replace (url_encode , quote (url_encode , safe = "" ))
7886
7987 webserver_url : AnyUrl = TypeAdapter (AnyUrl ).validate_python (f"{ converted_url } " )
8088 return webserver_url
@@ -228,7 +236,7 @@ class _PathParams(BaseModel):
228236 location_id : LocationID
229237 file_id : StorageFileIDStr
230238
231- parse_request_path_parameters_as (_PathParams , request )
239+ path_params = parse_request_path_parameters_as (_PathParams , request )
232240
233241 class _QueryParams (BaseModel ):
234242 file_size : ByteSize | None = None
@@ -240,11 +248,16 @@ class _QueryParams(BaseModel):
240248 payload , status = await _forward_request_to_storage (request , "PUT" , body = None )
241249 data , _ = unwrap_envelope (payload )
242250 file_upload_schema = FileUploadSchema .model_validate (data )
251+ # NOTE: since storage is fastapi-based it returns file_id not url encoded and aiohttp does not like it
252+ # /v0/locations/{location_id}/files/{file_id:non-encoded-containing-slashes}:complete --> /v0/storage/locations/{location_id}/files/{file_id:non-encode}:complete
253+
243254 file_upload_schema .links .complete_upload = _from_storage_url (
244- request , file_upload_schema .links .complete_upload
255+ request ,
256+ file_upload_schema .links .complete_upload ,
257+ url_encode = path_params .file_id ,
245258 )
246259 file_upload_schema .links .abort_upload = _from_storage_url (
247- request , file_upload_schema .links .abort_upload
260+ request , file_upload_schema .links .abort_upload , url_encode = path_params . file_id
248261 )
249262 return create_data_response (jsonable_encoder (file_upload_schema ), status = status )
250263
@@ -260,7 +273,7 @@ class _PathParams(BaseModel):
260273 location_id : LocationID
261274 file_id : StorageFileIDStr
262275
263- parse_request_path_parameters_as (_PathParams , request )
276+ path_params = parse_request_path_parameters_as (_PathParams , request )
264277 body_item = await parse_request_body_as (FileUploadCompletionBody , request )
265278
266279 payload , status = await _forward_request_to_storage (
@@ -269,7 +282,7 @@ class _PathParams(BaseModel):
269282 data , _ = unwrap_envelope (payload )
270283 file_upload_complete = FileUploadCompleteResponse .model_validate (data )
271284 file_upload_complete .links .state = _from_storage_url (
272- request , file_upload_complete .links .state
285+ request , file_upload_complete .links .state , url_encode = path_params . file_id
273286 )
274287 return create_data_response (jsonable_encoder (file_upload_complete ), status = status )
275288
0 commit comments