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 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 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 89 TEST(WebSocketPerMessageDeflateTest, TestDeflateInflateMultipleFrame) 90 { 91 WebSocketPerMessageDeflate c; 92 WebSocketFrame::OpCode opcode = WebSocketFrame::OpCodeText; 93 c.enable(8, WebSocketDeflater::DoNotTakeOverContext); 94 size_t length = 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(opcode, &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 c.resetDeflateBuffer(); 113 WebSocketFrame frame(opcode, &payload[i], 1); 114 frame.final = (i == length - 1); 115 116 ASSERT_TRUE(c.deflate(frame)); 117 ASSERT_EQ(i == length - 1, frame.final); 118 ASSERT_EQ(!i, frame.compress); 119 actual += std::string(frame.payload, frame.payloadLength); 120 } 121 EXPECT_EQ(expected, actual); 122 123 for (size_t i = 0; i < actual.size(); ++i) { 124 c.resetInflateBuffer(); 125 WebSocketFrame frame(opcode, &actual[i], 1); 126 frame.final = (i == length - 1); 127 frame.compress = !i; 128 129 ASSERT_TRUE(c.inflate(frame)); 130 ASSERT_EQ(i == length - 1, frame.final); 131 ASSERT_FALSE(frame.compress); 132 inflated += std::string(frame.payload, frame.payloadLength); 133 } 134 EXPECT_EQ(payload, inflated); 135 } 136 137 TEST(WebSocketPerMessageDeflateTest, TestDeflateBinary) 138 { 139 WebSocketPerMessageDeflate c; 140 c.enable(8, WebSocketDeflater::TakeOverContext); 141 WebSocketFrame::OpCode opcode = WebSocketFrame::OpCodeBinary; 142 WebSocketFrame f1(opcode, "Hello", 5, WebSocketFrame::Final); 143 144 ASSERT_TRUE(c.deflate(f1)); 145 EXPECT_EQ(7u, f1.payloadLength); 146 EXPECT_EQ(0, memcmp("\xf2\x48\xcd\xc9\xc9\x07\x00", f1.payload, f1.payloadLength)); 147 EXPECT_EQ(opcode, f1.opCode); 148 EXPECT_TRUE(f1.compress); 149 EXPECT_TRUE(f1.final); 150 } 151 152 TEST(WebSocketPerMessageDeflateTest, TestDeflateEmptyFrame) 153 { 154 WebSocketPerMessageDeflate c; 155 c.enable(8, WebSocketDeflater::TakeOverContext); 156 WebSocketFrame::OpCode opcode = WebSocketFrame::OpCodeText; 157 WebSocketFrame f1(opcode, "Hello", 5); 158 WebSocketFrame f2(opcode, "", 0, WebSocketFrame::Final); 159 160 ASSERT_TRUE(c.deflate(f1)); 161 EXPECT_EQ(0u, f1.payloadLength); 162 EXPECT_FALSE(f1.final); 163 EXPECT_TRUE(f1.compress); 164 165 c.resetDeflateBuffer(); 166 ASSERT_TRUE(c.deflate(f2)); 167 EXPECT_EQ(7u, f2.payloadLength); 168 EXPECT_EQ(0, memcmp("\xf2\x48\xcd\xc9\xc9\x07\x00", f2.payload, f2.payloadLength)); 169 EXPECT_TRUE(f2.final); 170 EXPECT_FALSE(f2.compress); 171 } 172 173 TEST(WebSocketPerMessageDeflateTest, TestDeflateEmptyMessages) 174 { 175 WebSocketPerMessageDeflate c; 176 c.enable(8, WebSocketDeflater::TakeOverContext); 177 WebSocketFrame::OpCode opcode = WebSocketFrame::OpCodeText; 178 WebSocketFrame f1(opcode, "", 0); 179 WebSocketFrame f2(opcode, "", 0, WebSocketFrame::Final); 180 WebSocketFrame f3(opcode, "", 0, WebSocketFrame::Final); 181 WebSocketFrame f4(opcode, "", 0, WebSocketFrame::Final); 182 WebSocketFrame f5(opcode, "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(2u, f3.payloadLength); 199 EXPECT_EQ(0, memcmp("\x02\x00", f3.payload, f3.payloadLength)); 200 EXPECT_TRUE(f3.final); 201 EXPECT_TRUE(f3.compress); 202 203 c.resetDeflateBuffer(); 204 ASSERT_TRUE(c.deflate(f4)); 205 EXPECT_EQ(2u, f4.payloadLength); 206 EXPECT_EQ(0, memcmp("\x02\x00", f4.payload, f4.payloadLength)); 207 EXPECT_TRUE(f4.final); 208 EXPECT_TRUE(f4.compress); 209 210 c.resetDeflateBuffer(); 211 ASSERT_TRUE(c.deflate(f5)); 212 EXPECT_EQ(7u, f5.payloadLength); 213 EXPECT_EQ(0, memcmp("\xf2\x48\xcd\xc9\xc9\x07\x00", f5.payload, f5.payloadLength)); 214 EXPECT_TRUE(f5.final); 215 EXPECT_TRUE(f5.compress); 216 } 217 218 TEST(WebSocketPerMessageDeflateTest, TestControlMessage) 219 { 220 WebSocketPerMessageDeflate c; 221 c.enable(8, WebSocketDeflater::TakeOverContext); 222 WebSocketFrame::OpCode opcode = WebSocketFrame::OpCodeClose; 223 WebSocketFrame f1(opcode, "Hello", 5, WebSocketFrame::Final); 224 225 ASSERT_TRUE(c.deflate(f1)); 226 EXPECT_TRUE(f1.final); 227 EXPECT_FALSE(f1.compress); 228 EXPECT_EQ(std::string("Hello"), std::string(f1.payload, f1.payloadLength)); 229 } 230 231 TEST(WebSocketPerMessageDeflateTest, TestDeflateControlMessageBetweenTextFrames) 232 { 233 WebSocketPerMessageDeflate c; 234 c.enable(8, WebSocketDeflater::TakeOverContext); 235 WebSocketFrame::OpCode close = WebSocketFrame::OpCodeClose; 236 WebSocketFrame::OpCode text = WebSocketFrame::OpCodeText; 237 WebSocketFrame f1(text, "Hello", 5); 238 WebSocketFrame f2(close, "close", 5, WebSocketFrame::Final); 239 WebSocketFrame f3(text, "", 0, WebSocketFrame::Final); 240 241 std::vector<char> compressed; 242 ASSERT_TRUE(c.deflate(f1)); 243 EXPECT_FALSE(f1.final); 244 EXPECT_TRUE(f1.compress); 245 std::copy(&f1.payload[0], &f1.payload[f1.payloadLength], std::inserter(compressed, compressed.end())); 246 247 c.resetDeflateBuffer(); 248 ASSERT_TRUE(c.deflate(f2)); 249 EXPECT_TRUE(f2.final); 250 EXPECT_FALSE(f2.compress); 251 EXPECT_EQ(std::string("close"), std::string(f2.payload, f2.payloadLength)); 252 253 c.resetDeflateBuffer(); 254 ASSERT_TRUE(c.deflate(f3)); 255 EXPECT_TRUE(f3.final); 256 EXPECT_FALSE(f3.compress); 257 std::copy(&f3.payload[0], &f3.payload[f3.payloadLength], std::inserter(compressed, compressed.end())); 258 259 EXPECT_EQ(7u, compressed.size()); 260 EXPECT_EQ(0, memcmp("\xf2\x48\xcd\xc9\xc9\x07\x00", &compressed[0], compressed.size())); 261 } 262 263 TEST(WebSocketPerMessageDeflateTest, TestInflate) 264 { 265 WebSocketPerMessageDeflate c; 266 c.enable(8, WebSocketDeflater::TakeOverContext); 267 WebSocketFrame::OpCode opcode = WebSocketFrame::OpCodeText; 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(opcode, "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 295 TEST(WebSocketPerMessageDeflateTest, TestInflateEmptyFrame) 296 { 297 WebSocketPerMessageDeflate c; 298 c.enable(8, WebSocketDeflater::TakeOverContext); 299 WebSocketFrame::OpCode opcode = WebSocketFrame::OpCodeText; 300 WebSocketFrame f1(opcode, "", 0, WebSocketFrame::Compress); 301 WebSocketFrame f2(opcode, "\xf2\x48\xcd\xc9\xc9\x07\x00", 7, WebSocketFrame::Final); 302 303 ASSERT_TRUE(c.inflate(f1)); 304 EXPECT_EQ(0u, f1.payloadLength); 305 EXPECT_FALSE(f1.compress); 306 EXPECT_FALSE(f1.final); 307 308 c.resetInflateBuffer(); 309 ASSERT_TRUE(c.inflate(f2)); 310 EXPECT_EQ(5u, f2.payloadLength); 311 EXPECT_EQ(std::string("Hello"), std::string(f2.payload, f2.payloadLength)); 312 EXPECT_FALSE(f2.compress); 313 EXPECT_TRUE(f2.final); 314 } 315 316 TEST(WebSocketPerMessageDeflateTest, TestInflateControlMessageBetweenTextFrames) 317 { 318 WebSocketPerMessageDeflate c; 319 c.enable(8, WebSocketDeflater::TakeOverContext); 320 WebSocketFrame::OpCode close = WebSocketFrame::OpCodeClose; 321 WebSocketFrame::OpCode text = WebSocketFrame::OpCodeText; 322 WebSocketFrame f1(text, "\xf2\x48", 2, WebSocketFrame::Compress); 323 WebSocketFrame f2(close, "close", 5, WebSocketFrame::Final); 324 WebSocketFrame f3(text, "\xcd\xc9\xc9\x07\x00", 5, WebSocketFrame::Final); 325 326 std::vector<char> decompressed; 327 ASSERT_TRUE(c.inflate(f1)); 328 EXPECT_FALSE(f1.final); 329 EXPECT_FALSE(f1.compress); 330 std::copy(&f1.payload[0], &f1.payload[f1.payloadLength], std::inserter(decompressed, decompressed.end())); 331 332 c.resetInflateBuffer(); 333 ASSERT_TRUE(c.inflate(f2)); 334 EXPECT_TRUE(f2.final); 335 EXPECT_FALSE(f2.compress); 336 EXPECT_EQ(std::string("close"), std::string(f2.payload, f2.payloadLength)); 337 338 c.resetInflateBuffer(); 339 ASSERT_TRUE(c.inflate(f3)); 340 std::copy(&f3.payload[0], &f3.payload[f3.payloadLength], std::inserter(decompressed, decompressed.end())); 341 EXPECT_TRUE(f3.final); 342 EXPECT_FALSE(f3.compress); 343 344 EXPECT_EQ(std::string("Hello"), std::string(&decompressed[0], decompressed.size())); 345 } 346 347 TEST(WebSocketPerMessageDeflateTest, TestNotEnabled) 348 { 349 WebSocketPerMessageDeflate c; 350 WebSocketFrame::OpCode opcode = WebSocketFrame::OpCodeClose; 351 WebSocketFrame f1(opcode, "Hello", 5, WebSocketFrame::Final | WebSocketFrame::Compress); 352 WebSocketFrame f2(opcode, "\xf2\x48\xcd\xc9\xc9\x07\x00", 7, WebSocketFrame::Final | WebSocketFrame::Compress); 353 354 // deflate and inflate return true and do nothing if it is not enabled. 355 ASSERT_TRUE(c.deflate(f1)); 356 ASSERT_TRUE(f1.compress); 357 ASSERT_TRUE(c.inflate(f2)); 358 ASSERT_TRUE(f2.compress); 359 } 360 361 bool processResponse(const HashMap<String, String>& serverParameters) 362 { 363 return WebSocketPerMessageDeflate().createExtensionProcessor()->processResponse(serverParameters); 364 } 365 366 TEST(WebSocketPerMessageDeflateTest, TestValidNegotiationResponse) 367 { 368 { 369 HashMap<String, String> params; 370 EXPECT_TRUE(processResponse(params)); 371 } 372 { 373 HashMap<String, String> params; 374 params.add("c2s_max_window_bits", "15"); 375 EXPECT_TRUE(processResponse(params)); 376 } 377 { 378 HashMap<String, String> params; 379 params.add("c2s_max_window_bits", "8"); 380 EXPECT_TRUE(processResponse(params)); 381 } 382 { 383 HashMap<String, String> params; 384 params.add("c2s_max_window_bits", "15"); 385 params.add("c2s_no_context_takeover", String()); 386 EXPECT_TRUE(processResponse(params)); 387 } 388 { 389 // Unsolicited s2c_no_context_takeover should be ignored. 390 HashMap<String, String> params; 391 params.add("s2c_no_context_takeover", String()); 392 EXPECT_TRUE(processResponse(params)); 393 } 394 { 395 // Unsolicited s2c_max_window_bits should be ignored. 396 HashMap<String, String> params; 397 params.add("s2c_max_window_bits", "15"); 398 EXPECT_TRUE(processResponse(params)); 399 } 400 } 401 402 TEST(WebSocketPerMessageDeflateTest, TestInvalidNegotiationResponse) 403 { 404 { 405 HashMap<String, String> params; 406 params.add("method", "deflate"); 407 EXPECT_FALSE(processResponse(params)); 408 } 409 { 410 HashMap<String, String> params; 411 params.add("foo", ""); 412 EXPECT_FALSE(processResponse(params)); 413 } 414 { 415 HashMap<String, String> params; 416 params.add("foo", "bar"); 417 EXPECT_FALSE(processResponse(params)); 418 } 419 { 420 HashMap<String, String> params; 421 params.add("c2s_max_window_bits", ""); 422 EXPECT_FALSE(processResponse(params)); 423 } 424 { 425 HashMap<String, String> params; 426 params.add("c2s_max_window_bits", "16"); 427 EXPECT_FALSE(processResponse(params)); 428 } 429 { 430 HashMap<String, String> params; 431 params.add("c2s_max_window_bits", "7"); 432 EXPECT_FALSE(processResponse(params)); 433 } 434 { 435 HashMap<String, String> params; 436 params.add("c2s_max_window_bits", "+15"); 437 EXPECT_FALSE(processResponse(params)); 438 } 439 { 440 HashMap<String, String> params; 441 params.add("c2s_max_window_bits", "0x9"); 442 EXPECT_FALSE(processResponse(params)); 443 } 444 { 445 HashMap<String, String> params; 446 params.add("c2s_max_window_bits", "08"); 447 EXPECT_FALSE(processResponse(params)); 448 } 449 { 450 // Unsolicited s2c_no_context_takeover should be verified though it is not used. 451 HashMap<String, String> params; 452 params.add("s2c_no_context_takeover", "foo"); 453 EXPECT_FALSE(processResponse(params)); 454 } 455 { 456 // Unsolicited s2c_max_window_bits should be verified though it is not used. 457 HashMap<String, String> params; 458 params.add("s2c_max_window_bits", "7"); 459 EXPECT_FALSE(processResponse(params)); 460 } 461 { 462 // Unsolicited s2c_max_window_bits should be verified though it is not used. 463 HashMap<String, String> params; 464 params.add("s2c_max_window_bits", "bar"); 465 EXPECT_FALSE(processResponse(params)); 466 } 467 { 468 // Unsolicited s2c_max_window_bits should be verified though it is not used. 469 HashMap<String, String> params; 470 params.add("s2c_max_window_bits", "16"); 471 EXPECT_FALSE(processResponse(params)); 472 } 473 { 474 // Unsolicited s2c_max_window_bits should be verified though it is not used. 475 HashMap<String, String> params; 476 params.add("s2c_max_window_bits", "08"); 477 EXPECT_FALSE(processResponse(params)); 478 } 479 } 480 481 TEST(WebSocketPerMessageDeflateTest, TestNegotiationRequest) 482 { 483 String actual = WebSocketPerMessageDeflate().createExtensionProcessor()->handshakeString(); 484 EXPECT_EQ(String("permessage-deflate; c2s_max_window_bits"), actual); 485 } 486 } // namespace 487