2525// cargo mutants -f s3.rs --no-config -C --features=s3,s3-integration-test
2626
2727use std:: fmt;
28- use std:: path:: Path ;
2928use std:: sync:: Arc ;
29+ use std:: time:: SystemTime ;
3030
3131use aws_config:: { AppName , BehaviorVersion } ;
3232use aws_sdk_s3:: error:: SdkError ;
@@ -73,7 +73,11 @@ impl Protocol {
7373 let runtime = tokio:: runtime:: Builder :: new_current_thread ( )
7474 . enable_all ( )
7575 . build ( )
76- . map_err ( |err| Error :: io_error ( Path :: new ( "" ) , err) ) ?;
76+ . map_err ( |source| Error {
77+ kind : ErrorKind :: CreateTransport ,
78+ url : Some ( url. to_owned ( ) ) ,
79+ source : Some ( Box :: new ( source) ) ,
80+ } ) ?;
7781
7882 let bucket = url. authority ( ) . to_owned ( ) ;
7983 assert ! ( !bucket. is_empty( ) , "S3 bucket name is empty in {url:?}" ) ;
@@ -121,6 +125,24 @@ impl Protocol {
121125 fn join_path ( & self , relpath : & str ) -> String {
122126 join_paths ( & self . base_path , relpath)
123127 }
128+
129+ fn s3_error < E , R > ( & self , key : & str , source : SdkError < E , R > ) -> Error
130+ where
131+ E : std:: error:: Error + Send + Sync + ' static ,
132+ R : std:: fmt:: Debug + Send + Sync + ' static ,
133+ ErrorKind : for < ' a > From < & ' a E > ,
134+ {
135+ debug ! ( s3_error = ?source) ;
136+ let kind = match & source {
137+ SdkError :: ServiceError ( service_err) => ErrorKind :: from ( service_err. err ( ) ) ,
138+ _ => ErrorKind :: Other ,
139+ } ;
140+ Error {
141+ kind,
142+ url : self . url . join ( key) . ok ( ) ,
143+ source : Some ( source. into ( ) ) ,
144+ }
145+ }
124146}
125147
126148impl fmt:: Debug for Protocol {
@@ -221,7 +243,7 @@ impl super::Protocol for Protocol {
221243 result. files . push ( name. to_owned ( ) ) ;
222244 }
223245 }
224- Some ( Err ( err) ) => return Err ( s3_error ( prefix, err) ) ,
246+ Some ( Err ( err) ) => return Err ( self . s3_error ( & prefix, err) ) ,
225247 None => break ,
226248 }
227249 }
@@ -240,13 +262,13 @@ impl super::Protocol for Protocol {
240262 let response = self
241263 . runtime
242264 . block_on ( request. send ( ) )
243- . map_err ( |source| s3_error ( key. clone ( ) , source) ) ?;
265+ . map_err ( |source| self . s3_error ( & key, source) ) ?;
244266 let body_bytes = self
245267 . runtime
246268 . block_on ( response. body . collect ( ) )
247269 . map_err ( |source| Error {
248270 kind : ErrorKind :: Other ,
249- path : Some ( key . clone ( ) ) ,
271+ url : self . url . join ( relpath ) . ok ( ) ,
250272 source : Some ( Box :: new ( source) ) ,
251273 } ) ?
252274 . into_bytes ( ) ;
@@ -279,7 +301,7 @@ impl super::Protocol for Protocol {
279301 }
280302 let response = self . runtime . block_on ( request. send ( ) ) ;
281303 // trace!(?response);
282- response. map_err ( |err| s3_error ( key, err) ) ?;
304+ response. map_err ( |err| self . s3_error ( & key, err) ) ?;
283305 trace ! ( body_len = content. len( ) , "wrote file" ) ;
284306 Ok ( ( ) )
285307 }
@@ -290,7 +312,7 @@ impl super::Protocol for Protocol {
290312 let request = self . client . delete_object ( ) . bucket ( & self . bucket ) . key ( & key) ;
291313 let response = self . runtime . block_on ( request. send ( ) ) ;
292314 trace ! ( ?response) ;
293- response. map_err ( |err| s3_error ( key, err) ) ?;
315+ response. map_err ( |err| self . s3_error ( & key, err) ) ?;
294316 trace ! ( "deleted file" ) ;
295317 Ok ( ( ) )
296318 }
@@ -311,7 +333,7 @@ impl super::Protocol for Protocol {
311333 let mut n_files = 0 ;
312334 while let Some ( response) = self . runtime . block_on ( stream. next ( ) ) {
313335 for object in response
314- . map_err ( |err| s3_error ( prefix. clone ( ) , err) ) ?
336+ . map_err ( |err| self . s3_error ( & prefix, err) ) ?
315337 . contents
316338 . expect ( "ListObjectsV2Response has contents" )
317339 {
@@ -324,7 +346,7 @@ impl super::Protocol for Protocol {
324346 . key ( & key)
325347 . send ( ) ,
326348 )
327- . map_err ( |err| s3_error ( key, err) ) ?;
349+ . map_err ( |err| self . s3_error ( & key, err) ) ?;
328350 n_files += 1 ;
329351 }
330352 }
@@ -346,14 +368,20 @@ impl super::Protocol for Protocol {
346368 . expect ( "S3 HeadObject response should have a content_length" )
347369 . try_into ( )
348370 . expect ( "Content length non-negative" ) ;
371+ let modified: SystemTime = response
372+ . last_modified
373+ . expect ( "S3 HeadObject response should have a last_modified" )
374+ . try_into ( )
375+ . expect ( "S3 last_modified is valid SystemTime" ) ;
349376 trace ! ( ?len, "File exists" ) ;
350377 Ok ( Metadata {
351378 kind : Kind :: File ,
352379 len,
380+ modified : modified. into ( ) ,
353381 } )
354382 }
355383 Err ( err) => {
356- let translated = s3_error ( key, err) ;
384+ let translated = self . s3_error ( & key, err) ;
357385 if translated. is_not_found ( ) {
358386 trace ! ( "file does not exist" ) ;
359387 } else {
@@ -380,25 +408,6 @@ impl super::Protocol for Protocol {
380408 }
381409}
382410
383- fn s3_error < K , E , R > ( key : K , source : SdkError < E , R > ) -> Error
384- where
385- K : ToOwned < Owned = String > ,
386- E : std:: error:: Error + Send + Sync + ' static ,
387- R : std:: fmt:: Debug + Send + Sync + ' static ,
388- ErrorKind : for < ' a > From < & ' a E > ,
389- {
390- debug ! ( s3_error = ?source) ;
391- let kind = match & source {
392- SdkError :: ServiceError ( service_err) => ErrorKind :: from ( service_err. err ( ) ) ,
393- _ => ErrorKind :: Other ,
394- } ;
395- Error {
396- kind,
397- path : Some ( key. to_owned ( ) ) ,
398- source : Some ( source. into ( ) ) ,
399- }
400- }
401-
402411impl From < & GetObjectError > for ErrorKind {
403412 fn from ( source : & GetObjectError ) -> Self {
404413 match source {
0 commit comments