1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32 #include "modules/websockets/WebSocketPerMessageDeflate.h"
33
34 #include "wtf/Vector.h"
35 #include "wtf/text/StringHash.h"
36
37 #include <algorithm>
38 #include <gtest/gtest.h>
39 #include <iterator>
40
41 using namespace WebCore;
42
43 namespace {
44
TEST(WebSocketPerMessageDeflateTest,TestDeflateHelloTakeOver)45 TEST(WebSocketPerMessageDeflateTest, TestDeflateHelloTakeOver)
46 {
47 WebSocketPerMessageDeflate c;
48 c.enable(8, WebSocketDeflater::TakeOverContext);
49 WebSocketFrame::OpCode opcode = WebSocketFrame::OpCodeText;
50 WebSocketFrame f1(opcode, "Hello", 5, WebSocketFrame::Final);
51 WebSocketFrame f2(opcode, "Hello", 5, WebSocketFrame::Final);
52
53 ASSERT_TRUE(c.deflate(f1));
54 EXPECT_EQ(7u, f1.payloadLength);
55 EXPECT_EQ(0, memcmp("\xf2\x48\xcd\xc9\xc9\x07\x00", f1.payload, f1.payloadLength));
56 EXPECT_TRUE(f1.compress);
57 EXPECT_TRUE(f1.final);
58
59 c.resetDeflateBuffer();
60 ASSERT_TRUE(c.deflate(f2));
61 EXPECT_EQ(5u, f2.payloadLength);
62 EXPECT_EQ(0, memcmp("\xf2\x00\x11\x00\x00", f2.payload, f2.payloadLength));
63 EXPECT_TRUE(f2.compress);
64 EXPECT_TRUE(f2.final);
65 }
66
TEST(WebSocketPerMessageTest,TestDeflateHelloNoTakeOver)67 TEST(WebSocketPerMessageTest, TestDeflateHelloNoTakeOver)
68 {
69 WebSocketPerMessageDeflate c;
70 c.enable(8, WebSocketDeflater::DoNotTakeOverContext);
71 WebSocketFrame::OpCode opcode = WebSocketFrame::OpCodeText;
72 WebSocketFrame f1(opcode, "Hello", 5, WebSocketFrame::Final);
73 WebSocketFrame f2(opcode, "Hello", 5, WebSocketFrame::Final);
74
75 ASSERT_TRUE(c.deflate(f1));
76 EXPECT_EQ(7u, f1.payloadLength);
77 EXPECT_EQ(0, memcmp("\xf2\x48\xcd\xc9\xc9\x07\x00", f1.payload, f1.payloadLength));
78 EXPECT_TRUE(f1.compress);
79 EXPECT_TRUE(f1.final);
80
81 c.resetDeflateBuffer();
82 ASSERT_TRUE(c.deflate(f2));
83 EXPECT_EQ(7u, f2.payloadLength);
84 EXPECT_EQ(0, memcmp("\xf2\x48\xcd\xc9\xc9\x07\x00", f2.payload, f2.payloadLength));
85 EXPECT_TRUE(f2.compress);
86 EXPECT_TRUE(f2.final);
87 }
88
TEST(WebSocketPerMessageDeflateTest,TestDeflateInflateMultipleFrame)89 TEST(WebSocketPerMessageDeflateTest, TestDeflateInflateMultipleFrame)
90 {
91 WebSocketPerMessageDeflate c;
92 WebSocketFrame::OpCode text = WebSocketFrame::OpCodeText;
93 c.enable(8, WebSocketDeflater::DoNotTakeOverContext);
94 size_t length = 64 * 1024;
95 std::string payload;
96 std::string expected;
97 std::string actual;
98 std::string inflated;
99 // Generate string by a linear congruential generator.
100 uint64_t r = 0;
101 for (size_t i = 0; i < length; ++i) {
102 payload += 'a' + (r % 25);
103 r = (r * 12345 + 1103515245) % (static_cast<uint64_t>(1) << 31);
104 }
105
106 WebSocketFrame frame(text, &payload[0], payload.size(), WebSocketFrame::Final);
107 ASSERT_TRUE(c.deflate(frame));
108 ASSERT_TRUE(frame.final);
109 ASSERT_TRUE(frame.compress);
110 expected = std::string(frame.payload, frame.payloadLength);
111 for (size_t i = 0; i < length; ++i) {
112 WebSocketFrame::OpCode opcode = !i ? text : WebSocketFrame::OpCodeContinuation;
113 c.resetDeflateBuffer();
114 WebSocketFrame frame(opcode, &payload[i], 1);
115 frame.final = (i == length - 1);
116
117 ASSERT_TRUE(c.deflate(frame));
118 ASSERT_EQ(i == length - 1, frame.final);
119 ASSERT_EQ(!i, frame.compress);
120 actual += std::string(frame.payload, frame.payloadLength);
121 }
122 EXPECT_EQ(expected, actual);
123
124 for (size_t i = 0; i < actual.size(); ++i) {
125 WebSocketFrame::OpCode opcode = !i ? text : WebSocketFrame::OpCodeContinuation;
126 c.resetInflateBuffer();
127 WebSocketFrame frame(opcode, &actual[i], 1);
128 frame.final = (i == actual.size() - 1);
129 frame.compress = !i;
130
131 ASSERT_TRUE(c.inflate(frame));
132 ASSERT_EQ(i == actual.size() - 1, frame.final);
133 ASSERT_FALSE(frame.compress);
134 inflated += std::string(frame.payload, frame.payloadLength);
135 }
136 EXPECT_EQ(payload, inflated);
137 }
138
TEST(WebSocketPerMessageDeflateTest,TestDeflateBinary)139 TEST(WebSocketPerMessageDeflateTest, TestDeflateBinary)
140 {
141 WebSocketPerMessageDeflate c;
142 c.enable(8, WebSocketDeflater::TakeOverContext);
143 WebSocketFrame::OpCode opcode = WebSocketFrame::OpCodeBinary;
144 WebSocketFrame f1(opcode, "Hello", 5, WebSocketFrame::Final);
145
146 ASSERT_TRUE(c.deflate(f1));
147 EXPECT_EQ(7u, f1.payloadLength);
148 EXPECT_EQ(0, memcmp("\xf2\x48\xcd\xc9\xc9\x07\x00", f1.payload, f1.payloadLength));
149 EXPECT_EQ(opcode, f1.opCode);
150 EXPECT_TRUE(f1.compress);
151 EXPECT_TRUE(f1.final);
152 }
153
TEST(WebSocketPerMessageDeflateTest,TestDeflateEmptyFrame)154 TEST(WebSocketPerMessageDeflateTest, TestDeflateEmptyFrame)
155 {
156 WebSocketPerMessageDeflate c;
157 c.enable(8, WebSocketDeflater::TakeOverContext);
158 WebSocketFrame f1(WebSocketFrame::OpCodeText, "Hello", 5);
159 WebSocketFrame f2(WebSocketFrame::OpCodeContinuation, "", 0, WebSocketFrame::Final);
160
161 ASSERT_TRUE(c.deflate(f1));
162 EXPECT_EQ(0u, f1.payloadLength);
163 EXPECT_FALSE(f1.final);
164 EXPECT_TRUE(f1.compress);
165
166 c.resetDeflateBuffer();
167 ASSERT_TRUE(c.deflate(f2));
168 EXPECT_EQ(7u, f2.payloadLength);
169 EXPECT_EQ(0, memcmp("\xf2\x48\xcd\xc9\xc9\x07\x00", f2.payload, f2.payloadLength));
170 EXPECT_TRUE(f2.final);
171 EXPECT_FALSE(f2.compress);
172 }
173
TEST(WebSocketPerMessageDeflateTest,TestDeflateEmptyMessages)174 TEST(WebSocketPerMessageDeflateTest, TestDeflateEmptyMessages)
175 {
176 WebSocketPerMessageDeflate c;
177 c.enable(8, WebSocketDeflater::TakeOverContext);
178 WebSocketFrame f1(WebSocketFrame::OpCodeText, "", 0);
179 WebSocketFrame f2(WebSocketFrame::OpCodeContinuation, "", 0, WebSocketFrame::Final);
180 WebSocketFrame f3(WebSocketFrame::OpCodeText, "", 0, WebSocketFrame::Final);
181 WebSocketFrame f4(WebSocketFrame::OpCodeText, "", 0, WebSocketFrame::Final);
182 WebSocketFrame f5(WebSocketFrame::OpCodeText, "Hello", 5, WebSocketFrame::Final);
183
184 ASSERT_TRUE(c.deflate(f1));
185 EXPECT_EQ(0u, f1.payloadLength);
186 EXPECT_FALSE(f1.final);
187 EXPECT_TRUE(f1.compress);
188
189 c.resetDeflateBuffer();
190 ASSERT_TRUE(c.deflate(f2));
191 EXPECT_EQ(2u, f2.payloadLength);
192 EXPECT_EQ(0, memcmp("\x02\x00", f2.payload, f2.payloadLength));
193 EXPECT_TRUE(f2.final);
194 EXPECT_FALSE(f2.compress);
195
196 c.resetDeflateBuffer();
197 ASSERT_TRUE(c.deflate(f3));
198 EXPECT_EQ(0u, f3.payloadLength);
199 EXPECT_TRUE(f3.final);
200 EXPECT_FALSE(f3.compress);
201
202 c.resetDeflateBuffer();
203 ASSERT_TRUE(c.deflate(f4));
204 EXPECT_EQ(0u, f4.payloadLength);
205 EXPECT_TRUE(f4.final);
206 EXPECT_FALSE(f4.compress);
207
208 c.resetDeflateBuffer();
209 ASSERT_TRUE(c.deflate(f5));
210 EXPECT_EQ(7u, f5.payloadLength);
211 EXPECT_EQ(0, memcmp("\xf2\x48\xcd\xc9\xc9\x07\x00", f5.payload, f5.payloadLength));
212 EXPECT_TRUE(f5.final);
213 EXPECT_TRUE(f5.compress);
214 }
215
TEST(WebSocketPerMessageDeflateTest,TestControlMessage)216 TEST(WebSocketPerMessageDeflateTest, TestControlMessage)
217 {
218 WebSocketPerMessageDeflate c;
219 c.enable(8, WebSocketDeflater::TakeOverContext);
220 WebSocketFrame::OpCode opcode = WebSocketFrame::OpCodeClose;
221 WebSocketFrame f1(opcode, "Hello", 5, WebSocketFrame::Final);
222
223 ASSERT_TRUE(c.deflate(f1));
224 EXPECT_TRUE(f1.final);
225 EXPECT_FALSE(f1.compress);
226 EXPECT_EQ(std::string("Hello"), std::string(f1.payload, f1.payloadLength));
227 }
228
TEST(WebSocketPerMessageDeflateTest,TestDeflateControlMessageBetweenTextFrames)229 TEST(WebSocketPerMessageDeflateTest, TestDeflateControlMessageBetweenTextFrames)
230 {
231 WebSocketPerMessageDeflate c;
232 c.enable(8, WebSocketDeflater::TakeOverContext);
233 WebSocketFrame::OpCode close = WebSocketFrame::OpCodeClose;
234 WebSocketFrame::OpCode text = WebSocketFrame::OpCodeText;
235 WebSocketFrame::OpCode continuation = WebSocketFrame::OpCodeContinuation;
236 WebSocketFrame f1(text, "Hello", 5);
237 WebSocketFrame f2(close, "close", 5, WebSocketFrame::Final);
238 WebSocketFrame f3(continuation, "", 0, WebSocketFrame::Final);
239
240 std::vector<char> compressed;
241 ASSERT_TRUE(c.deflate(f1));
242 EXPECT_FALSE(f1.final);
243 EXPECT_TRUE(f1.compress);
244 std::copy(&f1.payload[0], &f1.payload[f1.payloadLength], std::inserter(compressed, compressed.end()));
245
246 c.resetDeflateBuffer();
247 ASSERT_TRUE(c.deflate(f2));
248 EXPECT_TRUE(f2.final);
249 EXPECT_FALSE(f2.compress);
250 EXPECT_EQ(std::string("close"), std::string(f2.payload, f2.payloadLength));
251
252 c.resetDeflateBuffer();
253 ASSERT_TRUE(c.deflate(f3));
254 EXPECT_TRUE(f3.final);
255 EXPECT_FALSE(f3.compress);
256 std::copy(&f3.payload[0], &f3.payload[f3.payloadLength], std::inserter(compressed, compressed.end()));
257
258 EXPECT_EQ(7u, compressed.size());
259 EXPECT_EQ(0, memcmp("\xf2\x48\xcd\xc9\xc9\x07\x00", &compressed[0], compressed.size()));
260 }
261
TEST(WebSocketPerMessageDeflateTest,TestInflate)262 TEST(WebSocketPerMessageDeflateTest, TestInflate)
263 {
264 WebSocketPerMessageDeflate c;
265 c.enable(8, WebSocketDeflater::TakeOverContext);
266 WebSocketFrame::OpCode opcode = WebSocketFrame::OpCodeText;
267 WebSocketFrame::OpCode continuation = WebSocketFrame::OpCodeContinuation;
268 std::string expected = "HelloHi!Hello";
269 std::string actual;
270 WebSocketFrame f1(opcode, "\xf2\x48\xcd\xc9\xc9\x07\x00", 7, WebSocketFrame::Final | WebSocketFrame::Compress);
271 WebSocketFrame f2(continuation, "Hi!", 3, WebSocketFrame::Final);
272 WebSocketFrame f3(opcode, "\xf2\x00\x11\x00\x00", 5, WebSocketFrame::Final | WebSocketFrame::Compress);
273
274 ASSERT_TRUE(c.inflate(f1));
275 EXPECT_EQ(5u, f1.payloadLength);
276 EXPECT_EQ(std::string("Hello"), std::string(f1.payload, f1.payloadLength));
277 EXPECT_FALSE(f1.compress);
278 EXPECT_TRUE(f1.final);
279
280 c.resetInflateBuffer();
281 ASSERT_TRUE(c.inflate(f2));
282 EXPECT_EQ(3u, f2.payloadLength);
283 EXPECT_EQ(std::string("Hi!"), std::string(f2.payload, f2.payloadLength));
284 EXPECT_FALSE(f2.compress);
285 EXPECT_TRUE(f2.final);
286
287 c.resetInflateBuffer();
288 ASSERT_TRUE(c.inflate(f3));
289 EXPECT_EQ(5u, f3.payloadLength);
290 EXPECT_EQ(std::string("Hello"), std::string(f3.payload, f3.payloadLength));
291 EXPECT_FALSE(f3.compress);
292 EXPECT_TRUE(f3.final);
293 }
294
TEST(WebSocketPerMessageDeflateTest,TestInflateEmptyFrame)295 TEST(WebSocketPerMessageDeflateTest, TestInflateEmptyFrame)
296 {
297 WebSocketPerMessageDeflate c;
298 c.enable(8, WebSocketDeflater::TakeOverContext);
299 WebSocketFrame::OpCode opcode = WebSocketFrame::OpCodeText;
300 WebSocketFrame::OpCode continuation = WebSocketFrame::OpCodeContinuation;
301 WebSocketFrame f1(opcode, "", 0, WebSocketFrame::Compress);
302 WebSocketFrame f2(continuation, "\xf2\x48\xcd\xc9\xc9\x07\x00", 7, WebSocketFrame::Final);
303
304 ASSERT_TRUE(c.inflate(f1));
305 EXPECT_EQ(0u, f1.payloadLength);
306 EXPECT_FALSE(f1.compress);
307 EXPECT_FALSE(f1.final);
308
309 c.resetInflateBuffer();
310 ASSERT_TRUE(c.inflate(f2));
311 EXPECT_EQ(5u, f2.payloadLength);
312 EXPECT_EQ(std::string("Hello"), std::string(f2.payload, f2.payloadLength));
313 EXPECT_FALSE(f2.compress);
314 EXPECT_TRUE(f2.final);
315 }
316
TEST(WebSocketPerMessageDeflateTest,TestInflateControlMessageBetweenTextFrames)317 TEST(WebSocketPerMessageDeflateTest, TestInflateControlMessageBetweenTextFrames)
318 {
319 WebSocketPerMessageDeflate c;
320 c.enable(8, WebSocketDeflater::TakeOverContext);
321 WebSocketFrame::OpCode close = WebSocketFrame::OpCodeClose;
322 WebSocketFrame::OpCode text = WebSocketFrame::OpCodeText;
323 WebSocketFrame f1(text, "\xf2\x48", 2, WebSocketFrame::Compress);
324 WebSocketFrame f2(close, "close", 5, WebSocketFrame::Final);
325 WebSocketFrame f3(text, "\xcd\xc9\xc9\x07\x00", 5, WebSocketFrame::Final);
326
327 std::vector<char> decompressed;
328 ASSERT_TRUE(c.inflate(f1));
329 EXPECT_FALSE(f1.final);
330 EXPECT_FALSE(f1.compress);
331 std::copy(&f1.payload[0], &f1.payload[f1.payloadLength], std::inserter(decompressed, decompressed.end()));
332
333 c.resetInflateBuffer();
334 ASSERT_TRUE(c.inflate(f2));
335 EXPECT_TRUE(f2.final);
336 EXPECT_FALSE(f2.compress);
337 EXPECT_EQ(std::string("close"), std::string(f2.payload, f2.payloadLength));
338
339 c.resetInflateBuffer();
340 ASSERT_TRUE(c.inflate(f3));
341 std::copy(&f3.payload[0], &f3.payload[f3.payloadLength], std::inserter(decompressed, decompressed.end()));
342 EXPECT_TRUE(f3.final);
343 EXPECT_FALSE(f3.compress);
344
345 EXPECT_EQ(std::string("Hello"), std::string(&decompressed[0], decompressed.size()));
346 }
347
TEST(WebSocketPerMessageDeflateTest,TestNotEnabled)348 TEST(WebSocketPerMessageDeflateTest, TestNotEnabled)
349 {
350 WebSocketPerMessageDeflate c;
351 WebSocketFrame::OpCode opcode = WebSocketFrame::OpCodeClose;
352 WebSocketFrame f1(opcode, "Hello", 5, WebSocketFrame::Final | WebSocketFrame::Compress);
353 WebSocketFrame f2(opcode, "\xf2\x48\xcd\xc9\xc9\x07\x00", 7, WebSocketFrame::Final | WebSocketFrame::Compress);
354
355 // deflate and inflate return true and do nothing if it is not enabled.
356 ASSERT_TRUE(c.deflate(f1));
357 ASSERT_TRUE(f1.compress);
358 ASSERT_TRUE(c.inflate(f2));
359 ASSERT_TRUE(f2.compress);
360 }
361
processResponse(const HashMap<String,String> & serverParameters)362 bool processResponse(const HashMap<String, String>& serverParameters)
363 {
364 return WebSocketPerMessageDeflate().createExtensionProcessor()->processResponse(serverParameters);
365 }
366
TEST(WebSocketPerMessageDeflateTest,TestValidNegotiationResponse)367 TEST(WebSocketPerMessageDeflateTest, TestValidNegotiationResponse)
368 {
369 {
370 HashMap<String, String> params;
371 EXPECT_TRUE(processResponse(params));
372 }
373 {
374 HashMap<String, String> params;
375 params.add("client_max_window_bits", "15");
376 EXPECT_TRUE(processResponse(params));
377 }
378 {
379 HashMap<String, String> params;
380 params.add("client_max_window_bits", "8");
381 EXPECT_TRUE(processResponse(params));
382 }
383 {
384 HashMap<String, String> params;
385 params.add("client_max_window_bits", "15");
386 params.add("client_no_context_takeover", String());
387 EXPECT_TRUE(processResponse(params));
388 }
389 {
390 // Unsolicited server_no_context_takeover should be ignored.
391 HashMap<String, String> params;
392 params.add("server_no_context_takeover", String());
393 EXPECT_TRUE(processResponse(params));
394 }
395 {
396 // Unsolicited server_max_window_bits should be ignored.
397 HashMap<String, String> params;
398 params.add("server_max_window_bits", "15");
399 EXPECT_TRUE(processResponse(params));
400 }
401 }
402
TEST(WebSocketPerMessageDeflateTest,TestInvalidNegotiationResponse)403 TEST(WebSocketPerMessageDeflateTest, TestInvalidNegotiationResponse)
404 {
405 {
406 HashMap<String, String> params;
407 params.add("method", "deflate");
408 EXPECT_FALSE(processResponse(params));
409 }
410 {
411 HashMap<String, String> params;
412 params.add("foo", "");
413 EXPECT_FALSE(processResponse(params));
414 }
415 {
416 HashMap<String, String> params;
417 params.add("foo", "bar");
418 EXPECT_FALSE(processResponse(params));
419 }
420 {
421 HashMap<String, String> params;
422 params.add("client_max_window_bits", "");
423 EXPECT_FALSE(processResponse(params));
424 }
425 {
426 HashMap<String, String> params;
427 params.add("client_max_window_bits", "16");
428 EXPECT_FALSE(processResponse(params));
429 }
430 {
431 HashMap<String, String> params;
432 params.add("client_max_window_bits", "7");
433 EXPECT_FALSE(processResponse(params));
434 }
435 {
436 HashMap<String, String> params;
437 params.add("client_max_window_bits", "+15");
438 EXPECT_FALSE(processResponse(params));
439 }
440 {
441 HashMap<String, String> params;
442 params.add("client_max_window_bits", "0x9");
443 EXPECT_FALSE(processResponse(params));
444 }
445 {
446 HashMap<String, String> params;
447 params.add("client_max_window_bits", "08");
448 EXPECT_FALSE(processResponse(params));
449 }
450 {
451 // Unsolicited server_no_context_takeover should be verified though it is not used.
452 HashMap<String, String> params;
453 params.add("server_no_context_takeover", "foo");
454 EXPECT_FALSE(processResponse(params));
455 }
456 {
457 // Unsolicited server_max_window_bits should be verified though it is not used.
458 HashMap<String, String> params;
459 params.add("server_max_window_bits", "7");
460 EXPECT_FALSE(processResponse(params));
461 }
462 {
463 // Unsolicited server_max_window_bits should be verified though it is not used.
464 HashMap<String, String> params;
465 params.add("server_max_window_bits", "bar");
466 EXPECT_FALSE(processResponse(params));
467 }
468 {
469 // Unsolicited server_max_window_bits should be verified though it is not used.
470 HashMap<String, String> params;
471 params.add("server_max_window_bits", "16");
472 EXPECT_FALSE(processResponse(params));
473 }
474 {
475 // Unsolicited server_max_window_bits should be verified though it is not used.
476 HashMap<String, String> params;
477 params.add("server_max_window_bits", "08");
478 EXPECT_FALSE(processResponse(params));
479 }
480 }
481
TEST(WebSocketPerMessageDeflateTest,TestNegotiationRequest)482 TEST(WebSocketPerMessageDeflateTest, TestNegotiationRequest)
483 {
484 String actual = WebSocketPerMessageDeflate().createExtensionProcessor()->handshakeString();
485 EXPECT_EQ(String("permessage-deflate; client_max_window_bits"), actual);
486 }
487 } // namespace
488