ToHex shouldn't require padding between bytes.

This was getting obnoxious for SHA-1s, and particularly so when serving them
as etags.
This commit is contained in:
Scott Lamb 2016-01-13 06:51:23 -08:00
parent 29696688b5
commit 95523c3522
9 changed files with 33 additions and 31 deletions

View File

@ -45,13 +45,13 @@ namespace {
TEST(DigestTest, Sha1) { TEST(DigestTest, Sha1) {
auto sha1 = Digest::SHA1(); auto sha1 = Digest::SHA1();
EXPECT_EQ("da 39 a3 ee 5e 6b 4b 0d 32 55 bf ef 95 60 18 90 af d8 07 09", EXPECT_EQ("da39a3ee5e6b4b0d3255bfef95601890afd80709",
ToHex(sha1->Finalize())); ToHex(sha1->Finalize()));
sha1 = Digest::SHA1(); sha1 = Digest::SHA1();
sha1->Update("hello"); sha1->Update("hello");
sha1->Update(" world"); sha1->Update(" world");
EXPECT_EQ("2a ae 6c 35 c9 4f cf b4 15 db e9 5f 40 8b 9c e9 1e e8 46 ed", EXPECT_EQ("2aae6c35c94fcfb415dbe95f408b9ce91ee846ed",
ToHex(sha1->Finalize())); ToHex(sha1->Finalize()));
} }

View File

@ -70,7 +70,7 @@ TEST(H264Test, DecodeOnly) {
re2::StringPiece test_input(reinterpret_cast<const char *>(kAnnexBTestInput), re2::StringPiece test_input(reinterpret_cast<const char *>(kAnnexBTestInput),
sizeof(kAnnexBTestInput)); sizeof(kAnnexBTestInput));
internal::NalUnitFunction fn = [&nal_units_hexed](re2::StringPiece nal_unit) { internal::NalUnitFunction fn = [&nal_units_hexed](re2::StringPiece nal_unit) {
nal_units_hexed.push_back(ToHex(nal_unit)); nal_units_hexed.push_back(ToHex(nal_unit, true));
return IterationControl::kContinue; return IterationControl::kContinue;
}; };
std::string error_message; std::string error_message;
@ -91,7 +91,7 @@ TEST(H264Test, SampleDataFromAnnexBExtraData) {
GetH264SampleEntry(test_input, 1280, 720, &sample_entry, &error_message)) GetH264SampleEntry(test_input, 1280, 720, &sample_entry, &error_message))
<< error_message; << error_message;
EXPECT_EQ(kTestOutput, ToHex(sample_entry)); EXPECT_EQ(kTestOutput, ToHex(sample_entry, true));
} }
TEST(H264Test, SampleDataFromAvcDecoderConfigExtraData) { TEST(H264Test, SampleDataFromAvcDecoderConfigExtraData) {
@ -104,7 +104,7 @@ TEST(H264Test, SampleDataFromAvcDecoderConfigExtraData) {
GetH264SampleEntry(test_input, 1280, 720, &sample_entry, &error_message)) GetH264SampleEntry(test_input, 1280, 720, &sample_entry, &error_message))
<< error_message; << error_message;
EXPECT_EQ(kTestOutput, ToHex(sample_entry)); EXPECT_EQ(kTestOutput, ToHex(sample_entry, true));
} }
} // namespace } // namespace

View File

@ -92,8 +92,8 @@ bool DecodeH264AnnexB(re2::StringPiece data, NalUnitFunction process_nal_unit,
static const RE2 kStartCode("(\\x00{2,}\\x01)"); static const RE2 kStartCode("(\\x00{2,}\\x01)");
if (!RE2::Consume(&data, kStartCode)) { if (!RE2::Consume(&data, kStartCode)) {
*error_message = *error_message = StrCat("stream does not start with Annex B start code: ",
StrCat("stream does not start with Annex B start code: ", ToHex(data)); ToHex(data, true));
return false; return false;
} }

View File

@ -52,15 +52,18 @@ using moonfire_nvr::internal::Mp4SampleTablePieces;
namespace moonfire_nvr { namespace moonfire_nvr {
namespace { namespace {
std::string ToHex(const FileSlice *slice) { std::string ToHex(const FileSlice *slice, bool pad) {
EvBuffer buf; EvBuffer buf;
std::string error_message; std::string error_message;
size_t size = slice->size(); size_t size = slice->size();
CHECK(slice->AddRange(ByteRange(0, size), &buf, &error_message)) CHECK(slice->AddRange(ByteRange(0, size), &buf, &error_message))
<< error_message; << error_message;
CHECK_EQ(size, evbuffer_get_length(buf.get())); CHECK_EQ(size, evbuffer_get_length(buf.get()));
return ::moonfire_nvr::ToHex(re2::StringPiece( return ::moonfire_nvr::ToHex(
reinterpret_cast<const char *>(evbuffer_pullup(buf.get(), size)), size)); re2::StringPiece(
reinterpret_cast<const char *>(evbuffer_pullup(buf.get(), size)),
size),
pad);
} }
TEST(Mp4SampleTablePiecesTest, Stts) { TEST(Mp4SampleTablePiecesTest, Stts) {
@ -81,7 +84,7 @@ TEST(Mp4SampleTablePiecesTest, Stts) {
"00 00 00 01 00 00 00 02 " "00 00 00 01 00 00 00 02 "
"00 00 00 01 00 00 00 03 " "00 00 00 01 00 00 00 03 "
"00 00 00 01 00 00 00 04"; "00 00 00 01 00 00 00 04";
EXPECT_EQ(kExpectedEntries, ToHex(pieces.stts_entries())); EXPECT_EQ(kExpectedEntries, ToHex(pieces.stts_entries(), true));
} }
TEST(Mp4SampleTablePiecesTest, SttsAfterSyncSample) { TEST(Mp4SampleTablePiecesTest, SttsAfterSyncSample) {
@ -102,7 +105,7 @@ TEST(Mp4SampleTablePiecesTest, SttsAfterSyncSample) {
"00 00 00 01 00 00 00 02 " "00 00 00 01 00 00 00 02 "
"00 00 00 01 00 00 00 03 " "00 00 00 01 00 00 00 03 "
"00 00 00 01 00 00 00 04"; "00 00 00 01 00 00 00 04";
EXPECT_EQ(kExpectedEntries, ToHex(pieces.stts_entries())); EXPECT_EQ(kExpectedEntries, ToHex(pieces.stts_entries(), true));
} }
TEST(Mp4SampleTablePiecesTest, Stss) { TEST(Mp4SampleTablePiecesTest, Stss) {
@ -117,7 +120,7 @@ TEST(Mp4SampleTablePiecesTest, Stss) {
<< error_message; << error_message;
EXPECT_EQ(2, pieces.stss_entry_count()); EXPECT_EQ(2, pieces.stss_entry_count());
const char kExpectedSampleNumbers[] = "00 00 00 0a 00 00 00 0c"; const char kExpectedSampleNumbers[] = "00 00 00 0a 00 00 00 0c";
EXPECT_EQ(kExpectedSampleNumbers, ToHex(pieces.stss_entries())); EXPECT_EQ(kExpectedSampleNumbers, ToHex(pieces.stss_entries(), true));
} }
TEST(Mp4SampleTablePiecesTest, Stsc) { TEST(Mp4SampleTablePiecesTest, Stsc) {
@ -132,7 +135,7 @@ TEST(Mp4SampleTablePiecesTest, Stsc) {
<< error_message; << error_message;
EXPECT_EQ(1, pieces.stsc_entry_count()); EXPECT_EQ(1, pieces.stsc_entry_count());
const char kExpectedEntries[] = "00 00 00 0a 00 00 00 04 00 00 00 02"; const char kExpectedEntries[] = "00 00 00 0a 00 00 00 04 00 00 00 02";
EXPECT_EQ(kExpectedEntries, ToHex(pieces.stsc_entries())); EXPECT_EQ(kExpectedEntries, ToHex(pieces.stsc_entries(), true));
} }
TEST(Mp4SampleTablePiecesTest, Stsz) { TEST(Mp4SampleTablePiecesTest, Stsz) {
@ -150,7 +153,7 @@ TEST(Mp4SampleTablePiecesTest, Stsz) {
<< error_message; << error_message;
EXPECT_EQ(3, pieces.stsz_entry_count()); EXPECT_EQ(3, pieces.stsz_entry_count());
const char kExpectedEntries[] = "00 00 00 04 00 00 00 06 00 00 00 08"; const char kExpectedEntries[] = "00 00 00 04 00 00 00 06 00 00 00 08";
EXPECT_EQ(kExpectedEntries, ToHex(pieces.stsz_entries())); EXPECT_EQ(kExpectedEntries, ToHex(pieces.stsz_entries(), true));
} }
class IntegrationTest : public testing::Test { class IntegrationTest : public testing::Test {

View File

@ -60,7 +60,7 @@ TEST(SampleIndexTest, EncodeExample) {
encoder.AddSample(11, 15, false); encoder.AddSample(11, 15, false);
encoder.AddSample(10, 12, false); encoder.AddSample(10, 12, false);
encoder.AddSample(10, 1050, true); encoder.AddSample(10, 1050, true);
ASSERT_EQ("29 d0 0f 02 14 08 0a 02 05 01 64", ToHex(encoder.data())); ASSERT_EQ("29 d0 0f 02 14 08 0a 02 05 01 64", ToHex(encoder.data(), true));
} }
TEST(SampleIndexTest, RoundTrip) { TEST(SampleIndexTest, RoundTrip) {
@ -150,8 +150,7 @@ TEST(SampleFileWriterTest, Simple) {
EXPECT_TRUE(writer.Write(write_1, &error_message)) << error_message; EXPECT_TRUE(writer.Write(write_1, &error_message)) << error_message;
EXPECT_TRUE(writer.Write(write_2, &error_message)) << error_message; EXPECT_TRUE(writer.Write(write_2, &error_message)) << error_message;
EXPECT_TRUE(writer.Close(&sha1, &error_message)) << error_message; EXPECT_TRUE(writer.Close(&sha1, &error_message)) << error_message;
EXPECT_EQ("6b c3 73 25 b3 6f b5 fd 20 5e 57 28 44 29 e7 57 64 33 86 18", EXPECT_EQ("6bc37325b36fb5fd205e57284429e75764338618", ToHex(sha1));
ToHex(sha1));
} }
TEST(SampleFileWriterTest, PartialWriteIsRetried) { TEST(SampleFileWriterTest, PartialWriteIsRetried) {
@ -181,8 +180,7 @@ TEST(SampleFileWriterTest, PartialWriteIsRetried) {
EXPECT_TRUE(writer.Write(write_1, &error_message)) << error_message; EXPECT_TRUE(writer.Write(write_1, &error_message)) << error_message;
EXPECT_TRUE(writer.Write(write_2, &error_message)) << error_message; EXPECT_TRUE(writer.Write(write_2, &error_message)) << error_message;
EXPECT_TRUE(writer.Close(&sha1, &error_message)) << error_message; EXPECT_TRUE(writer.Close(&sha1, &error_message)) << error_message;
EXPECT_EQ("6b c3 73 25 b3 6f b5 fd 20 5e 57 28 44 29 e7 57 64 33 86 18", EXPECT_EQ("6bc37325b36fb5fd205e57284429e75764338618", ToHex(sha1));
ToHex(sha1));
} }
TEST(SampleFileWriterTest, PartialWriteIsTruncated) { TEST(SampleFileWriterTest, PartialWriteIsTruncated) {
@ -212,8 +210,7 @@ TEST(SampleFileWriterTest, PartialWriteIsTruncated) {
EXPECT_TRUE(writer.Write(write_1, &error_message)) << error_message; EXPECT_TRUE(writer.Write(write_1, &error_message)) << error_message;
EXPECT_FALSE(writer.Write(write_2, &error_message)) << error_message; EXPECT_FALSE(writer.Write(write_2, &error_message)) << error_message;
EXPECT_TRUE(writer.Close(&sha1, &error_message)) << error_message; EXPECT_TRUE(writer.Close(&sha1, &error_message)) << error_message;
EXPECT_EQ("b1 cc ee 33 9b 93 55 87 c0 99 97 a9 ec 8b b2 37 4e 02 b5 d0", EXPECT_EQ("b1ccee339b935587c09997a9ec8bb2374e02b5d0", ToHex(sha1));
ToHex(sha1));
} }
TEST(SampleFileWriterTest, PartialWriteTruncateFailureCausesCloseToFail) { TEST(SampleFileWriterTest, PartialWriteTruncateFailureCausesCloseToFail) {

View File

@ -87,7 +87,7 @@ TEST_F(SqliteTest, BindAndColumn) {
&error_message); &error_message);
ASSERT_TRUE(select_stmt != nullptr) << error_message; ASSERT_TRUE(select_stmt != nullptr) << error_message;
ASSERT_EQ(SQLITE_ROW, select_stmt->Step()); ASSERT_EQ(SQLITE_ROW, select_stmt->Step());
EXPECT_EQ(ToHex(blob_piece), ToHex(select_stmt->ColumnBlob(0))); EXPECT_EQ(ToHex(blob_piece, true), ToHex(select_stmt->ColumnBlob(0), true));
EXPECT_EQ(kText, select_stmt->ColumnText(1).as_string()); EXPECT_EQ(kText, select_stmt->ColumnText(1).as_string());
EXPECT_EQ(kInt64, select_stmt->ColumnInt64(2)); EXPECT_EQ(kInt64, select_stmt->ColumnInt64(2));
ASSERT_EQ(SQLITE_DONE, select_stmt->Step()); ASSERT_EQ(SQLITE_DONE, select_stmt->Step());

View File

@ -93,8 +93,10 @@ TEST(EscapeTest, Simple) {
} }
TEST(ToHexTest, Simple) { TEST(ToHexTest, Simple) {
EXPECT_EQ("", ToHex("")); EXPECT_EQ("", ToHex("", false));
EXPECT_EQ("12 34 de ad be ef", ToHex("\x12\x34\xde\xad\xbe\xef")); EXPECT_EQ("", ToHex("", true));
EXPECT_EQ("1234deadbeef", ToHex("\x12\x34\xde\xad\xbe\xef", false));
EXPECT_EQ("12 34 de ad be ef", ToHex("\x12\x34\xde\xad\xbe\xef", true));
} }
} // namespace } // namespace

View File

@ -112,11 +112,11 @@ std::string EscapeHtml(const std::string &input) {
return output; return output;
} }
std::string ToHex(re2::StringPiece in) { std::string ToHex(re2::StringPiece in, bool pad) {
std::string out; std::string out;
out.reserve(in.size() * 3 + 1); out.reserve(in.size() * (2 + pad) + pad);
for (int i = 0; i < in.size(); ++i) { for (int i = 0; i < in.size(); ++i) {
if (i > 0) out.push_back(' '); if (pad && i > 0) out.push_back(' ');
uint8_t byte = in[i]; uint8_t byte = in[i];
out.push_back(HexDigit(byte >> 4)); out.push_back(HexDigit(byte >> 4));
out.push_back(HexDigit(byte & 0x0F)); out.push_back(HexDigit(byte & 0x0F));

View File

@ -118,9 +118,9 @@ bool IsWord(const std::string &str);
// HTML-escape the given UTF-8-encoded string. // HTML-escape the given UTF-8-encoded string.
std::string EscapeHtml(const std::string &input); std::string EscapeHtml(const std::string &input);
// Return a hex string for debugging. // Return a hex-encoded version of |in|, optionally padding between bytes.
// For example, ToHex("\xde\xad\xbe\xef") returns "de ad be ef". // For example, ToHex("\xde\xad\xbe\xef", true) returns "de ad be ef".
std::string ToHex(re2::StringPiece in); std::string ToHex(re2::StringPiece in, bool pad = false);
// Wrapper around ::strtol that returns true iff valid and corrects // Wrapper around ::strtol that returns true iff valid and corrects
// constness. // constness.