From 9654ee237b7042a824d3d0f9055947456f80ce2a Mon Sep 17 00:00:00 2001 From: Gary Yu Date: Fri, 29 Jun 2018 23:03:06 +0800 Subject: [PATCH] Panic on chain/outputs API (#1086) (#1089) --- api/src/handlers.rs | 46 ++++++++++++++++++++++++++++++++++++++++----- util/src/hex.rs | 18 ++++++++++++++++-- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/api/src/handlers.rs b/api/src/handlers.rs index ed55386d..91d15864 100644 --- a/api/src/handlers.rs +++ b/api/src/handlers.rs @@ -57,6 +57,11 @@ impl Handler for IndexHandler { } } +struct HandlerResult { + with_status: status::Status, + with_body: String, +} + // Supports retrieval of multiple outputs in a single request - // GET /v1/chain/outputs/byids?id=xxx,yyy,zzz // GET /v1/chain/outputs/byids?id=xxx&id=yyy&id=zzz @@ -158,7 +163,11 @@ impl OutputHandler { } // returns outputs for a specified range of blocks - fn outputs_block_batch(&self, req: &mut Request) -> Vec { + fn outputs_block_batch( + &self, + req: &mut Request, + result: &mut HandlerResult, + ) -> Vec { let mut commitments: Vec = vec![]; let mut start_height = 1; let mut end_height = 1; @@ -176,12 +185,28 @@ impl OutputHandler { } if let Some(heights) = params.get("start_height") { for height in heights { - start_height = height.parse().unwrap(); + start_height = match height.parse() { + Ok(h) => h, + _ => { + result.with_status = status::BadRequest; + result.with_body = + String::from("start_height parse error. check request format"); + return vec![]; + } + } } } if let Some(heights) = params.get("end_height") { for height in heights { - end_height = height.parse().unwrap(); + end_height = match height.parse() { + Ok(h) => h, + _ => { + result.with_status = status::BadRequest; + result.with_body = + String::from("end_height parse error. check request format"); + return vec![]; + } + } } } if let Some(_) = params.get("include_rp") { @@ -217,10 +242,21 @@ impl Handler for OutputHandler { if *path_elems.last().unwrap() == "" { path_elems.pop(); } - match *path_elems.last().unwrap() { + + let mut result = HandlerResult { + with_status: status::Ok, + with_body: String::new(), + }; + + let response = match *path_elems.last().unwrap() { "byids" => json_response(&self.outputs_by_ids(req)), - "byheight" => json_response(&self.outputs_block_batch(req)), + "byheight" => json_response(&self.outputs_block_batch(req, &mut result)), _ => Ok(Response::with((status::BadRequest, ""))), + }; + + match result.with_status { + status::Ok => response, + _ => Ok(Response::with((result.with_status, result.with_body))), } } } diff --git a/util/src/hex.rs b/util/src/hex.rs index 683addf2..31fb0c09 100644 --- a/util/src/hex.rs +++ b/util/src/hex.rs @@ -16,7 +16,6 @@ /// to bytes. Given that rustc-serialize is deprecated and serde doesn't /// provide easy hex encoding, hex is a bit in limbo right now in Rust- /// land. It's simple enough that we can just have our own. - use std::fmt::Write; use std::num; @@ -31,11 +30,17 @@ pub fn to_hex(bytes: Vec) -> String { /// Decode a hex string into bytes. pub fn from_hex(hex_str: String) -> Result, num::ParseIntError> { - let hex_trim = if &hex_str[..2] == "0x" { + let mut hex_trim = if hex_str.len() >= 2 && &hex_str[..2] == "0x" { hex_str[2..].to_owned() } else { hex_str.clone() }; + + // fill one nibble if having half byte tail + if hex_trim.len() & 1 != 0 { + hex_trim.push('0'); + } + split_n(&hex_trim.trim()[..], 2) .iter() .map(|b| u8::from_str_radix(b, 16)) @@ -43,6 +48,9 @@ pub fn from_hex(hex_str: String) -> Result, num::ParseIntError> { } fn split_n(s: &str, n: usize) -> Vec<&str> { + if s.len() < n { + return vec![]; + } (0..(s.len() - n + 1) / 2 + 1) .map(|i| &s[2 * i..2 * i + n]) .collect() @@ -70,5 +78,11 @@ mod test { from_hex("000000ff".to_string()).unwrap(), vec![0, 0, 0, 255] ); + assert!( + from_hex("".to_string()).is_ok(), + "should return Ok([]) for empty string" + ); + assert_eq!(from_hex("0".to_string()).unwrap(), vec![0]); + assert_eq!(from_hex("0ff".to_string()).unwrap(), vec![15, 240]); } }