@@ -279,32 +279,27 @@ impl HttpClient {
279279 }
280280 }
281281
282- if !status. is_ok ( ) {
283- // TODO: Handle 3xx redirection responses.
284- return Err ( std:: io:: Error :: new ( std:: io:: ErrorKind :: NotFound , "not found" ) ) ;
285- }
286-
287282 // Read message body
288283 let read_limit = MAX_HTTP_MESSAGE_BODY_SIZE - reader. buffer ( ) . len ( ) ;
289284 reader. get_mut ( ) . set_limit ( read_limit as u64 ) ;
290- match message_length {
291- HttpMessageLength :: Empty => { Ok ( Vec :: new ( ) ) } ,
285+ let contents = match message_length {
286+ HttpMessageLength :: Empty => { Vec :: new ( ) } ,
292287 HttpMessageLength :: ContentLength ( length) => {
293288 if length == 0 || length > MAX_HTTP_MESSAGE_BODY_SIZE {
294- Err ( std:: io:: Error :: new ( std:: io:: ErrorKind :: InvalidData , "out of range" ) )
289+ return Err ( std:: io:: Error :: new ( std:: io:: ErrorKind :: InvalidData , "out of range" ) )
295290 } else {
296291 let mut content = vec ! [ 0 ; length] ;
297292 #[ cfg( feature = "tokio" ) ]
298293 reader. read_exact ( & mut content[ ..] ) . await ?;
299294 #[ cfg( not( feature = "tokio" ) ) ]
300295 reader. read_exact ( & mut content[ ..] ) ?;
301- Ok ( content)
296+ content
302297 }
303298 } ,
304299 HttpMessageLength :: TransferEncoding ( coding) => {
305300 if !coding. eq_ignore_ascii_case ( "chunked" ) {
306- Err ( std:: io:: Error :: new (
307- std:: io:: ErrorKind :: InvalidInput , "unsupported transfer coding" ) )
301+ return Err ( std:: io:: Error :: new (
302+ std:: io:: ErrorKind :: InvalidInput , "unsupported transfer coding" ) )
308303 } else {
309304 let mut content = Vec :: new ( ) ;
310305 #[ cfg( feature = "tokio" ) ]
@@ -339,17 +334,34 @@ impl HttpClient {
339334 reader. read_exact ( & mut content[ chunk_offset..] ) . await ?;
340335 content. resize ( chunk_offset + chunk_size, 0 ) ;
341336 }
342- Ok ( content)
337+ content
343338 }
344339 #[ cfg( not( feature = "tokio" ) ) ]
345340 {
346341 let mut decoder = chunked_transfer:: Decoder :: new ( reader) ;
347342 decoder. read_to_end ( & mut content) ?;
348- Ok ( content)
343+ content
349344 }
350345 }
351346 } ,
347+ } ;
348+
349+ if !status. is_ok ( ) {
350+ // TODO: Handle 3xx redirection responses.
351+ let mut all_ascii = true ;
352+ for byte in contents. iter ( ) {
353+ if !byte. is_ascii ( ) { all_ascii = false ; }
354+ }
355+ let error_details = match all_ascii {
356+ true => String :: from_utf8_lossy ( & contents) . to_string ( ) ,
357+ false => "binary" . to_string ( )
358+ } ;
359+ let error_msg = format ! ( "Errored with status: {} and contents: {}" ,
360+ status. code, error_details) ;
361+ return Err ( std:: io:: Error :: new ( std:: io:: ErrorKind :: Other , error_msg) ) ;
352362 }
363+
364+ Ok ( contents)
353365 }
354366}
355367
@@ -720,6 +732,23 @@ pub(crate) mod client_tests {
720732 }
721733 }
722734
735+ #[ tokio:: test]
736+ async fn read_error ( ) {
737+ let response = String :: from (
738+ "HTTP/1.1 500 Internal Server Error\r \n \
739+ Content-Length: 10\r \n \r \n test error\r \n ") ;
740+ let server = HttpServer :: responding_with ( response) ;
741+
742+ let mut client = HttpClient :: connect ( & server. endpoint ( ) ) . unwrap ( ) ;
743+ match client. get :: < JsonResponse > ( "/foo" , "foo.com" ) . await {
744+ Err ( e) => {
745+ assert_eq ! ( e. get_ref( ) . unwrap( ) . to_string( ) , "Errored with status: 500 and contents: test error" ) ;
746+ assert_eq ! ( e. kind( ) , std:: io:: ErrorKind :: Other ) ;
747+ } ,
748+ Ok ( _) => panic ! ( "Expected error" ) ,
749+ }
750+ }
751+
723752 #[ tokio:: test]
724753 async fn read_empty_message_body ( ) {
725754 let server = HttpServer :: responding_with_ok :: < String > ( MessageBody :: Empty ) ;
0 commit comments