Repository: AlexPikalov/cdrs (language: rust)

Issue:
Fix parsing a body which contains null and not-set values
Found in #96 

Description: when body contains null or not-set values `.get_body()` runs out of memory.

Root cause: issue with parsing negative integers


Discussion / hints:

Fix patch:
diff --git a/src/types/mod.rs b/src/types/mod.rs
index 7a4d497..870afc8 100644
--- a/src/types/mod.rs
+++ b/src/types/mod.rs
@@ -84,6 +84,12 @@ pub fn try_i32_from_bytes(bytes: &[u8]) -> Result<i32, io::Error> {
     return c.read_i32::<BigEndian>();
 }
 
+/// Tries to decode bytes array into `i16`.
+pub fn try_i16_from_bytes(bytes: &[u8]) -> Result<i16, io::Error> {
+    let mut c = Cursor::new(bytes);
+    return c.read_i16::<BigEndian>();
+}
+
 /// Tries to decode bytes array into `f32`.
 pub fn try_f32_from_bytes(bytes: &[u8]) -> Result<f32, io::Error> {
     let mut c = Cursor::new(bytes);
@@ -353,8 +359,12 @@ impl FromCursor for CBytes {
     /// from_cursor gets Cursor who's position is set such that it should be a start of a [bytes].
     /// It reads required number of bytes and returns a CBytes
     fn from_cursor(mut cursor: &mut Cursor<&[u8]>) -> CBytes {
-        let len: u64 = CInt::from_cursor(&mut cursor) as u64;
-        return CBytes { bytes: cursor_next_value(&mut cursor, len) };
+        let len = CInt::from_cursor(&mut cursor);
+        // null or not set value
+        if len < 0 {
+            return CBytes { bytes: vec![] };
+        }
+        return CBytes { bytes: cursor_next_value(&mut cursor, len as u64) };
     }
 }
 
@@ -412,7 +422,7 @@ pub type CInt = i32;
 impl FromCursor for CInt {
     fn from_cursor(mut cursor: &mut Cursor<&[u8]>) -> CInt {
         let bytes = cursor_next_value(&mut cursor, INT_LEN as u64);
-        return from_bytes(bytes.as_slice()) as CInt;
+        try_i32_from_bytes(bytes.as_slice()).unwrap() as CInt
     }
 }
 
@@ -422,7 +432,7 @@ pub type CIntShort = i16;
 impl FromCursor for CIntShort {
     fn from_cursor(mut cursor: &mut Cursor<&[u8]>) -> CIntShort {
         let bytes = cursor_next_value(&mut cursor, SHORT_LEN as u64);
-        return from_bytes(bytes.as_slice()) as CIntShort;
+        try_i16_from_bytes(bytes.as_slice()).unwrap() as CIntShort
     }
 }
 


Test patch:
diff --git a/tests/create_insert_table.rs b/tests/create_insert_table.rs
index 049e34d..f6d1c82 100644
--- a/tests/create_insert_table.rs
+++ b/tests/create_insert_table.rs
@@ -79,10 +79,9 @@ fn insert_data_users() {
     println!("insert_data_users");
     let ctx = TestContext::new();
     let mut session = ctx.client.start(Compression::None).unwrap();
-    let insert_table_cql = " insert into user_keyspace.users
-            (user_name ,password,gender,session_token, state)
-    values  (?         ,  ?     ,     ?,            ?,     ?)";
-
+    let insert_table_cql = "INSERT INTO user_keyspace.users
+            (user_name, password, gender, session_token, state)
+    VALUES (?, ?, ?, ?, ?)";
 
     let prepared = session.prepare(insert_table_cql.to_string(), true, true)
         .unwrap()
@@ -92,17 +91,13 @@ fn insert_data_users() {
 
     println!("prepared:\n{:?}", prepared);
 
-    let v: Vec<Value> = vec!["harry".to_string().into(),
-                             "pwd".to_string().into(),
-                             "male".to_string().into(),
-                             "09000".to_string().into(),
-                             "FL".to_string().into()];
+    let v: Vec<Value> =
+        vec!["harry".into(), "pwd".into(), "male".into(), "09000".into(), "FL".into()];
     let execution_params = QueryParamsBuilder::new(Consistency::One).values(v).finalize();
 
     let ref query_id = prepared.id;
     let executed = session.execute(query_id, execution_params, true, true);
 
-
     info!("executed:\n{:?}", executed);
 }
 
@@ -110,11 +105,10 @@ fn read_from_user_table() {
     println!("read_from_user_table");
     let ctx = TestContext::new();
     let mut session = ctx.client.start(Compression::None).unwrap();
-    let select_query = QueryBuilder::new("SELECT user_name ,password,gender,session_token, state
+    let select_query = QueryBuilder::new("SELECT user_name, password, gender, session_token, state
      FROM user_keyspace.users")
         .finalize();
 
-
     let query_op = session.query(select_query, true, true);
 
     match query_op {
@@ -175,8 +169,8 @@ impl TestContext {
 fn create_keyspace() {
     let ctx = TestContext::new();
     let mut session = ctx.client.start(Compression::None).unwrap();
-    let create_ks_cql = "CREATE KEYSPACE user_keyspace WITH REPLICATION = { 'class' : \
-                         'SimpleStrategy', 'replication_factor' : 1 } ;";
+    let create_ks_cql = "CREATE KEYSPACE IF NOT EXISTS user_keyspace WITH REPLICATION = { 'class' \
+                         : 'SimpleStrategy', 'replication_factor' : 1 } ;";
 
     let create_ks_query = QueryBuilder::new(create_ks_cql)
         .consistency(Consistency::One)
@@ -191,7 +185,7 @@ fn create_keyspace() {
 fn create_table() {
     let ctx = TestContext::new();
     let mut session = ctx.client.start(Compression::None).unwrap();
-    let create_table_cql = "CREATE TABLE user_keyspace.users (
+    let create_table_cql = "CREATE TABLE IF NOT EXISTS user_keyspace.users (
         user_name varchar PRIMARY KEY,
         password varchar,
         gender varchar,