Adds length-prefixed read to BigEndianReader
A common task when parsing encoded structs from a network is to
read a serialization of an object with (possibly nested) length-prefixed
members.
//third_party/boringssl's Crypto ByteString bakes
support for this in by having a "length-prefixed read" API that
initially reads a big-endian length L from the buffer, then constructs
and returns a new reader on the L many bytes immediately following
the length, skipping the parent reader over this substring. However,
this API is C-style and, as a consequence, perhaps not suitable for
wide use in Chromium code.
This patch adds similar functionality to base::BigEndianReader
by adding ReadU8LengthPrefixed and ReadU16LengthPrefixed methods.
R=mark
Change-Id: Idaf0b04b414a3484099a861ef02501e5f8a83a47
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1860518
Commit-Queue: David Van Cleve <[email protected]>
Reviewed-by: Mark Mentovai <[email protected]>
Cr-Commit-Position: refs/heads/master@{#706074}
diff --git a/base/big_endian_unittest.cc b/base/big_endian_unittest.cc
index 7f8d9a5..07c208a 100644
--- a/base/big_endian_unittest.cc
+++ b/base/big_endian_unittest.cc
@@ -42,6 +42,64 @@
EXPECT_EQ(expected.data(), piece.data());
}
+TEST(BigEndianReaderTest, ReadsLengthPrefixedValues) {
+ {
+ char u8_prefixed_data[] = {8, 8, 9, 0xA, 0xB, 0xC, 0xD,
+ 0xE, 0xF, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E};
+ BigEndianReader reader(u8_prefixed_data, sizeof(u8_prefixed_data));
+
+ base::StringPiece piece;
+ ASSERT_TRUE(reader.ReadU8LengthPrefixed(&piece));
+ // |reader| should skip both a u8 and the length-8 length-prefixed field.
+ EXPECT_EQ(reader.ptr(), u8_prefixed_data + 9);
+ EXPECT_EQ(piece.size(), 8u);
+ EXPECT_EQ(piece.data(), u8_prefixed_data + 1);
+ }
+
+ {
+ char u16_prefixed_data[] = {0, 8, 0xD, 0xE, 0xF,
+ 0x1A, 0x2B, 0x3C, 0x4D, 0x5E};
+ BigEndianReader reader(u16_prefixed_data, sizeof(u16_prefixed_data));
+ base::StringPiece piece;
+ ASSERT_TRUE(reader.ReadU16LengthPrefixed(&piece));
+ // |reader| should skip both a u16 and the length-8 length-prefixed field.
+ EXPECT_EQ(reader.ptr(), u16_prefixed_data + 10);
+ EXPECT_EQ(piece.size(), 8u);
+ EXPECT_EQ(piece.data(), u16_prefixed_data + 2);
+
+ // With no data left, we shouldn't be able to
+ // read another u8 length prefix (or a u16 length prefix,
+ // for that matter).
+ EXPECT_FALSE(reader.ReadU8LengthPrefixed(&piece));
+ EXPECT_FALSE(reader.ReadU16LengthPrefixed(&piece));
+ }
+
+ {
+ // Make sure there's no issue reading a zero-value length prefix.
+ char u16_prefixed_data[3] = {};
+ BigEndianReader reader(u16_prefixed_data, sizeof(u16_prefixed_data));
+ base::StringPiece piece;
+ ASSERT_TRUE(reader.ReadU16LengthPrefixed(&piece));
+ EXPECT_EQ(reader.ptr(), u16_prefixed_data + 2);
+ EXPECT_EQ(piece.data(), u16_prefixed_data + 2);
+ EXPECT_EQ(piece.size(), 0u);
+ }
+}
+
+TEST(BigEndianReaderTest, LengthPrefixedReadsFailGracefully) {
+ // We can't read 0xF (or, for that matter, 0xF8) bytes after the length
+ // prefix: there isn't enough data.
+ char data[] = {0xF, 8, 9, 0xA, 0xB, 0xC, 0xD,
+ 0xE, 0xF, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E};
+ BigEndianReader reader(data, sizeof(data));
+ base::StringPiece piece;
+ EXPECT_FALSE(reader.ReadU8LengthPrefixed(&piece));
+ EXPECT_EQ(data, reader.ptr());
+
+ EXPECT_FALSE(reader.ReadU16LengthPrefixed(&piece));
+ EXPECT_EQ(data, reader.ptr());
+}
+
TEST(BigEndianReaderTest, RespectsLength) {
char data[8];
char buf[2];