|  | // Copyright 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/websockets/websocket_deflate_parameters.h" | 
|  |  | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/macros.h" | 
|  | #include "net/websockets/websocket_extension_parser.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace net { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | void CheckExtension(const WebSocketDeflateParameters& params, | 
|  | const std::string& name, | 
|  | const std::string& value) { | 
|  | WebSocketExtension e = params.AsExtension(); | 
|  | EXPECT_EQ("permessage-deflate", e.name()); | 
|  | if (e.parameters().size() != 1) | 
|  | FAIL() << "parameters must have one element."; | 
|  | EXPECT_EQ(name, e.parameters()[0].name()); | 
|  | EXPECT_EQ(value, e.parameters()[0].value()); | 
|  | } | 
|  |  | 
|  | TEST(WebSocketDeflateParametersTest, Empty) { | 
|  | WebSocketDeflateParameters r; | 
|  |  | 
|  | EXPECT_EQ(WebSocketDeflater::TAKE_OVER_CONTEXT, | 
|  | r.server_context_take_over_mode()); | 
|  | EXPECT_EQ(WebSocketDeflater::TAKE_OVER_CONTEXT, | 
|  | r.client_context_take_over_mode()); | 
|  | EXPECT_FALSE(r.is_server_max_window_bits_specified()); | 
|  | EXPECT_FALSE(r.is_client_max_window_bits_specified()); | 
|  | EXPECT_TRUE(r.IsValidAsRequest()); | 
|  | EXPECT_TRUE(r.IsValidAsResponse()); | 
|  | WebSocketExtension e = r.AsExtension(); | 
|  | EXPECT_EQ("permessage-deflate", e.name()); | 
|  | EXPECT_TRUE(e.parameters().empty()); | 
|  | } | 
|  |  | 
|  | TEST(WebSocketDeflateParametersTest, ServerContextTakeover) { | 
|  | WebSocketDeflateParameters r; | 
|  |  | 
|  | r.SetServerNoContextTakeOver(); | 
|  | CheckExtension(r, "server_no_context_takeover", ""); | 
|  | EXPECT_TRUE(r.IsValidAsRequest()); | 
|  | EXPECT_TRUE(r.IsValidAsResponse()); | 
|  | } | 
|  |  | 
|  | TEST(WebSocketDeflateParametersTest, ClientContextTakeover) { | 
|  | WebSocketDeflateParameters r; | 
|  |  | 
|  | r.SetClientNoContextTakeOver(); | 
|  | CheckExtension(r, "client_no_context_takeover", ""); | 
|  | EXPECT_TRUE(r.IsValidAsRequest()); | 
|  | EXPECT_TRUE(r.IsValidAsResponse()); | 
|  | } | 
|  |  | 
|  | TEST(WebSocketDeflateParametersTest, ServerMaxWindowBits) { | 
|  | WebSocketDeflateParameters r; | 
|  |  | 
|  | r.SetServerMaxWindowBits(13); | 
|  | CheckExtension(r, "server_max_window_bits", "13"); | 
|  | EXPECT_TRUE(r.IsValidAsRequest()); | 
|  | EXPECT_TRUE(r.IsValidAsResponse()); | 
|  | } | 
|  |  | 
|  | TEST(WebSocketDeflateParametersTest, ClientMaxWindowBitsWithoutValue) { | 
|  | WebSocketDeflateParameters r; | 
|  | std::string failure_message; | 
|  |  | 
|  | r.SetClientMaxWindowBits(); | 
|  | CheckExtension(r, "client_max_window_bits", ""); | 
|  | EXPECT_TRUE(r.IsValidAsRequest()); | 
|  | EXPECT_FALSE(r.IsValidAsResponse(&failure_message)); | 
|  | EXPECT_EQ("client_max_window_bits must have value", failure_message); | 
|  | } | 
|  |  | 
|  | TEST(WebSocketDeflateParametersTest, ClientMaxWindowBitsWithValue) { | 
|  | WebSocketDeflateParameters r; | 
|  |  | 
|  | r.SetClientMaxWindowBits(12); | 
|  | CheckExtension(r, "client_max_window_bits", "12"); | 
|  | EXPECT_TRUE(r.IsValidAsRequest()); | 
|  | EXPECT_TRUE(r.IsValidAsResponse()); | 
|  | } | 
|  |  | 
|  | struct InitializeTestParameter { | 
|  | const std::string query; | 
|  | struct Expectation { | 
|  | bool result; | 
|  | std::string failure_message; | 
|  | } const expected; | 
|  | }; | 
|  |  | 
|  | void PrintTo(const InitializeTestParameter& p, std::ostream* o) { | 
|  | *o << p.query; | 
|  | } | 
|  |  | 
|  | class WebSocketDeflateParametersInitializeTest | 
|  | : public ::testing::TestWithParam<InitializeTestParameter> {}; | 
|  |  | 
|  | TEST_P(WebSocketDeflateParametersInitializeTest, Initialize) { | 
|  | const std::string query = GetParam().query; | 
|  | const bool expected = GetParam().expected.result; | 
|  | const std::string expected_failure_message = | 
|  | GetParam().expected.failure_message; | 
|  |  | 
|  | WebSocketExtensionParser parser; | 
|  | ASSERT_TRUE(parser.Parse("permessage-deflate" + query)); | 
|  | ASSERT_EQ(1u, parser.extensions().size()); | 
|  | WebSocketExtension extension = parser.extensions()[0]; | 
|  |  | 
|  | WebSocketDeflateParameters parameters; | 
|  | std::string failure_message; | 
|  | bool actual = parameters.Initialize(extension, &failure_message); | 
|  |  | 
|  | if (expected) { | 
|  | EXPECT_TRUE(actual); | 
|  | EXPECT_TRUE(extension.Equals(parameters.AsExtension())); | 
|  | } else { | 
|  | EXPECT_FALSE(actual); | 
|  | } | 
|  | EXPECT_EQ(expected_failure_message, failure_message); | 
|  | } | 
|  |  | 
|  | struct CompatibilityTestParameter { | 
|  | const char* request_query; | 
|  | const char* response_query; | 
|  | const bool expected; | 
|  | }; | 
|  |  | 
|  | void PrintTo(const CompatibilityTestParameter& p, std::ostream* o) { | 
|  | *o << "req = \"" << p.request_query << "\", res = \"" << p.response_query | 
|  | << "\""; | 
|  | } | 
|  |  | 
|  | class WebSocketDeflateParametersCompatibilityTest | 
|  | : public ::testing::TestWithParam<CompatibilityTestParameter> {}; | 
|  |  | 
|  | TEST_P(WebSocketDeflateParametersCompatibilityTest, CheckCompatiblity) { | 
|  | const std::string request_query = GetParam().request_query; | 
|  | const std::string response_query = GetParam().response_query; | 
|  | const bool expected = GetParam().expected; | 
|  |  | 
|  | std::string message; | 
|  | WebSocketDeflateParameters request, response; | 
|  |  | 
|  | WebSocketExtensionParser request_parser; | 
|  | ASSERT_TRUE(request_parser.Parse("permessage-deflate" + request_query)); | 
|  | ASSERT_EQ(1u, request_parser.extensions().size()); | 
|  | ASSERT_TRUE(request.Initialize(request_parser.extensions()[0], &message)); | 
|  | ASSERT_TRUE(request.IsValidAsRequest(&message)); | 
|  |  | 
|  | WebSocketExtensionParser response_parser; | 
|  | ASSERT_TRUE(response_parser.Parse("permessage-deflate" + response_query)); | 
|  | ASSERT_EQ(1u, response_parser.extensions().size()); | 
|  | ASSERT_TRUE(response.Initialize(response_parser.extensions()[0], &message)); | 
|  | ASSERT_TRUE(response.IsValidAsResponse(&message)); | 
|  |  | 
|  | EXPECT_EQ(expected, request.IsCompatibleWith(response)); | 
|  | } | 
|  |  | 
|  | InitializeTestParameter::Expectation Duplicate(const std::string& name) { | 
|  | return {false, | 
|  | "Received duplicate permessage-deflate extension parameter " + name}; | 
|  | } | 
|  |  | 
|  | InitializeTestParameter::Expectation Invalid(const std::string& name) { | 
|  | return {false, "Received invalid " + name + " parameter"}; | 
|  | } | 
|  |  | 
|  | // We need this function in order to avoid global non-pod variables. | 
|  | std::vector<InitializeTestParameter> InitializeTestParameters() { | 
|  | const InitializeTestParameter::Expectation kInitialized = {true, ""}; | 
|  | const InitializeTestParameter::Expectation kUnknownParameter = { | 
|  | false, "Received an unexpected permessage-deflate extension parameter"}; | 
|  |  | 
|  | const InitializeTestParameter parameters[] = { | 
|  | {"", kInitialized}, | 
|  | {"; server_no_context_takeover", kInitialized}, | 
|  | {"; server_no_context_takeover=0", Invalid("server_no_context_takeover")}, | 
|  | {"; server_no_context_takeover; server_no_context_takeover", | 
|  | Duplicate("server_no_context_takeover")}, | 
|  | {"; client_no_context_takeover", kInitialized}, | 
|  | {"; client_no_context_takeover=0", Invalid("client_no_context_takeover")}, | 
|  | {"; client_no_context_takeover; client_no_context_takeover", | 
|  | Duplicate("client_no_context_takeover")}, | 
|  | {"; server_max_window_bits=8", kInitialized}, | 
|  | {"; server_max_window_bits=15", kInitialized}, | 
|  | {"; server_max_window_bits=15; server_max_window_bits=15", | 
|  | Duplicate("server_max_window_bits")}, | 
|  | {"; server_max_window_bits=a", Invalid("server_max_window_bits")}, | 
|  | {"; server_max_window_bits=09", Invalid("server_max_window_bits")}, | 
|  | {"; server_max_window_bits=+9", Invalid("server_max_window_bits")}, | 
|  | {"; server_max_window_bits=9a", Invalid("server_max_window_bits")}, | 
|  | {"; server_max_window_bits", Invalid("server_max_window_bits")}, | 
|  | {"; server_max_window_bits=7", Invalid("server_max_window_bits")}, | 
|  | {"; server_max_window_bits=16", Invalid("server_max_window_bits")}, | 
|  | {"; client_max_window_bits=8", kInitialized}, | 
|  | {"; client_max_window_bits=15", kInitialized}, | 
|  | {"; client_max_window_bits=15; client_max_window_bits=15", | 
|  | Duplicate("client_max_window_bits")}, | 
|  | {"; client_max_window_bits=a", Invalid("client_max_window_bits")}, | 
|  | {"; client_max_window_bits=09", Invalid("client_max_window_bits")}, | 
|  | {"; client_max_window_bits=+9", Invalid("client_max_window_bits")}, | 
|  | {"; client_max_window_bits=9a", Invalid("client_max_window_bits")}, | 
|  | {"; client_max_window_bits", kInitialized}, | 
|  | {"; client_max_window_bits=7", Invalid("client_max_window_bits")}, | 
|  | {"; client_max_window_bits=16", Invalid("client_max_window_bits")}, | 
|  | {"; server_no_context_takeover; client_no_context_takeover" | 
|  | "; server_max_window_bits=12; client_max_window_bits=13", | 
|  | kInitialized}, | 
|  | {"; hogefuga", kUnknownParameter}, | 
|  | }; | 
|  | return std::vector<InitializeTestParameter>( | 
|  | parameters, parameters + arraysize(parameters)); | 
|  | } | 
|  |  | 
|  | const CompatibilityTestParameter kCompatibilityTestParameters[] = { | 
|  | {"", "", true}, | 
|  | // server_no_context_takeover | 
|  | {"", "; server_no_context_takeover", true}, | 
|  | {"; server_no_context_takeover", "", false}, | 
|  | {"; server_no_context_takeover", "; server_no_context_takeover", true}, | 
|  | // client_no_context_takeover | 
|  | {"", "; client_no_context_takeover", true}, | 
|  | {"; client_no_context_takeover", "", true}, | 
|  | {"; client_no_context_takeover", "; client_no_context_takeover", true}, | 
|  | // server_max_window_bits | 
|  | {"", "; server_max_window_bits=14", true}, | 
|  | {"; server_max_window_bits=12", "", false}, | 
|  | {"; server_max_window_bits=12", "; server_max_window_bits=12", true}, | 
|  | {"; server_max_window_bits=12", "; server_max_window_bits=11", true}, | 
|  | {"; server_max_window_bits=12", "; server_max_window_bits=13", false}, | 
|  | // client_max_window_bits | 
|  | {"", "; client_max_window_bits=14", false}, | 
|  | {"; client_max_window_bits", "", true}, | 
|  | {"; client_max_window_bits", "; client_max_window_bits=15", true}, | 
|  | {"; client_max_window_bits=12", "", true}, | 
|  | {"; client_max_window_bits=12", "; client_max_window_bits=12", true}, | 
|  | {"; client_max_window_bits=12", "; client_max_window_bits=11", true}, | 
|  | {"; client_max_window_bits=12", "; client_max_window_bits=13", true}, | 
|  | }; | 
|  |  | 
|  | INSTANTIATE_TEST_CASE_P(WebSocketDeflateParametersInitializeTest, | 
|  | WebSocketDeflateParametersInitializeTest, | 
|  | ::testing::ValuesIn(InitializeTestParameters())); | 
|  |  | 
|  | INSTANTIATE_TEST_CASE_P(WebSocketDeflateParametersCompatibilityTest, | 
|  | WebSocketDeflateParametersCompatibilityTest, | 
|  | ::testing::ValuesIn(kCompatibilityTestParameters)); | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | }  // namespace net |