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
@@ -170,11 +170,19 @@ def get_cygwin_setup():
170170 """
171171 filename = "setup-x86_64.exe"
172172 response = http_session .get (f"https://www.cygwin.com/{ filename } " )
173+
174+ # Construct headers to return with response
175+ headers : dict [str , str ] = {
176+ "Content-Disposition" : f"attachment; filename=cygwin-{ filename } "
177+ }
178+ if response .headers .get ("Content-Length" ):
179+ headers ["Content-Length" ] = response .headers ["Content-Length" ]
180+
173181 return StreamingResponse (
174182 content = response .iter_content (chunk_size = 8192 ),
175- media_type = response .headers .get ("Content-Type" ),
176- headers = {"Content-Disposition" : f"attachment; filename=cygwin-{ filename } " },
177183 status_code = response .status_code ,
184+ headers = headers ,
185+ media_type = response .headers .get ("Content-Type" ),
178186 )
179187
180188
@@ -251,10 +259,16 @@ def parse_cygwin_request(
251259
252260 logger .info (f"Forwarding Cygwin download request to { _sanitise_str (url )} " )
253261 response = http_session .get (url )
262+
263+ headers : dict [str , str ] = {}
264+ if response .headers .get ("Content-Length" ):
265+ headers ["Content-Length" ] = response .headers ["Content-Length" ]
266+
254267 return StreamingResponse (
255268 content = response .iter_content (chunk_size = 8192 ),
256- media_type = response .headers .get ("Content-Type" ),
257269 status_code = response .status_code ,
270+ headers = headers ,
271+ media_type = response .headers .get ("Content-Type" ),
258272 )
259273
260274
@@ -324,10 +338,16 @@ def get_msys2_setup(
324338 raise ValueError (f"{ setup_file !r} is not a valid executable" )
325339
326340 response = http_session .get (f"{ msys2_url } /distrib/{ setup_file } " )
341+
342+ headers : dict [str , str ] = {}
343+ if response .headers .get ("Content-Length" ):
344+ headers ["Content-Length" ] = response .headers ["Content-Length" ]
345+
327346 return StreamingResponse (
328347 content = response .iter_content (chunk_size = 8192 ),
329- media_type = response .headers .get ("Content-Type" ),
330348 status_code = response .status_code ,
349+ headers = headers ,
350+ media_type = response .headers .get ("Content-Type" ),
331351 )
332352
333353
@@ -476,10 +496,16 @@ def get_msys2_package_file(
476496 response = http_session .get (package_url )
477497 if response .status_code != 200 :
478498 raise HTTPException (status_code = response .status_code )
499+
500+ headers : dict [str , str ] = {}
501+ if response .headers .get ("Content-Length" ):
502+ headers ["Content-Length" ] = response .headers ["Content-Length" ]
503+
479504 return StreamingResponse (
480505 content = response .iter_content (chunk_size = 8192 ),
481- media_type = response .headers .get ("Content-Type" ),
482506 status_code = response .status_code ,
507+ headers = headers ,
508+ media_type = response .headers .get ("Content-Type" ),
483509 )
484510
485511
@@ -540,12 +566,18 @@ def get_cargo_config(request: Request):
540566 "" ,
541567 ]
542568 )
543- config_bytes = io .BytesIO (config_data .encode ("utf-8" ))
569+ config_bytes = config_data .encode ("utf-8" )
570+
571+ headers : dict [str , str ] = {
572+ "Content-Disposition" : "attachment; filename=config.toml" ,
573+ "Content-Length" : str (len (config_bytes )),
574+ }
544575
545576 return StreamingResponse (
546- config_bytes ,
577+ BytesIO (config_bytes ),
578+ status_code = 200 ,
579+ headers = headers ,
547580 media_type = "application/toml+json" ,
548- headers = {"Content-Disposition" : "attachment; filename=config.toml" },
549581 )
550582
551583
@@ -565,8 +597,8 @@ def get_index_page():
565597 raise HTTPException (status_code = response .status_code )
566598 return Response (
567599 content = response .content ,
568- media_type = response .headers .get ("Content-Type" ),
569600 status_code = response .status_code ,
601+ media_type = response .headers .get ("Content-Type" ),
570602 )
571603
572604
@@ -604,12 +636,18 @@ def get_index_config(request: Request):
604636
605637 # Save it as a JSON and return it as part of the response
606638 json_data = json .dumps (config , indent = 4 )
607- json_bytes = io .BytesIO (json_data .encode ("utf-8" ))
639+ json_bytes = json_data .encode ("utf-8" )
640+
641+ headers : dict [str , str ] = {
642+ "Content-Disposition" : "attachment; filename=config.json" ,
643+ "Content-Length" : str (len (json_bytes )),
644+ }
608645
609646 return StreamingResponse (
610- json_bytes ,
647+ BytesIO (json_bytes ),
648+ status_code = 200 ,
649+ headers = headers ,
611650 media_type = "application/json" ,
612- headers = {"Content-Disposition" : "attachment; filename=config.json" },
613651 )
614652
615653
@@ -651,7 +689,8 @@ def get_index_package_metadata(
651689 raise HTTPException (status_code = response .status_code )
652690 return StreamingResponse (
653691 response .iter_content (chunk_size = 8192 ),
654- media_type = "application/json" ,
692+ status_code = response .status_code ,
693+ media_type = response .headers .get ("Content-Type" ),
655694 )
656695
657696
@@ -682,7 +721,8 @@ def get_index_package_metadata_for_short_package_names(
682721 raise HTTPException (status_code = response .status_code )
683722 return StreamingResponse (
684723 response .iter_content (chunk_size = 8192 ),
685- media_type = "application/json" ,
724+ status_code = response .status_code ,
725+ media_type = response .headers .get ("Content-Type" ),
686726 )
687727
688728
@@ -711,16 +751,16 @@ def get_rust_package_download(
711751 file_name = f"{ package } -{ version } .crate" # Construct file name to save package as
712752 if response .status_code != 200 :
713753 raise HTTPException (status_code = response .status_code )
754+
755+ headers = {"Content-Disposition" : f'attachment; filename="{ file_name } "' }
756+ if response .headers .get ("Content-Length" ):
757+ headers ["Content-Length" ] = response .headers ["Content-Length" ]
758+
714759 return StreamingResponse (
715760 content = response .iter_content (chunk_size = 8192 ),
716- headers = {
717- "Content-Disposition" : f'attachment; filename="{ file_name } "' ,
718- "Content-Type" : response .headers .get (
719- "Content-Type" , "application/octet-stream"
720- ),
721- "Content-Length" : response .headers .get ("Content-Length" ),
722- },
723761 status_code = response .status_code ,
762+ headers = headers ,
763+ media_type = response .headers .get ("Content-Type" , "application/octet-stream" ),
724764 )
725765
726766
@@ -844,16 +884,16 @@ def get_rust_api_package_download(
844884 file_name = f"{ package } -{ version } .crate" # Construct crate name to save as
845885 if response .status_code != 200 :
846886 raise HTTPException (status_code = response .status_code )
887+
888+ headers = {"Content-Disposition" : f'attachment; filename="{ file_name } "' }
889+ if response .headers .get ("Content-Length" ):
890+ headers ["Content-Length" ] = response .headers ["Content-Length" ]
891+
847892 return StreamingResponse (
848893 content = response .iter_content (chunk_size = 8192 ),
849- headers = {
850- "Content-Disposition" : f'attachment; filename="{ file_name } "' ,
851- "Content-Type" : response .headers .get (
852- "Content-Type" , "application/octet-stream"
853- ),
854- "Content-Length" : response .headers .get ("Content-Length" ),
855- },
856894 status_code = response .status_code ,
895+ headers = headers ,
896+ media_type = response .headers .get ("Content-Type" , "application/octet-stream" ),
857897 )
858898
859899
@@ -892,16 +932,16 @@ def get_rust_package_crate(
892932 response = http_session .get (url )
893933 if response .status_code != 200 :
894934 raise HTTPException (status_code = response .status_code )
935+
936+ headers = {"Content-Disposition" : f'attachment; filename="{ crate } "' }
937+ if response .headers .get ("Content-Length" ):
938+ headers ["Content-Length" ] = response .headers ["Content-Length" ]
939+
895940 return StreamingResponse (
896- content = response .iter_content (),
897- headers = {
898- "Content-Disposition" : f'attachment; filename="{ crate } "' ,
899- "Content-Type" : response .headers .get (
900- "Content-Type" , "application/octet-stream"
901- ),
902- "Content-Length" : response .headers .get ("Content-Length" ),
903- },
941+ content = response .iter_content (chunk_size = 8192 ),
904942 status_code = response .status_code ,
943+ headers = headers ,
944+ media_type = response .headers .get ("Content-Type" , "application/octet-stream" ),
905945 )
906946
907947
@@ -997,8 +1037,8 @@ def _rewrite_pypi_url(match):
9971037
9981038 return Response (
9991039 content = content_new ,
1000- media_type = full_path_response .headers .get ("Content-Type" ),
10011040 status_code = full_path_response .status_code ,
1041+ media_type = full_path_response .headers .get ("Content-Type" ),
10021042 )
10031043
10041044
@@ -1066,10 +1106,15 @@ def _expose_wheel_metadata(response_bytes: bytes) -> bytes:
10661106 original_url = selected_package_link .group (1 )
10671107 response = http_session .get (original_url )
10681108
1109+ # Construct headers to return with response
1110+ headers : dict [str , str ] = {}
1111+ if response .headers .get ("Content-Length" ):
1112+ headers ["Content-Lengh" ] = response .headers ["Content-Length" ]
10691113 return StreamingResponse (
10701114 content = response .iter_content (chunk_size = 8192 ),
1071- media_type = response .headers .get ("Content-Type" ),
10721115 status_code = response .status_code ,
1116+ headers = headers ,
1117+ media_type = response .headers .get ("Content-Type" ),
10731118 )
10741119
10751120
0 commit comments