Index: net/spdy/spdy_alt_svc_wire_format_test.cc |
diff --git a/net/spdy/spdy_alt_svc_wire_format_test.cc b/net/spdy/spdy_alt_svc_wire_format_test.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1ecd53b6065ba31025ababe9da6f0a7fa817ac16 |
--- /dev/null |
+++ b/net/spdy/spdy_alt_svc_wire_format_test.cc |
@@ -0,0 +1,420 @@ |
+// Copyright (c) 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "net/spdy/spdy_alt_svc_wire_format.h" |
+ |
+#include "base/logging.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "testing/platform_test.h" |
+ |
+using ::testing::_; |
+ |
+namespace net { |
+ |
+namespace test { |
+ |
+// Expose all private methods of class SpdyAltSvcWireFormat. |
+class SpdyAltSvcWireFormatPeer { |
+ public: |
+ static void SkipWhiteSpace(StringPiece::const_iterator* c, |
+ StringPiece::const_iterator end) { |
+ SpdyAltSvcWireFormat::SkipWhiteSpace(c, end); |
+ } |
+ static bool PercentDecode(StringPiece::const_iterator c, |
+ StringPiece::const_iterator end, |
+ std::string* output) { |
+ return SpdyAltSvcWireFormat::PercentDecode(c, end, output); |
+ } |
+ static bool ParseAltAuthority(StringPiece::const_iterator c, |
+ StringPiece::const_iterator end, |
+ std::string* host, |
+ uint16* port) { |
+ return SpdyAltSvcWireFormat::ParseAltAuthority(c, end, host, port); |
+ } |
+ static bool ParsePositiveInteger16(StringPiece::const_iterator c, |
+ StringPiece::const_iterator end, |
+ uint16* max_age) { |
+ return SpdyAltSvcWireFormat::ParsePositiveInteger16(c, end, max_age); |
+ } |
+ static bool ParsePositiveInteger32(StringPiece::const_iterator c, |
+ StringPiece::const_iterator end, |
+ uint32* max_age) { |
+ return SpdyAltSvcWireFormat::ParsePositiveInteger32(c, end, max_age); |
+ } |
+ static bool ParseProbability(StringPiece::const_iterator c, |
+ StringPiece::const_iterator end, |
+ double* p) { |
+ return SpdyAltSvcWireFormat::ParseProbability(c, end, p); |
+ } |
+}; |
+ |
+} // namespace test |
+ |
+namespace { |
+ |
+class SpdyAltSvcWireFormatTest : public ::testing::Test {}; |
+ |
+// Tests of public API. |
+ |
+// Fuzz test of ParseHeaderFieldValue() with optional whitespaces, ignored |
+// parameters, duplicate parameters, trailing space, trailing alternate service |
+// separator, etc. |
+TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValue) { |
+ for (int i = 0; i < 1 << 13; ++i) { |
+ std::string header_field_value = "a%3Db%25c=\""; |
+ std::string expected_host; |
+ if (i & 1 << 0) { |
+ expected_host = "foo\"bar\\baz"; |
+ header_field_value.append("foo\\\"bar\\\\baz"); |
+ } |
+ header_field_value.append(":42\""); |
+ if (i & 1 << 1) { |
+ header_field_value.append(" "); |
+ } |
+ uint32 expected_max_age = 86400; |
+ if (i & 3 << 2) { |
+ expected_max_age = 1111; |
+ header_field_value.append(";"); |
+ if (i & 1 << 2) { |
+ header_field_value.append(" "); |
+ } |
+ header_field_value.append("mA=1111"); |
+ if (i & 2 << 2) { |
+ header_field_value.append(" "); |
+ } |
+ } |
+ if (i & 1 << 4) { |
+ header_field_value.append("; J=s"); |
+ } |
+ double expected_p = 1.0; |
+ if (i & 1 << 5) { |
+ expected_p = 0.33; |
+ header_field_value.append("; P=.33"); |
+ } |
+ if (i & 1 << 6) { |
+ expected_p = 0.0; |
+ header_field_value.append("; p=0"); |
+ } |
+ if (i & 1 << 7) { |
+ expected_max_age = 999999999; |
+ header_field_value.append("; Ma=999999999"); |
+ } |
+ if (i & 1 << 8) { |
+ expected_p = 0.0; |
+ header_field_value.append("; P=0."); |
+ } |
+ if (i & 1 << 9) { |
+ header_field_value.append(";"); |
+ } |
+ if (i & 1 << 10) { |
+ header_field_value.append(" "); |
+ } |
+ if (i & 1 << 11) { |
+ header_field_value.append(","); |
+ } |
+ if (i & 1 << 12) { |
+ header_field_value.append(" "); |
+ } |
+ |
+ std::string protocol_id; |
+ std::string host; |
+ uint16 port = 0; |
+ uint32 max_age = 0; |
+ double p = 0.0; |
+ |
+ ASSERT_TRUE(SpdyAltSvcWireFormat::ParseHeaderFieldValue( |
+ header_field_value, &protocol_id, &host, &port, &max_age, &p)); |
+ EXPECT_EQ("a=b%c", protocol_id); |
+ EXPECT_EQ(expected_host, host); |
+ EXPECT_EQ(42, port); |
+ EXPECT_EQ(expected_max_age, max_age); |
+ EXPECT_DOUBLE_EQ(expected_p, p); |
+ } |
+} |
+ |
+// Test SerializeHeaderFieldValue() with and without hostname and each |
+// parameter. |
+TEST(SpdyAltSvcWireFormatTest, SerializeHeaderFieldValue) { |
+ for (int i = 0; i < 1 << 3; ++i) { |
+ std::string expected_header_field_value = "a%3Db%25c=\""; |
+ std::string host; |
+ if (i & 1 << 0) { |
+ host = "foo\"bar\\baz"; |
+ expected_header_field_value.append("foo\\\"bar\\\\baz"); |
+ } |
+ expected_header_field_value.append(":42\""); |
+ int max_age = 86400; |
+ if (i & 1 << 1) { |
+ max_age = 1111; |
+ expected_header_field_value.append("; ma=1111"); |
+ } |
+ double p = 1.0; |
+ if (i & 1 << 2) { |
+ p = 0.33; |
+ expected_header_field_value.append("; p=0.33"); |
+ } |
+ EXPECT_EQ(expected_header_field_value, |
+ SpdyAltSvcWireFormat::SerializeHeaderFieldValue("a=b%c", host, 42, |
+ max_age, p)); |
+ } |
+} |
+ |
+// ParseHeaderFieldValue() should return false on malformed field values: |
+// invalid percent encoding, unmatched quotation mark, empty port, non-numeric |
+// characters in numeric fields, negative or larger than 1.0 probability. |
+TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValueInvalid) { |
+ std::string protocol_id; |
+ std::string host; |
+ uint16 port; |
+ uint32 max_age; |
+ double p; |
+ const char* invalid_field_value_array[] = {"", "a%", "a%x", "a%b", "a%9z", |
+ "a=", "a=\"", "a=\"b\"", "a=\":\"", "a=\"c:\"", "a=\"c:foo\"", |
+ "a=\"c:42foo\"", "a=\"b:42\"bar", "a=\"b:42\" ; m", |
+ "a=\"b:42\" ; min-age", "a=\"b:42\" ; ma", "a=\"b:42\" ; ma=", |
+ "a=\"b:42\" ; ma=ma", "a=\"b:42\" ; ma=123bar", "a=\"b:42\" ; p=-2", |
+ "a=\"b:42\" ; p=..", "a=\"b:42\" ; p=1.05"}; |
+ for (const char* invalid_field_value : invalid_field_value_array) { |
+ EXPECT_FALSE(SpdyAltSvcWireFormat::ParseHeaderFieldValue( |
+ invalid_field_value, &protocol_id, &host, &port, &max_age, &p)) |
+ << invalid_field_value; |
+ } |
+} |
+ |
+// ParseHeaderFieldValue() should return false on a field values truncated |
+// before closing quotation mark, without trying to access memory beyond the end |
+// of the input. |
+TEST(SpdyAltSvcWireFormatTest, ParseTruncatedHeaderFieldValue) { |
+ std::string protocol_id; |
+ std::string host; |
+ uint16 port; |
+ uint32 max_age; |
+ double p; |
+ const char* field_value_array[] = { |
+ "p=\":137\"", "p=\"foo:137\"", "p%25=\"foo\\\"bar\\\\baz:137\""}; |
+ for (std::string field_value : field_value_array) { |
+ for (size_t len = 1; len < field_value.size(); ++len) { |
+ EXPECT_FALSE(SpdyAltSvcWireFormat::ParseHeaderFieldValue( |
+ field_value.substr(0, len), &protocol_id, &host, &port, &max_age, &p)) |
+ << len; |
+ } |
+ } |
+} |
+ |
+// Tests of private methods. |
+ |
+// Test SkipWhiteSpace(). |
+TEST(SpdyAltSvcWireFormatTest, SkipWhiteSpace) { |
+ StringPiece input("a \tb "); |
+ StringPiece::const_iterator c = input.begin(); |
+ test::SpdyAltSvcWireFormatPeer::SkipWhiteSpace(&c, input.end()); |
+ ASSERT_EQ(input.begin(), c); |
+ ++c; |
+ test::SpdyAltSvcWireFormatPeer::SkipWhiteSpace(&c, input.end()); |
+ ASSERT_EQ(input.begin() + 3, c); |
+ ++c; |
+ test::SpdyAltSvcWireFormatPeer::SkipWhiteSpace(&c, input.end()); |
+ ASSERT_EQ(input.end(), c); |
+} |
+ |
+// Test PercentDecode() on valid input. |
+TEST(SpdyAltSvcWireFormatTest, PercentDecodeValid) { |
+ StringPiece input(""); |
+ std::string output; |
+ ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::PercentDecode( |
+ input.begin(), input.end(), &output)); |
+ EXPECT_EQ("", output); |
+ |
+ input = StringPiece("foo"); |
+ output.clear(); |
+ ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::PercentDecode( |
+ input.begin(), input.end(), &output)); |
+ EXPECT_EQ("foo", output); |
+ |
+ input = StringPiece("%2ca%5Cb"); |
+ output.clear(); |
+ ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::PercentDecode( |
+ input.begin(), input.end(), &output)); |
+ EXPECT_EQ(",a\\b", output); |
+} |
+ |
+// Test PercentDecode() on invalid input. |
+TEST(SpdyAltSvcWireFormatTest, PercentDecodeInvalid) { |
+ const char* invalid_input_array[] = {"a%", "a%x", "a%b", "%J22", "%9z"}; |
+ for (const char* invalid_input : invalid_input_array) { |
+ StringPiece input(invalid_input); |
+ std::string output; |
+ EXPECT_FALSE(test::SpdyAltSvcWireFormatPeer::PercentDecode( |
+ input.begin(), input.end(), &output)) |
+ << input; |
+ } |
+} |
+ |
+// Test ParseAltAuthority() on valid input. |
+TEST(SpdyAltSvcWireFormatTest, ParseAltAuthorityValid) { |
+ StringPiece input(":42"); |
+ std::string host; |
+ uint16 port; |
+ ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseAltAuthority( |
+ input.begin(), input.end(), &host, &port)); |
+ EXPECT_TRUE(host.empty()); |
+ EXPECT_EQ(42, port); |
+ |
+ input = StringPiece("foo:137"); |
+ ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseAltAuthority( |
+ input.begin(), input.end(), &host, &port)); |
+ EXPECT_EQ("foo", host); |
+ EXPECT_EQ(137, port); |
+} |
+ |
+// Test ParseAltAuthority() on invalid input: empty string, no port, zero port, |
+// non-digit characters following port. |
+TEST(SpdyAltSvcWireFormatTest, ParseAltAuthorityInvalid) { |
+ const char* invalid_input_array[] = {"", ":", "foo:", ":bar", ":0", "foo:0", |
+ ":12bar", "foo:23bar", " ", ":12 ", "foo:12 "}; |
+ for (const char* invalid_input : invalid_input_array) { |
+ StringPiece input(invalid_input); |
+ std::string host; |
+ uint16 port; |
+ EXPECT_FALSE(test::SpdyAltSvcWireFormatPeer::ParseAltAuthority( |
+ input.begin(), input.end(), &host, &port)) |
+ << input; |
+ } |
+} |
+ |
+// Test ParseInteger() on valid input. |
+TEST(SpdyAltSvcWireFormatTest, ParseIntegerValid) { |
+ StringPiece input("3"); |
+ uint16 value; |
+ ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( |
+ input.begin(), input.end(), &value)); |
+ EXPECT_EQ(3, value); |
+ |
+ input = StringPiece("1337"); |
+ ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( |
+ input.begin(), input.end(), &value)); |
+ EXPECT_EQ(1337, value); |
+} |
+ |
+// Test ParseIntegerValid() on invalid input: empty, zero, non-numeric, trailing |
+// non-numeric characters. |
+TEST(SpdyAltSvcWireFormatTest, ParseIntegerInvalid) { |
+ const char* invalid_input_array[] = {"", " ", "a", "0", "00", "1 ", "12b"}; |
+ for (const char* invalid_input : invalid_input_array) { |
+ StringPiece input(invalid_input); |
+ uint16 value; |
+ EXPECT_FALSE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( |
+ input.begin(), input.end(), &value)) |
+ << input; |
+ } |
+} |
+ |
+// Test ParseIntegerValid() around overflow limit. |
+TEST(SpdyAltSvcWireFormatTest, ParseIntegerOverflow) { |
+ // Largest possible uint16 value. |
+ StringPiece input("65535"); |
+ uint16 value16; |
+ ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( |
+ input.begin(), input.end(), &value16)); |
+ EXPECT_EQ(65535, value16); |
+ |
+ // Overflow uint16, ParsePositiveInteger16() should return false. |
+ input = StringPiece("65536"); |
+ ASSERT_FALSE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( |
+ input.begin(), input.end(), &value16)); |
+ |
+ // However, even if overflow is not checked for, 65536 overflows to 0, which |
+ // returns false anyway. Check for a larger number which overflows to 1. |
+ input = StringPiece("65537"); |
+ ASSERT_FALSE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( |
+ input.begin(), input.end(), &value16)); |
+ |
+ // Largest possible uint32 value. |
+ input = StringPiece("4294967295"); |
+ uint32 value32; |
+ ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger32( |
+ input.begin(), input.end(), &value32)); |
+ EXPECT_EQ(4294967295, value32); |
+ |
+ // Overflow uint32, ParsePositiveInteger32() should return false. |
+ input = StringPiece("4294967296"); |
+ ASSERT_FALSE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger32( |
+ input.begin(), input.end(), &value32)); |
+ |
+ // However, even if overflow is not checked for, 4294967296 overflows to 0, |
+ // which returns false anyway. Check for a larger number which overflows to |
+ // 1. |
+ input = StringPiece("4294967297"); |
+ ASSERT_FALSE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger32( |
+ input.begin(), input.end(), &value32)); |
+} |
+ |
+// Test ParseProbability() on valid input. |
+TEST(SpdyAltSvcWireFormatTest, ParseProbabilityValid) { |
+ StringPiece input("0"); |
+ double probability = -2.0; |
+ ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseProbability( |
+ input.begin(), input.end(), &probability)); |
+ EXPECT_DOUBLE_EQ(0.0, probability); |
+ |
+ input = StringPiece("0."); |
+ probability = -2.0; |
+ ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseProbability( |
+ input.begin(), input.end(), &probability)); |
+ EXPECT_DOUBLE_EQ(0.0, probability); |
+ |
+ input = StringPiece("0.0"); |
+ probability = -2.0; |
+ ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseProbability( |
+ input.begin(), input.end(), &probability)); |
+ EXPECT_DOUBLE_EQ(0.0, probability); |
+ |
+ input = StringPiece("1"); |
+ probability = -2.0; |
+ ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseProbability( |
+ input.begin(), input.end(), &probability)); |
+ EXPECT_DOUBLE_EQ(1.0, probability); |
+ |
+ input = StringPiece("1."); |
+ probability = -2.0; |
+ ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseProbability( |
+ input.begin(), input.end(), &probability)); |
+ EXPECT_DOUBLE_EQ(1.0, probability); |
+ |
+ input = StringPiece("1.0"); |
+ probability = -2.0; |
+ ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseProbability( |
+ input.begin(), input.end(), &probability)); |
+ EXPECT_DOUBLE_EQ(1.0, probability); |
+ |
+ input = StringPiece("0.37"); |
+ probability = -2.0; |
+ ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseProbability( |
+ input.begin(), input.end(), &probability)); |
+ EXPECT_DOUBLE_EQ(0.37, probability); |
+ |
+ input = StringPiece("0.72"); |
+ probability = -2.0; |
+ ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseProbability( |
+ input.begin(), input.end(), &probability)); |
+ EXPECT_DOUBLE_EQ(0.72, probability); |
+} |
+ |
+// Test ParseProbability() on invalid input: empty string, non-digit characters, |
+// negative input, larger than 1.0. |
+TEST(SpdyAltSvcWireFormatTest, ParseProbabilityInvalid) { |
+ const char* invalid_input_array[] = {"", " ", ".", "a", "-2", "-0", "0a", |
+ "1b ", "0.9z2", "0.33 ", "0.98x", "2.0", "1.0001", "1.00001", |
+ "1.000001"}; |
+ for (const char* invalid_input : invalid_input_array) { |
+ StringPiece input(invalid_input); |
+ double probability; |
+ EXPECT_FALSE(test::SpdyAltSvcWireFormatPeer::ParseProbability( |
+ input.begin(), input.end(), &probability)); |
+ } |
+} |
+ |
+} // namespace |
+ |
+} // namespace net |