@@ -118,6 +118,22 @@ pub enum Error {
118118 UpdateNotImplemented ,
119119}
120120
121+ /// We need to implement to string because we are sending the errors to the clients by
122+ /// using json_fault_message function that expects a type which implements AsRef<str>.
123+ /// When using the default Debug formatting, we end up with invalid jsons because we don't
124+ /// escape the quotes in the error message.
125+ impl ToString for Error {
126+ fn to_string ( & self ) -> String {
127+ match self {
128+ Error :: InstanceStartFailed ( _, ref err_msg) => err_msg. replace ( "\" " , "" ) ,
129+ _ => {
130+ let err_msg = format ! ( "{:?}" , self ) ;
131+ err_msg. replace ( "\" " , "" )
132+ }
133+ }
134+ }
135+ }
136+
121137#[ derive( Debug ) ]
122138pub enum ErrorType {
123139 UserError ,
@@ -137,13 +153,13 @@ impl GenerateResponse for Error {
137153 StatusCode :: BadRequest ,
138154 json_fault_message ( "The specified guest MAC address is already in use." ) ,
139155 ) ,
140- InstanceStartFailed ( ref error_type, ref error_msg ) => {
156+ InstanceStartFailed ( ref error_type, _ ) => {
141157 let status_code = match error_type {
142158 ErrorType :: InternalError => StatusCode :: InternalServerError ,
143159 ErrorType :: UserError => StatusCode :: BadRequest ,
144160 } ;
145161
146- json_response ( status_code, json_fault_message ( error_msg ) )
162+ json_response ( status_code, json_fault_message ( self . to_string ( ) ) )
147163 }
148164 InvalidPayload => json_response (
149165 StatusCode :: BadRequest ,
@@ -153,9 +169,9 @@ impl GenerateResponse for Error {
153169 StatusCode :: Forbidden ,
154170 json_fault_message ( "The microVM is already running." ) ,
155171 ) ,
156- OpenTap ( ref e ) => json_response (
172+ OpenTap ( _ ) => json_response (
157173 StatusCode :: BadRequest ,
158- json_fault_message ( format ! ( "Could not open TAP device. {:? }" , e ) ) ,
174+ json_fault_message ( format ! ( "Could not open TAP device. {}" , self . to_string ( ) ) ) ,
159175 ) ,
160176 OperationFailed => json_response (
161177 StatusCode :: BadRequest ,
@@ -220,7 +236,9 @@ impl PartialEq for ParsedRequest {
220236mod tests {
221237 use super :: * ;
222238
223- use serde_json:: Map ;
239+ use futures:: { Future , Stream } ;
240+ use hyper:: { Body , Response } ;
241+ use serde_json:: { self , Map } ;
224242 use std;
225243
226244 // Implementation for the "==" operator.
@@ -293,47 +311,73 @@ mod tests {
293311 assert_eq ! ( ret. status( ) , StatusCode :: NoContent ) ;
294312 }
295313
314+ fn get_body (
315+ response : Response < Body > ,
316+ ) -> std:: result:: Result < serde_json:: Value , serde_json:: Error > {
317+ let body = response
318+ . body ( )
319+ . map_err ( |_| ( ) )
320+ . fold ( vec ! [ ] , |mut acc, chunk| {
321+ acc. extend_from_slice ( & chunk) ;
322+ Ok ( acc)
323+ } ) . and_then ( |v| String :: from_utf8 ( v) . map_err ( |_| ( ) ) ) ;
324+ serde_json:: from_str :: < Value > ( body. wait ( ) . unwrap ( ) . as_ref ( ) )
325+ }
326+
296327 #[ test]
297328 fn test_generate_response_error ( ) {
298329 let mut ret =
299330 Error :: DriveOperationFailed ( DriveError :: InvalidBlockDeviceID ) . generate_response ( ) ;
300331 assert_eq ! ( ret. status( ) , StatusCode :: BadRequest ) ;
332+ assert ! ( get_body( ret) . is_ok( ) ) ;
301333
302334 ret = Error :: GuestCIDAlreadyInUse . generate_response ( ) ;
303335 assert_eq ! ( ret. status( ) , StatusCode :: BadRequest ) ;
336+ assert ! ( get_body( ret) . is_ok( ) ) ;
304337
305338 ret = Error :: GuestMacAddressInUse . generate_response ( ) ;
306339 assert_eq ! ( ret. status( ) , StatusCode :: BadRequest ) ;
340+ assert ! ( get_body( ret) . is_ok( ) ) ;
307341
308- ret = Error :: InstanceStartFailed ( ErrorType :: InternalError , "Dummy error" . to_string ( ) )
309- . generate_response ( ) ;
342+ ret = Error :: InstanceStartFailed (
343+ ErrorType :: InternalError ,
344+ "Dummy error message." . to_string ( ) ,
345+ ) . generate_response ( ) ;
310346 assert_eq ! ( ret. status( ) , StatusCode :: InternalServerError ) ;
347+ assert ! ( get_body( ret) . is_ok( ) ) ;
311348
312- ret = Error :: InstanceStartFailed ( ErrorType :: UserError , "Dummy error" . to_string ( ) )
349+ ret = Error :: InstanceStartFailed ( ErrorType :: UserError , "Dummy error message. " . to_string ( ) )
313350 . generate_response ( ) ;
314351 assert_eq ! ( ret. status( ) , StatusCode :: BadRequest ) ;
352+ assert ! ( get_body( ret) . is_ok( ) ) ;
315353
316354 ret = Error :: InvalidPayload . generate_response ( ) ;
317355 assert_eq ! ( ret. status( ) , StatusCode :: BadRequest ) ;
356+ assert ! ( get_body( ret) . is_ok( ) ) ;
318357
319358 ret = Error :: MicroVMAlreadyRunning . generate_response ( ) ;
320359 assert_eq ! ( ret. status( ) , StatusCode :: Forbidden ) ;
360+ assert ! ( get_body( ret) . is_ok( ) ) ;
321361
322362 ret = Error :: OpenTap ( TapError :: OpenTun ( std:: io:: Error :: from_raw_os_error ( 22 ) ) )
323363 . generate_response ( ) ;
324364 assert_eq ! ( ret. status( ) , StatusCode :: BadRequest ) ;
365+ assert ! ( get_body( ret) . is_ok( ) ) ;
325366
326367 ret = Error :: OperationFailed . generate_response ( ) ;
327368 assert_eq ! ( ret. status( ) , StatusCode :: BadRequest ) ;
369+ assert ! ( get_body( ret) . is_ok( ) ) ;
328370
329371 ret = Error :: OperationNotAllowedPreBoot . generate_response ( ) ;
330372 assert_eq ! ( ret. status( ) , StatusCode :: Forbidden ) ;
373+ assert ! ( get_body( ret) . is_ok( ) ) ;
331374
332375 ret = Error :: UpdateNotAllowedPostBoot . generate_response ( ) ;
333376 assert_eq ! ( ret. status( ) , StatusCode :: Forbidden ) ;
377+ assert ! ( get_body( ret) . is_ok( ) ) ;
334378
335379 ret = Error :: UpdateNotImplemented . generate_response ( ) ;
336380 assert_eq ! ( ret. status( ) , StatusCode :: InternalServerError ) ;
381+ assert ! ( get_body( ret) . is_ok( ) ) ;
337382 }
338-
339383}
0 commit comments