1515from __future__ import annotations
1616
1717import functools
18- import io
1918import json
2019import logging
2120import random
2221import re
22+ from io import BytesIO
2323from urllib .parse import quote
2424
2525import packaging .version
@@ -185,11 +185,19 @@ def get_cygwin_setup():
185185 """
186186 filename = "setup-x86_64.exe"
187187 response = http_session .get (f"https://www.cygwin.com/{ filename } " )
188+
189+ # Construct headers to return with response
190+ headers : dict [str , str ] = {
191+ "Content-Disposition" : f"attachment; filename=cygwin-{ filename } "
192+ }
193+ if response .headers .get ("Content-Length" ):
194+ headers ["Content-Length" ] = response .headers ["Content-Length" ]
195+
188196 return StreamingResponse (
189197 content = response .iter_content (chunk_size = 8192 ),
190- media_type = response .headers .get ("Content-Type" ),
191- headers = {"Content-Disposition" : f"attachment; filename=cygwin-{ filename } " },
192198 status_code = response .status_code ,
199+ headers = headers ,
200+ media_type = response .headers .get ("Content-Type" ),
193201 )
194202
195203
@@ -266,10 +274,16 @@ def parse_cygwin_request(
266274
267275 logger .info (f"Forwarding Cygwin download request to { _sanitise_str (url )} " )
268276 response = http_session .get (url )
277+
278+ headers : dict [str , str ] = {}
279+ if response .headers .get ("Content-Length" ):
280+ headers ["Content-Length" ] = response .headers ["Content-Length" ]
281+
269282 return StreamingResponse (
270283 content = response .iter_content (chunk_size = 8192 ),
271- media_type = response .headers .get ("Content-Type" ),
272284 status_code = response .status_code ,
285+ headers = headers ,
286+ media_type = response .headers .get ("Content-Type" ),
273287 )
274288
275289
@@ -339,10 +353,16 @@ def get_msys2_setup(
339353 raise ValueError (f"{ setup_file !r} is not a valid executable" )
340354
341355 response = http_session .get (f"{ msys2_url } /distrib/{ setup_file } " )
356+
357+ headers : dict [str , str ] = {}
358+ if response .headers .get ("Content-Length" ):
359+ headers ["Content-Length" ] = response .headers ["Content-Length" ]
360+
342361 return StreamingResponse (
343362 content = response .iter_content (chunk_size = 8192 ),
344- media_type = response .headers .get ("Content-Type" ),
345363 status_code = response .status_code ,
364+ headers = headers ,
365+ media_type = response .headers .get ("Content-Type" ),
346366 )
347367
348368
@@ -491,10 +511,16 @@ def get_msys2_package_file(
491511 response = http_session .get (package_url )
492512 if response .status_code != 200 :
493513 raise HTTPException (status_code = response .status_code )
514+
515+ headers : dict [str , str ] = {}
516+ if response .headers .get ("Content-Length" ):
517+ headers ["Content-Length" ] = response .headers ["Content-Length" ]
518+
494519 return StreamingResponse (
495520 content = response .iter_content (chunk_size = 8192 ),
496- media_type = response .headers .get ("Content-Type" ),
497521 status_code = response .status_code ,
522+ headers = headers ,
523+ media_type = response .headers .get ("Content-Type" ),
498524 )
499525
500526
@@ -555,12 +581,18 @@ def get_cargo_config(request: Request):
555581 "" ,
556582 ]
557583 )
558- config_bytes = io .BytesIO (config_data .encode ("utf-8" ))
584+ config_bytes = config_data .encode ("utf-8" )
585+
586+ headers : dict [str , str ] = {
587+ "Content-Disposition" : "attachment; filename=config.toml" ,
588+ "Content-Length" : str (len (config_bytes )),
589+ }
559590
560591 return StreamingResponse (
561- config_bytes ,
592+ BytesIO (config_bytes ),
593+ status_code = 200 ,
594+ headers = headers ,
562595 media_type = "application/toml+json" ,
563- headers = {"Content-Disposition" : "attachment; filename=config.toml" },
564596 )
565597
566598
@@ -580,8 +612,8 @@ def get_index_page():
580612 raise HTTPException (status_code = response .status_code )
581613 return Response (
582614 content = response .content ,
583- media_type = response .headers .get ("Content-Type" ),
584615 status_code = response .status_code ,
616+ media_type = response .headers .get ("Content-Type" ),
585617 )
586618
587619
@@ -619,12 +651,18 @@ def get_index_config(request: Request):
619651
620652 # Save it as a JSON and return it as part of the response
621653 json_data = json .dumps (config , indent = 4 )
622- json_bytes = io .BytesIO (json_data .encode ("utf-8" ))
654+ json_bytes = json_data .encode ("utf-8" )
655+
656+ headers : dict [str , str ] = {
657+ "Content-Disposition" : "attachment; filename=config.json" ,
658+ "Content-Length" : str (len (json_bytes )),
659+ }
623660
624661 return StreamingResponse (
625- json_bytes ,
662+ BytesIO (json_bytes ),
663+ status_code = 200 ,
664+ headers = headers ,
626665 media_type = "application/json" ,
627- headers = {"Content-Disposition" : "attachment; filename=config.json" },
628666 )
629667
630668
@@ -666,7 +704,8 @@ def get_index_package_metadata(
666704 raise HTTPException (status_code = response .status_code )
667705 return StreamingResponse (
668706 response .iter_content (chunk_size = 8192 ),
669- media_type = "application/json" ,
707+ status_code = response .status_code ,
708+ media_type = response .headers .get ("Content-Type" ),
670709 )
671710
672711
@@ -697,7 +736,8 @@ def get_index_package_metadata_for_short_package_names(
697736 raise HTTPException (status_code = response .status_code )
698737 return StreamingResponse (
699738 response .iter_content (chunk_size = 8192 ),
700- media_type = "application/json" ,
739+ status_code = response .status_code ,
740+ media_type = response .headers .get ("Content-Type" ),
701741 )
702742
703743
@@ -726,16 +766,16 @@ def get_rust_package_download(
726766 file_name = f"{ package } -{ version } .crate" # Construct file name to save package as
727767 if response .status_code != 200 :
728768 raise HTTPException (status_code = response .status_code )
769+
770+ headers = {"Content-Disposition" : f'attachment; filename="{ file_name } "' }
771+ if response .headers .get ("Content-Length" ):
772+ headers ["Content-Length" ] = response .headers ["Content-Length" ]
773+
729774 return StreamingResponse (
730775 content = response .iter_content (chunk_size = 8192 ),
731- headers = {
732- "Content-Disposition" : f'attachment; filename="{ file_name } "' ,
733- "Content-Type" : response .headers .get (
734- "Content-Type" , "application/octet-stream"
735- ),
736- "Content-Length" : response .headers .get ("Content-Length" ),
737- },
738776 status_code = response .status_code ,
777+ headers = headers ,
778+ media_type = response .headers .get ("Content-Type" , "application/octet-stream" ),
739779 )
740780
741781
@@ -859,16 +899,16 @@ def get_rust_api_package_download(
859899 file_name = f"{ package } -{ version } .crate" # Construct crate name to save as
860900 if response .status_code != 200 :
861901 raise HTTPException (status_code = response .status_code )
902+
903+ headers = {"Content-Disposition" : f'attachment; filename="{ file_name } "' }
904+ if response .headers .get ("Content-Length" ):
905+ headers ["Content-Length" ] = response .headers ["Content-Length" ]
906+
862907 return StreamingResponse (
863908 content = response .iter_content (chunk_size = 8192 ),
864- headers = {
865- "Content-Disposition" : f'attachment; filename="{ file_name } "' ,
866- "Content-Type" : response .headers .get (
867- "Content-Type" , "application/octet-stream"
868- ),
869- "Content-Length" : response .headers .get ("Content-Length" ),
870- },
871909 status_code = response .status_code ,
910+ headers = headers ,
911+ media_type = response .headers .get ("Content-Type" , "application/octet-stream" ),
872912 )
873913
874914
@@ -907,16 +947,16 @@ def get_rust_package_crate(
907947 response = http_session .get (url )
908948 if response .status_code != 200 :
909949 raise HTTPException (status_code = response .status_code )
950+
951+ headers = {"Content-Disposition" : f'attachment; filename="{ crate } "' }
952+ if response .headers .get ("Content-Length" ):
953+ headers ["Content-Length" ] = response .headers ["Content-Length" ]
954+
910955 return StreamingResponse (
911- content = response .iter_content (),
912- headers = {
913- "Content-Disposition" : f'attachment; filename="{ crate } "' ,
914- "Content-Type" : response .headers .get (
915- "Content-Type" , "application/octet-stream"
916- ),
917- "Content-Length" : response .headers .get ("Content-Length" ),
918- },
956+ content = response .iter_content (chunk_size = 8192 ),
919957 status_code = response .status_code ,
958+ headers = headers ,
959+ media_type = response .headers .get ("Content-Type" , "application/octet-stream" ),
920960 )
921961
922962
@@ -1012,8 +1052,8 @@ def _rewrite_pypi_url(match):
10121052
10131053 return Response (
10141054 content = content_new ,
1015- media_type = full_path_response .headers .get ("Content-Type" ),
10161055 status_code = full_path_response .status_code ,
1056+ media_type = full_path_response .headers .get ("Content-Type" ),
10171057 )
10181058
10191059
@@ -1081,10 +1121,15 @@ def _expose_wheel_metadata(response_bytes: bytes) -> bytes:
10811121 original_url = selected_package_link .group (1 )
10821122 response = http_session .get (original_url )
10831123
1124+ # Construct headers to return with response
1125+ headers : dict [str , str ] = {}
1126+ if response .headers .get ("Content-Length" ):
1127+ headers ["Content-Lengh" ] = response .headers ["Content-Length" ]
10841128 return StreamingResponse (
10851129 content = response .iter_content (chunk_size = 8192 ),
1086- media_type = response .headers .get ("Content-Type" ),
10871130 status_code = response .status_code ,
1131+ headers = headers ,
1132+ media_type = response .headers .get ("Content-Type" ),
10881133 )
10891134
10901135
0 commit comments