Support previously and currently documented encodings for boolean lists
diff --git a/lib/rs/src/protocol/compact.rs b/lib/rs/src/protocol/compact.rs
index 8ed4e06..4dc45ca 100644
--- a/lib/rs/src/protocol/compact.rs
+++ b/lib/rs/src/protocol/compact.rs
@@ -210,6 +210,10 @@
None => {
let b = self.read_byte()?;
match b {
+ // Previous versions of the thrift compact protocol specification said to use 0
+ // and 1 inside collections, but that differed from existing implementations.
+ // The specification was updated in https://github.com/apache/thrift/commit/2c29c5665bc442e703480bb0ee60fe925ffe02e8.
+ 0x00 => Ok(false),
0x01 => Ok(true),
0x02 => Ok(false),
unkn => Err(crate::Error::Protocol(crate::ProtocolError {
@@ -652,7 +656,11 @@
fn collection_u8_to_type(b: u8) -> crate::Result<TType> {
match b {
- 0x01 => Ok(TType::Bool),
+ // For historical and compatibility reasons, a reader should be capable to deal with both cases.
+ // The only valid value in the original spec was 2, but due to a widespread implementation bug
+ // the defacto standard across large parts of the library became 1 instead.
+ // As a result, both values are now allowed.
+ 0x01 | 0x02 => Ok(TType::Bool),
o => u8_to_type(o),
}
}
@@ -2839,4 +2847,40 @@
assert!(write_fn(&mut o_prot).is_ok());
assert_eq!(o_prot.transport.write_bytes().len(), 0);
}
+
+ #[test]
+ fn must_read_boolean_list() {
+ let (mut i_prot, _) = test_objects();
+
+ let source_bytes: [u8; 3] = [0x21, 2, 1];
+
+ i_prot.transport.set_readable_bytes(&source_bytes);
+
+ let (ttype, element_count) = assert_success!(i_prot.read_list_set_begin());
+
+ assert_eq!(ttype, TType::Bool);
+ assert_eq!(element_count, 2);
+ assert_eq!(i_prot.read_bool().unwrap(), false);
+ assert_eq!(i_prot.read_bool().unwrap(), true);
+
+ assert_success!(i_prot.read_list_end());
+ }
+
+ #[test]
+ fn must_read_boolean_list_alternative_encoding() {
+ let (mut i_prot, _) = test_objects();
+
+ let source_bytes: [u8; 3] = [0x22, 0, 1];
+
+ i_prot.transport.set_readable_bytes(&source_bytes);
+
+ let (ttype, element_count) = assert_success!(i_prot.read_list_set_begin());
+
+ assert_eq!(ttype, TType::Bool);
+ assert_eq!(element_count, 2);
+ assert_eq!(i_prot.read_bool().unwrap(), false);
+ assert_eq!(i_prot.read_bool().unwrap(), true);
+
+ assert_success!(i_prot.read_list_end());
+ }
}