@@ -53,6 +53,18 @@ fn sanitize_tag_component(input: &str) -> String {
5353 . collect ( )
5454}
5555
56+ fn normalize_sas_token ( input : & str ) -> String {
57+ let trimmed = input. trim ( ) ;
58+ if trimmed. is_empty ( ) {
59+ return String :: new ( ) ;
60+ }
61+ if trimmed. starts_with ( '?' ) {
62+ trimmed. to_string ( )
63+ } else {
64+ format ! ( "?{}" , trimmed)
65+ }
66+ }
67+
5668/// Get Azure credentials from config.toml
5769fn get_azure_credentials ( name : & str ) -> AzureConfig {
5870 let cfg_content = get_config_content ( ) ;
@@ -67,7 +79,30 @@ fn get_azure_credentials(name: &str) -> AzureConfig {
6779 account : account. to_string ( ) ,
6880 key : key. to_string ( ) ,
6981 container : container. to_string ( ) ,
70- sastoken : sastoken. to_string ( ) ,
82+ sastoken : normalize_sas_token ( sastoken) ,
83+ }
84+ }
85+
86+ #[ cfg( test) ]
87+ mod tests {
88+ use super :: normalize_sas_token;
89+
90+ #[ test]
91+ fn sas_token_is_left_empty ( ) {
92+ assert_eq ! ( normalize_sas_token( "" ) , "" ) ;
93+ assert_eq ! ( normalize_sas_token( " " ) , "" ) ;
94+ }
95+
96+ #[ test]
97+ fn sas_token_is_left_intact_when_prefixed ( ) {
98+ assert_eq ! ( normalize_sas_token( "?sv=1" ) , "?sv=1" ) ;
99+ assert_eq ! ( normalize_sas_token( " ?sv=1 " ) , "?sv=1" ) ;
100+ }
101+
102+ #[ test]
103+ fn sas_token_is_prefixed_when_missing_question_mark ( ) {
104+ assert_eq ! ( normalize_sas_token( "sv=1" ) , "?sv=1" ) ;
105+ assert_eq ! ( normalize_sas_token( " sv=1 " ) , "?sv=1" ) ;
71106 }
72107}
73108
@@ -440,7 +475,36 @@ async fn get_file_from_blob(filename: String) -> ReceivedFile {
440475 // is status anything else than 200?
441476 // TODO: Do we need to return headers as well or it is data leakage?
442477 if response. status ( ) != 200 {
443- eprintln ! ( "Error getting blob: {:?}" , response. status( ) ) ;
478+ let status = response. status ( ) ;
479+ let headers = response. headers ( ) . clone ( ) ;
480+ let ms_error_code = headers
481+ . get ( "x-ms-error-code" )
482+ . and_then ( |v| v. to_str ( ) . ok ( ) )
483+ . unwrap_or ( "<missing>" ) ;
484+ let ms_request_id = headers
485+ . get ( "x-ms-request-id" )
486+ . and_then ( |v| v. to_str ( ) . ok ( ) )
487+ . unwrap_or ( "<missing>" ) ;
488+ let content_type = headers
489+ . get ( "content-type" )
490+ . and_then ( |v| v. to_str ( ) . ok ( ) )
491+ . unwrap_or ( "<missing>" ) ;
492+ let body_preview = match response. bytes ( ) . await {
493+ Ok ( bytes) => {
494+ let mut preview = String :: from_utf8_lossy ( & bytes) . into_owned ( ) ;
495+ const MAX_LEN : usize = 4096 ;
496+ if preview. len ( ) > MAX_LEN {
497+ preview. truncate ( MAX_LEN ) ;
498+ preview. push_str ( "…<truncated>" ) ;
499+ }
500+ preview
501+ }
502+ Err ( e) => format ! ( "<failed to read body: {e}>" ) ,
503+ } ;
504+
505+ eprintln ! (
506+ "Error getting blob: {status} (x-ms-error-code={ms_error_code}, x-ms-request-id={ms_request_id}, content-type={content_type}) body={body_preview}"
507+ ) ;
444508 return received_file;
445509 }
446510 received_file. headers = response. headers ( ) . clone ( ) ;
0 commit comments