Skip to content

Commit bcb79bd

Browse files
api_server: fix bug when creating body for errors
The fault message for creating a tap device had nesting quotes, which was making the API server return an invalid JSON. Implemented ToString for Sync Errors in which we strip the quotes from the Error message. Signed-off-by: Andreea Florescu <[email protected]>
1 parent f0ef0d5 commit bcb79bd

File tree

1 file changed

+53
-9
lines changed

1 file changed

+53
-9
lines changed

api_server/src/request/mod.rs

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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)]
122138
pub 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 {
220236
mod 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

Comments
 (0)