1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/websockets/websocket_deflate_parameters.h"
6
7 #include <iterator>
8 #include <ostream>
9 #include <string>
10 #include <vector>
11
12 #include "net/websockets/websocket_extension_parser.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace net {
16
17 namespace {
18
CheckExtension(const WebSocketDeflateParameters & params,const std::string & name,const std::string & value)19 void CheckExtension(const WebSocketDeflateParameters& params,
20 const std::string& name,
21 const std::string& value) {
22 WebSocketExtension e = params.AsExtension();
23 EXPECT_EQ("permessage-deflate", e.name());
24 if (e.parameters().size() != 1)
25 FAIL() << "parameters must have one element.";
26 EXPECT_EQ(name, e.parameters()[0].name());
27 EXPECT_EQ(value, e.parameters()[0].value());
28 }
29
TEST(WebSocketDeflateParametersTest,Empty)30 TEST(WebSocketDeflateParametersTest, Empty) {
31 WebSocketDeflateParameters r;
32
33 EXPECT_EQ(WebSocketDeflater::TAKE_OVER_CONTEXT,
34 r.server_context_take_over_mode());
35 EXPECT_EQ(WebSocketDeflater::TAKE_OVER_CONTEXT,
36 r.client_context_take_over_mode());
37 EXPECT_FALSE(r.is_server_max_window_bits_specified());
38 EXPECT_FALSE(r.is_client_max_window_bits_specified());
39 EXPECT_TRUE(r.IsValidAsRequest());
40 EXPECT_TRUE(r.IsValidAsResponse());
41 WebSocketExtension e = r.AsExtension();
42 EXPECT_EQ("permessage-deflate", e.name());
43 EXPECT_TRUE(e.parameters().empty());
44 }
45
TEST(WebSocketDeflateParametersTest,ServerContextTakeover)46 TEST(WebSocketDeflateParametersTest, ServerContextTakeover) {
47 WebSocketDeflateParameters r;
48
49 r.SetServerNoContextTakeOver();
50 CheckExtension(r, "server_no_context_takeover", "");
51 EXPECT_TRUE(r.IsValidAsRequest());
52 EXPECT_TRUE(r.IsValidAsResponse());
53 }
54
TEST(WebSocketDeflateParametersTest,ClientContextTakeover)55 TEST(WebSocketDeflateParametersTest, ClientContextTakeover) {
56 WebSocketDeflateParameters r;
57
58 r.SetClientNoContextTakeOver();
59 CheckExtension(r, "client_no_context_takeover", "");
60 EXPECT_TRUE(r.IsValidAsRequest());
61 EXPECT_TRUE(r.IsValidAsResponse());
62 }
63
TEST(WebSocketDeflateParametersTest,ServerMaxWindowBits)64 TEST(WebSocketDeflateParametersTest, ServerMaxWindowBits) {
65 WebSocketDeflateParameters r;
66
67 r.SetServerMaxWindowBits(13);
68 CheckExtension(r, "server_max_window_bits", "13");
69 EXPECT_TRUE(r.IsValidAsRequest());
70 EXPECT_TRUE(r.IsValidAsResponse());
71 }
72
TEST(WebSocketDeflateParametersTest,ClientMaxWindowBitsWithoutValue)73 TEST(WebSocketDeflateParametersTest, ClientMaxWindowBitsWithoutValue) {
74 WebSocketDeflateParameters r;
75 std::string failure_message;
76
77 r.SetClientMaxWindowBits();
78 CheckExtension(r, "client_max_window_bits", "");
79 EXPECT_TRUE(r.IsValidAsRequest());
80 EXPECT_FALSE(r.IsValidAsResponse(&failure_message));
81 EXPECT_EQ("client_max_window_bits must have value", failure_message);
82 }
83
TEST(WebSocketDeflateParametersTest,ClientMaxWindowBitsWithValue)84 TEST(WebSocketDeflateParametersTest, ClientMaxWindowBitsWithValue) {
85 WebSocketDeflateParameters r;
86
87 r.SetClientMaxWindowBits(12);
88 CheckExtension(r, "client_max_window_bits", "12");
89 EXPECT_TRUE(r.IsValidAsRequest());
90 EXPECT_TRUE(r.IsValidAsResponse());
91 }
92
93 struct InitializeTestParameter {
94 const std::string query;
95 struct Expectation {
96 bool result;
97 std::string failure_message;
98 } const expected;
99 };
100
PrintTo(const InitializeTestParameter & p,std::ostream * o)101 void PrintTo(const InitializeTestParameter& p, std::ostream* o) {
102 *o << p.query;
103 }
104
105 class WebSocketDeflateParametersInitializeTest
106 : public ::testing::TestWithParam<InitializeTestParameter> {};
107
TEST_P(WebSocketDeflateParametersInitializeTest,Initialize)108 TEST_P(WebSocketDeflateParametersInitializeTest, Initialize) {
109 const std::string query = GetParam().query;
110 const bool expected = GetParam().expected.result;
111 const std::string expected_failure_message =
112 GetParam().expected.failure_message;
113
114 WebSocketExtensionParser parser;
115 ASSERT_TRUE(parser.Parse("permessage-deflate" + query));
116 ASSERT_EQ(1u, parser.extensions().size());
117 WebSocketExtension extension = parser.extensions()[0];
118
119 WebSocketDeflateParameters parameters;
120 std::string failure_message;
121 bool actual = parameters.Initialize(extension, &failure_message);
122
123 if (expected) {
124 EXPECT_TRUE(actual);
125 EXPECT_TRUE(extension.Equivalent(parameters.AsExtension()));
126 } else {
127 EXPECT_FALSE(actual);
128 }
129 EXPECT_EQ(expected_failure_message, failure_message);
130 }
131
132 struct CompatibilityTestParameter {
133 const char* request_query;
134 const char* response_query;
135 const bool expected;
136 };
137
PrintTo(const CompatibilityTestParameter & p,std::ostream * o)138 void PrintTo(const CompatibilityTestParameter& p, std::ostream* o) {
139 *o << "req = \"" << p.request_query << "\", res = \"" << p.response_query
140 << "\"";
141 }
142
143 class WebSocketDeflateParametersCompatibilityTest
144 : public ::testing::TestWithParam<CompatibilityTestParameter> {};
145
TEST_P(WebSocketDeflateParametersCompatibilityTest,CheckCompatiblity)146 TEST_P(WebSocketDeflateParametersCompatibilityTest, CheckCompatiblity) {
147 const std::string request_query = GetParam().request_query;
148 const std::string response_query = GetParam().response_query;
149 const bool expected = GetParam().expected;
150
151 std::string message;
152 WebSocketDeflateParameters request, response;
153
154 WebSocketExtensionParser request_parser;
155 ASSERT_TRUE(request_parser.Parse("permessage-deflate" + request_query));
156 ASSERT_EQ(1u, request_parser.extensions().size());
157 ASSERT_TRUE(request.Initialize(request_parser.extensions()[0], &message));
158 ASSERT_TRUE(request.IsValidAsRequest(&message));
159
160 WebSocketExtensionParser response_parser;
161 ASSERT_TRUE(response_parser.Parse("permessage-deflate" + response_query));
162 ASSERT_EQ(1u, response_parser.extensions().size());
163 ASSERT_TRUE(response.Initialize(response_parser.extensions()[0], &message));
164 ASSERT_TRUE(response.IsValidAsResponse(&message));
165
166 EXPECT_EQ(expected, request.IsCompatibleWith(response));
167 }
168
Duplicate(const std::string & name)169 InitializeTestParameter::Expectation Duplicate(const std::string& name) {
170 return {false,
171 "Received duplicate permessage-deflate extension parameter " + name};
172 }
173
Invalid(const std::string & name)174 InitializeTestParameter::Expectation Invalid(const std::string& name) {
175 return {false, "Received invalid " + name + " parameter"};
176 }
177
178 // We need this function in order to avoid global non-pod variables.
InitializeTestParameters()179 std::vector<InitializeTestParameter> InitializeTestParameters() {
180 const InitializeTestParameter::Expectation kInitialized = {true, ""};
181 const InitializeTestParameter::Expectation kUnknownParameter = {
182 false, "Received an unexpected permessage-deflate extension parameter"};
183
184 const InitializeTestParameter parameters[] = {
185 {"", kInitialized},
186 {"; server_no_context_takeover", kInitialized},
187 {"; server_no_context_takeover=0", Invalid("server_no_context_takeover")},
188 {"; server_no_context_takeover; server_no_context_takeover",
189 Duplicate("server_no_context_takeover")},
190 {"; client_no_context_takeover", kInitialized},
191 {"; client_no_context_takeover=0", Invalid("client_no_context_takeover")},
192 {"; client_no_context_takeover; client_no_context_takeover",
193 Duplicate("client_no_context_takeover")},
194 {"; server_max_window_bits=8", kInitialized},
195 {"; server_max_window_bits=15", kInitialized},
196 {"; server_max_window_bits=15; server_max_window_bits=15",
197 Duplicate("server_max_window_bits")},
198 {"; server_max_window_bits=a", Invalid("server_max_window_bits")},
199 {"; server_max_window_bits=09", Invalid("server_max_window_bits")},
200 {"; server_max_window_bits=+9", Invalid("server_max_window_bits")},
201 {"; server_max_window_bits=9a", Invalid("server_max_window_bits")},
202 {"; server_max_window_bits", Invalid("server_max_window_bits")},
203 {"; server_max_window_bits=7", Invalid("server_max_window_bits")},
204 {"; server_max_window_bits=16", Invalid("server_max_window_bits")},
205 {"; client_max_window_bits=8", kInitialized},
206 {"; client_max_window_bits=15", kInitialized},
207 {"; client_max_window_bits=15; client_max_window_bits=15",
208 Duplicate("client_max_window_bits")},
209 {"; client_max_window_bits=a", Invalid("client_max_window_bits")},
210 {"; client_max_window_bits=09", Invalid("client_max_window_bits")},
211 {"; client_max_window_bits=+9", Invalid("client_max_window_bits")},
212 {"; client_max_window_bits=9a", Invalid("client_max_window_bits")},
213 {"; client_max_window_bits", kInitialized},
214 {"; client_max_window_bits=7", Invalid("client_max_window_bits")},
215 {"; client_max_window_bits=16", Invalid("client_max_window_bits")},
216 {"; server_no_context_takeover; client_no_context_takeover"
217 "; server_max_window_bits=12; client_max_window_bits=13",
218 kInitialized},
219 {"; hogefuga", kUnknownParameter},
220 };
221 return std::vector<InitializeTestParameter>(
222 parameters, parameters + std::size(parameters));
223 }
224
225 constexpr CompatibilityTestParameter kCompatibilityTestParameters[] = {
226 {"", "", true},
227 // server_no_context_takeover
228 {"", "; server_no_context_takeover", true},
229 {"; server_no_context_takeover", "", false},
230 {"; server_no_context_takeover", "; server_no_context_takeover", true},
231 // client_no_context_takeover
232 {"", "; client_no_context_takeover", true},
233 {"; client_no_context_takeover", "", true},
234 {"; client_no_context_takeover", "; client_no_context_takeover", true},
235 // server_max_window_bits
236 {"", "; server_max_window_bits=14", true},
237 {"; server_max_window_bits=12", "", false},
238 {"; server_max_window_bits=12", "; server_max_window_bits=12", true},
239 {"; server_max_window_bits=12", "; server_max_window_bits=11", true},
240 {"; server_max_window_bits=12", "; server_max_window_bits=13", false},
241 // client_max_window_bits
242 {"", "; client_max_window_bits=14", false},
243 {"; client_max_window_bits", "", true},
244 {"; client_max_window_bits", "; client_max_window_bits=15", true},
245 {"; client_max_window_bits=12", "", true},
246 {"; client_max_window_bits=12", "; client_max_window_bits=12", true},
247 {"; client_max_window_bits=12", "; client_max_window_bits=11", true},
248 {"; client_max_window_bits=12", "; client_max_window_bits=13", true},
249 };
250
251 INSTANTIATE_TEST_SUITE_P(WebSocketDeflateParametersInitializeTest,
252 WebSocketDeflateParametersInitializeTest,
253 ::testing::ValuesIn(InitializeTestParameters()));
254
255 INSTANTIATE_TEST_SUITE_P(WebSocketDeflateParametersCompatibilityTest,
256 WebSocketDeflateParametersCompatibilityTest,
257 ::testing::ValuesIn(kCompatibilityTestParameters));
258
259 } // namespace
260
261 } // namespace net
262