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