| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 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/socket/web_socket_server_socket.h" | |
| 6 | |
| 7 #include <stdlib.h> | |
| 8 #include <algorithm> | |
| 9 | |
| 10 #include "base/bind.h" | |
| 11 #include "base/bind_helpers.h" | |
| 12 #include "base/memory/ref_counted.h" | |
| 13 #include "base/memory/weak_ptr.h" | |
| 14 #include "base/message_loop.h" | |
| 15 #include "base/string_util.h" | |
| 16 #include "base/time.h" | |
| 17 #include "net/base/io_buffer.h" | |
| 18 #include "net/base/net_errors.h" | |
| 19 #include "testing/gtest/include/gtest/gtest.h" | |
| 20 | |
| 21 namespace { | |
| 22 | |
| 23 const char* kSampleHandshakeRequest[] = { | |
| 24 "GET /demo HTTP/1.1", | |
| 25 "Upgrade: WebSocket", | |
| 26 "Connection: Upgrade", | |
| 27 "Host: example.com", | |
| 28 "Origin: http://example.com", | |
| 29 "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5", | |
| 30 "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00", | |
| 31 "", | |
| 32 "^n:ds[4U" | |
| 33 }; | |
| 34 | |
| 35 const char kSampleHandshakeAnswer[] = | |
| 36 "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" | |
| 37 "Upgrade: WebSocket\r\n" | |
| 38 "Connection: Upgrade\r\n" | |
| 39 "Sec-WebSocket-Location: ws://example.com/demo\r\n" | |
| 40 "Sec-WebSocket-Origin: http://example.com\r\n" | |
| 41 "\r\n" | |
| 42 "8jKS'y:G*Co,Wxa-"; | |
| 43 | |
| 44 const int kHandshakeBufBytes = 1 << 12; | |
| 45 | |
| 46 const char kCRLF[] = "\r\n"; | |
| 47 const char kCRLFCRLF[] = "\r\n\r\n"; | |
| 48 const char kSpaceOctet = '\x20'; | |
| 49 | |
| 50 const int kReadSalt = 7; | |
| 51 const int kWriteSalt = 5; | |
| 52 | |
| 53 int GetRand(int min, int max) { | |
| 54 CHECK(max >= min); | |
| 55 CHECK(max - min < RAND_MAX); | |
| 56 return rand() % (max - min + 1) + min; | |
| 57 } | |
| 58 | |
| 59 class RandIntClass { | |
| 60 public: | |
| 61 int operator() (int range) { | |
| 62 return GetRand(0, range - 1); | |
| 63 } | |
| 64 } g_rand; | |
| 65 | |
| 66 net::DrainableIOBuffer* ResizeIOBuffer(net::DrainableIOBuffer* buf, int len) { | |
| 67 net::DrainableIOBuffer* rv = new net::DrainableIOBuffer( | |
| 68 new net::IOBuffer(len), len); | |
| 69 std::copy(buf->data(), buf->data() + std::min(len, buf->BytesRemaining()), | |
| 70 rv->data()); | |
| 71 return rv; | |
| 72 } | |
| 73 | |
| 74 // TODO(dilmah): consider switching to socket_test_util.h | |
| 75 // Simulates reading from |sample| stream; data supplied in Write() calls are | |
| 76 // stored in |answer| buffer. | |
| 77 class TestingTransportSocket : public net::Socket { | |
| 78 public: | |
| 79 TestingTransportSocket( | |
| 80 net::DrainableIOBuffer* sample, net::DrainableIOBuffer* answer) | |
| 81 : sample_(sample), | |
| 82 answer_(answer), | |
| 83 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { | |
| 84 } | |
| 85 | |
| 86 ~TestingTransportSocket() { | |
| 87 if (!final_read_callback_.is_null()) { | |
| 88 MessageLoop::current()->PostTask(FROM_HERE, | |
| 89 base::Bind(&TestingTransportSocket::DoReadCallback, | |
| 90 weak_factory_.GetWeakPtr(), | |
| 91 final_read_callback_, 0)); | |
| 92 } | |
| 93 } | |
| 94 | |
| 95 // Socket implementation. | |
| 96 virtual int Read(net::IOBuffer* buf, int buf_len, | |
| 97 const net::CompletionCallback& callback) { | |
| 98 CHECK_GT(buf_len, 0); | |
| 99 int remaining = sample_->BytesRemaining(); | |
| 100 if (remaining < 1) { | |
| 101 if (!final_read_callback_.is_null()) | |
| 102 return 0; | |
| 103 final_read_callback_ = callback; | |
| 104 return net::ERR_IO_PENDING; | |
| 105 } | |
| 106 int lot = GetRand(1, std::min(remaining, buf_len)); | |
| 107 std::copy(sample_->data(), sample_->data() + lot, buf->data()); | |
| 108 sample_->DidConsume(lot); | |
| 109 if (GetRand(0, 1)) { | |
| 110 return lot; | |
| 111 } | |
| 112 MessageLoop::current()->PostTask( | |
| 113 FROM_HERE, | |
| 114 base::Bind(&TestingTransportSocket::DoReadCallback, | |
| 115 weak_factory_.GetWeakPtr(), callback, lot)); | |
| 116 return net::ERR_IO_PENDING; | |
| 117 } | |
| 118 | |
| 119 virtual int Write(net::IOBuffer* buf, int buf_len, | |
| 120 const net::CompletionCallback& callback) { | |
| 121 CHECK_GT(buf_len, 0); | |
| 122 int remaining = answer_->BytesRemaining(); | |
| 123 CHECK_GE(remaining, buf_len); | |
| 124 int lot = std::min(remaining, buf_len); | |
| 125 if (GetRand(0, 1)) | |
| 126 lot = GetRand(1, lot); | |
| 127 std::copy(buf->data(), buf->data() + lot, answer_->data()); | |
| 128 answer_->DidConsume(lot); | |
| 129 if (GetRand(0, 1)) { | |
| 130 return lot; | |
| 131 } | |
| 132 MessageLoop::current()->PostTask( | |
| 133 FROM_HERE, | |
| 134 base::Bind(&TestingTransportSocket::DoWriteCallback, | |
| 135 weak_factory_.GetWeakPtr(), callback, lot)); | |
| 136 return net::ERR_IO_PENDING; | |
| 137 } | |
| 138 | |
| 139 virtual bool SetReceiveBufferSize(int32 size) { | |
| 140 return true; | |
| 141 } | |
| 142 | |
| 143 virtual bool SetSendBufferSize(int32 size) { | |
| 144 return true; | |
| 145 } | |
| 146 | |
| 147 net::DrainableIOBuffer* answer() { return answer_.get(); } | |
| 148 | |
| 149 void DoReadCallback(const net::CompletionCallback& callback, int result) { | |
| 150 if (result == 0 && !is_closed_) { | |
| 151 MessageLoop::current()->PostTask( | |
| 152 FROM_HERE, | |
| 153 base::Bind( | |
| 154 &TestingTransportSocket::DoReadCallback, | |
| 155 weak_factory_.GetWeakPtr(), callback, 0)); | |
| 156 } else { | |
| 157 if (!callback.is_null()) | |
| 158 callback.Run(result); | |
| 159 } | |
| 160 } | |
| 161 | |
| 162 void DoWriteCallback(const net::CompletionCallback& callback, int result) { | |
| 163 if (!callback.is_null()) | |
| 164 callback.Run(result); | |
| 165 } | |
| 166 | |
| 167 bool is_closed_; | |
| 168 | |
| 169 // Data to return for Read requests. | |
| 170 scoped_refptr<net::DrainableIOBuffer> sample_; | |
| 171 | |
| 172 // Data pushed to us by server socket (using Write calls). | |
| 173 scoped_refptr<net::DrainableIOBuffer> answer_; | |
| 174 | |
| 175 // Final read callback to report zero (zero stands for EOF). | |
| 176 net::CompletionCallback final_read_callback_; | |
| 177 | |
| 178 base::WeakPtrFactory<TestingTransportSocket> weak_factory_; | |
| 179 }; | |
| 180 | |
| 181 class Validator : public net::WebSocketServerSocket::Delegate { | |
| 182 public: | |
| 183 Validator(const std::string& resource, | |
| 184 const std::string& origin, | |
| 185 const std::string& host) | |
| 186 : resource_(resource), origin_(origin), host_(host) { | |
| 187 } | |
| 188 | |
| 189 // WebSocketServerSocket::Delegate implementation. | |
| 190 virtual bool ValidateWebSocket( | |
| 191 const std::string& resource, | |
| 192 const std::string& origin, | |
| 193 const std::string& host, | |
| 194 const std::vector<std::string>& subprotocol_list, | |
| 195 std::string* location_out, | |
| 196 std::string* subprotocol_out) { | |
| 197 if (resource != resource_ || origin != origin_ || host != host_) | |
| 198 return false; | |
| 199 if (!subprotocol_list.empty()) | |
| 200 *subprotocol_out = subprotocol_list.front(); | |
| 201 | |
| 202 char tmp[2048]; | |
| 203 base::snprintf( | |
| 204 tmp, sizeof(tmp), "ws://%s%s", host.c_str(), resource.c_str()); | |
| 205 location_out->assign(tmp); | |
| 206 return true; | |
| 207 } | |
| 208 | |
| 209 private: | |
| 210 std::string resource_; | |
| 211 std::string origin_; | |
| 212 std::string host_; | |
| 213 }; | |
| 214 | |
| 215 char ReferenceSeq(unsigned n, unsigned salt) { | |
| 216 return (salt * 2 + n * 3) % ('z' - 'a') + 'a'; | |
| 217 } | |
| 218 | |
| 219 class ReadWriteTracker { | |
| 220 public: | |
| 221 ReadWriteTracker( | |
| 222 net::WebSocketServerSocket* ws, int bytes_to_read, int bytes_to_write) | |
| 223 : ws_(ws), | |
| 224 buf_size_(1 << 14), | |
| 225 read_buf_(new net::IOBuffer(buf_size_)), | |
| 226 write_buf_(new net::IOBuffer(buf_size_)), | |
| 227 bytes_remaining_to_read_(bytes_to_read), | |
| 228 bytes_remaining_to_write_(bytes_to_write), | |
| 229 got_final_zero_(false) { | |
| 230 int rv = ws_->Accept( | |
| 231 base::Bind(&ReadWriteTracker::OnAccept, base::Unretained(this))); | |
| 232 if (rv != net::ERR_IO_PENDING) | |
| 233 OnAccept(rv); | |
| 234 } | |
| 235 | |
| 236 ~ReadWriteTracker() { | |
| 237 CHECK_EQ(bytes_remaining_to_write_, 0); | |
| 238 CHECK_EQ(bytes_remaining_to_read_, 0); | |
| 239 } | |
| 240 | |
| 241 void OnAccept(int result) { | |
| 242 ASSERT_EQ(result, 0); | |
| 243 if (GetRand(0, 1)) { | |
| 244 DoRead(); | |
| 245 DoWrite(); | |
| 246 } else { | |
| 247 DoWrite(); | |
| 248 DoRead(); | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 void DoWrite() { | |
| 253 if (bytes_remaining_to_write_ < 1) | |
| 254 return; | |
| 255 int lot = GetRand(1, bytes_remaining_to_write_); | |
| 256 lot = std::min(lot, buf_size_); | |
| 257 for (int i = 0; i < lot; ++i) | |
| 258 write_buf_->data()[i] = ReferenceSeq( | |
| 259 bytes_remaining_to_write_ - i - 1, kWriteSalt); | |
| 260 int rv = ws_->Write(write_buf_, lot, base::Bind(&ReadWriteTracker::OnWrite, | |
| 261 base::Unretained(this))); | |
| 262 if (rv != net::ERR_IO_PENDING) | |
| 263 OnWrite(rv); | |
| 264 } | |
| 265 | |
| 266 void DoRead() { | |
| 267 int lot = GetRand(1, buf_size_); | |
| 268 if (bytes_remaining_to_read_ < 1) { | |
| 269 if (got_final_zero_) | |
| 270 return; | |
| 271 } else { | |
| 272 lot = GetRand(1, bytes_remaining_to_read_); | |
| 273 lot = std::min(lot, buf_size_); | |
| 274 } | |
| 275 int rv = ws_->Read(read_buf_, lot, base::Bind(&ReadWriteTracker::OnRead, | |
| 276 base::Unretained(this))); | |
| 277 if (rv != net::ERR_IO_PENDING) | |
| 278 OnRead(rv); | |
| 279 } | |
| 280 | |
| 281 void OnWrite(int result) { | |
| 282 ASSERT_GT(result, 0); | |
| 283 ASSERT_LE(result, bytes_remaining_to_write_); | |
| 284 bytes_remaining_to_write_ -= result; | |
| 285 DoWrite(); | |
| 286 } | |
| 287 | |
| 288 void OnRead(int result) { | |
| 289 ASSERT_LE(result, bytes_remaining_to_read_); | |
| 290 if (bytes_remaining_to_read_ < 1) { | |
| 291 ASSERT_FALSE(got_final_zero_); | |
| 292 ASSERT_EQ(result, 0); | |
| 293 got_final_zero_ = true; | |
| 294 return; | |
| 295 } | |
| 296 for (int i = 0; i < result; ++i) { | |
| 297 ASSERT_EQ(read_buf_->data()[i], ReferenceSeq( | |
| 298 bytes_remaining_to_read_ - i - 1, kReadSalt)); | |
| 299 } | |
| 300 bytes_remaining_to_read_ -= result; | |
| 301 DoRead(); | |
| 302 } | |
| 303 | |
| 304 private: | |
| 305 net::WebSocketServerSocket* const ws_; | |
| 306 int const buf_size_; | |
| 307 scoped_refptr<net::IOBuffer> read_buf_; | |
| 308 scoped_refptr<net::IOBuffer> write_buf_; | |
| 309 int bytes_remaining_to_read_; | |
| 310 int bytes_remaining_to_write_; | |
| 311 bool got_final_zero_; | |
| 312 }; | |
| 313 | |
| 314 } // namespace | |
| 315 | |
| 316 namespace net { | |
| 317 | |
| 318 class WebSocketServerSocketTest : public testing::Test { | |
| 319 public: | |
| 320 virtual ~WebSocketServerSocketTest() { | |
| 321 } | |
| 322 | |
| 323 virtual void SetUp() { | |
| 324 count_ = 0; | |
| 325 } | |
| 326 | |
| 327 virtual void TearDown() { | |
| 328 } | |
| 329 | |
| 330 void OnAccept0(int result) { | |
| 331 ASSERT_EQ(result, 0); | |
| 332 ASSERT_LT(count_, 99999); | |
| 333 count_ += 1; | |
| 334 } | |
| 335 | |
| 336 void OnAccept1(int result) { | |
| 337 ASSERT_TRUE(result == ERR_CONNECTION_REFUSED || | |
| 338 result == ERR_ACCESS_DENIED); | |
| 339 ASSERT_LT(count_, 99999); | |
| 340 count_ += 1; | |
| 341 } | |
| 342 | |
| 343 int count_; | |
| 344 }; | |
| 345 | |
| 346 TEST_F(WebSocketServerSocketTest, Handshake) { | |
| 347 srand(2523456); | |
| 348 std::vector<Socket*> kill_list; | |
| 349 std::vector< scoped_refptr<DrainableIOBuffer> > answer_list; | |
| 350 Validator validator("/demo", "http://example.com/", "example.com"); | |
| 351 count_ = 0; | |
| 352 const int kNumTests = 300; | |
| 353 for (int run = kNumTests; run--;) { | |
| 354 scoped_refptr<DrainableIOBuffer> sample = new DrainableIOBuffer( | |
| 355 new IOBuffer(kHandshakeBufBytes), kHandshakeBufBytes); | |
| 356 for (size_t i = 0; i < arraysize(kSampleHandshakeRequest); ++i) { | |
| 357 std::copy(kSampleHandshakeRequest[i], | |
| 358 kSampleHandshakeRequest[i] + strlen(kSampleHandshakeRequest[i]), | |
| 359 sample->data()); | |
| 360 sample->DidConsume(strlen(kSampleHandshakeRequest[i])); | |
| 361 if (i != arraysize(kSampleHandshakeRequest) - 1) { | |
| 362 std::copy(kCRLF, kCRLF + strlen(kCRLF), sample->data()); | |
| 363 sample->DidConsume(strlen(kCRLF)); | |
| 364 } | |
| 365 } | |
| 366 int sample_len = sample->BytesConsumed(); | |
| 367 sample->SetOffset(0); | |
| 368 DrainableIOBuffer* answer = new DrainableIOBuffer( | |
| 369 new IOBuffer(kHandshakeBufBytes), kHandshakeBufBytes); | |
| 370 answer_list.push_back(answer); | |
| 371 TestingTransportSocket* transport = new TestingTransportSocket( | |
| 372 ResizeIOBuffer(sample.get(), sample_len), answer); | |
| 373 WebSocketServerSocket* ws = CreateWebSocketServerSocket( | |
| 374 transport, &validator); | |
| 375 ASSERT_TRUE(ws != NULL); | |
| 376 kill_list.push_back(ws); | |
| 377 | |
| 378 int rv = ws->Accept(base::Bind(&WebSocketServerSocketTest::OnAccept0, | |
| 379 base::Unretained(this))); | |
| 380 if (rv != ERR_IO_PENDING) | |
| 381 OnAccept0(rv); | |
| 382 } | |
| 383 MessageLoop::current()->RunAllPending(); | |
| 384 ASSERT_EQ(count_, kNumTests); | |
| 385 for (size_t i = answer_list.size(); i--;) { | |
| 386 ASSERT_EQ(answer_list[i]->BytesConsumed() + 0u, | |
| 387 strlen(kSampleHandshakeAnswer)); | |
| 388 ASSERT_TRUE(std::equal( | |
| 389 answer_list[i]->data() - answer_list[i]->BytesConsumed(), | |
| 390 answer_list[i]->data(), kSampleHandshakeAnswer)); | |
| 391 } | |
| 392 for (size_t i = kill_list.size(); i--;) | |
| 393 delete kill_list[i]; | |
| 394 MessageLoop::current()->RunAllPending(); | |
| 395 } | |
| 396 | |
| 397 TEST_F(WebSocketServerSocketTest, BadCred) { | |
| 398 srand(9034958); | |
| 399 std::vector<Socket*> kill_list; | |
| 400 std::vector< scoped_refptr<DrainableIOBuffer> > answer_list; | |
| 401 Validator *validator[] = { | |
| 402 new Validator("/demo", "http://gooogle.com/", "example.com"), | |
| 403 new Validator("/tcpproxy", "http://example.com/", "example.com"), | |
| 404 new Validator("/tcpproxy", "http://gooogle.com/", "example.com"), | |
| 405 new Validator("/demo", "http://example.com/", "exmple.com"), | |
| 406 new Validator("/demo", "http://gooogle.com/", "gooogle.com") | |
| 407 }; | |
| 408 count_ = 0; | |
| 409 for (int run = arraysize(validator); run--;) { | |
| 410 scoped_refptr<DrainableIOBuffer> sample = new DrainableIOBuffer( | |
| 411 new IOBuffer(kHandshakeBufBytes), kHandshakeBufBytes); | |
| 412 for (size_t i = 0; i < arraysize(kSampleHandshakeRequest); ++i) { | |
| 413 std::copy(kSampleHandshakeRequest[i], | |
| 414 kSampleHandshakeRequest[i] + strlen(kSampleHandshakeRequest[i]), | |
| 415 sample->data()); | |
| 416 sample->DidConsume(strlen(kSampleHandshakeRequest[i])); | |
| 417 if (i != arraysize(kSampleHandshakeRequest) - 1) { | |
| 418 std::copy(kCRLF, kCRLF + strlen(kCRLF), sample->data()); | |
| 419 sample->DidConsume(strlen(kCRLF)); | |
| 420 } | |
| 421 } | |
| 422 int sample_len = sample->BytesConsumed(); | |
| 423 sample->SetOffset(0); | |
| 424 DrainableIOBuffer* answer = new DrainableIOBuffer( | |
| 425 new IOBuffer(kHandshakeBufBytes), kHandshakeBufBytes); | |
| 426 answer_list.push_back(answer); | |
| 427 TestingTransportSocket* transport = new TestingTransportSocket( | |
| 428 ResizeIOBuffer(sample.get(), sample_len), answer); | |
| 429 WebSocketServerSocket* ws = CreateWebSocketServerSocket( | |
| 430 transport, validator[run]); | |
| 431 ASSERT_TRUE(ws != NULL); | |
| 432 kill_list.push_back(ws); | |
| 433 | |
| 434 int rv = ws->Accept(base::Bind(&WebSocketServerSocketTest::OnAccept1, | |
| 435 base::Unretained(this))); | |
| 436 if (rv != ERR_IO_PENDING) | |
| 437 OnAccept1(rv); | |
| 438 } | |
| 439 MessageLoop::current()->RunAllPending(); | |
| 440 ASSERT_EQ(count_ + 0u, arraysize(validator)); | |
| 441 for (size_t i = answer_list.size(); i--;) | |
| 442 ASSERT_EQ(answer_list[i]->BytesConsumed(), 0); | |
| 443 for (size_t i = kill_list.size(); i--;) | |
| 444 delete kill_list[i]; | |
| 445 for (size_t i = arraysize(validator); i--;) | |
| 446 delete validator[i]; | |
| 447 MessageLoop::current()->RunAllPending(); | |
| 448 } | |
| 449 | |
| 450 TEST_F(WebSocketServerSocketTest, ReorderedHandshake) { | |
| 451 srand(205643459); | |
| 452 std::vector<Socket*> kill_list; | |
| 453 std::vector< scoped_refptr<DrainableIOBuffer> > answer_list; | |
| 454 Validator validator("/demo", "http://example.com/", "example.com"); | |
| 455 count_ = 0; | |
| 456 const int kNumTests = 200; | |
| 457 for (int run = kNumTests; run--;) { | |
| 458 scoped_refptr<DrainableIOBuffer> sample = new DrainableIOBuffer( | |
| 459 new IOBuffer(kHandshakeBufBytes), kHandshakeBufBytes); | |
| 460 | |
| 461 std::vector<size_t> fields_order; | |
| 462 for (size_t i = 0; i < arraysize(kSampleHandshakeRequest); ++i) | |
| 463 fields_order.push_back(i); | |
| 464 // One leading and two trailing lines of request are special, leave them. | |
| 465 std::random_shuffle(fields_order.begin() + 1, | |
| 466 fields_order.begin() + fields_order.size() - 3, | |
| 467 g_rand); | |
| 468 | |
| 469 for (size_t i = 0; i < arraysize(kSampleHandshakeRequest); ++i) { | |
| 470 size_t j = fields_order[i]; | |
| 471 std::copy(kSampleHandshakeRequest[j], | |
| 472 kSampleHandshakeRequest[j] + strlen(kSampleHandshakeRequest[j]), | |
| 473 sample->data()); | |
| 474 sample->DidConsume(strlen(kSampleHandshakeRequest[j])); | |
| 475 if (i != arraysize(kSampleHandshakeRequest) - 1) { | |
| 476 std::copy(kCRLF, kCRLF + strlen(kCRLF), sample->data()); | |
| 477 sample->DidConsume(strlen(kCRLF)); | |
| 478 } | |
| 479 } | |
| 480 int sample_len = sample->BytesConsumed(); | |
| 481 sample->SetOffset(0); | |
| 482 DrainableIOBuffer* answer = new DrainableIOBuffer( | |
| 483 new IOBuffer(kHandshakeBufBytes), kHandshakeBufBytes); | |
| 484 answer_list.push_back(answer); | |
| 485 TestingTransportSocket* transport = new TestingTransportSocket( | |
| 486 ResizeIOBuffer(sample.get(), sample_len), answer); | |
| 487 WebSocketServerSocket* ws = CreateWebSocketServerSocket( | |
| 488 transport, &validator); | |
| 489 ASSERT_TRUE(ws != NULL); | |
| 490 kill_list.push_back(ws); | |
| 491 | |
| 492 int rv = ws->Accept(base::Bind(&WebSocketServerSocketTest::OnAccept0, | |
| 493 base::Unretained(this))); | |
| 494 if (rv != ERR_IO_PENDING) | |
| 495 OnAccept0(rv); | |
| 496 } | |
| 497 MessageLoop::current()->RunAllPending(); | |
| 498 ASSERT_EQ(count_, kNumTests); | |
| 499 for (size_t i = answer_list.size(); i--;) { | |
| 500 ASSERT_EQ(answer_list[i]->BytesConsumed() + 0u, | |
| 501 strlen(kSampleHandshakeAnswer)); | |
| 502 ASSERT_TRUE(std::equal( | |
| 503 answer_list[i]->data() - answer_list[i]->BytesConsumed(), | |
| 504 answer_list[i]->data(), kSampleHandshakeAnswer)); | |
| 505 } | |
| 506 for (size_t i = kill_list.size(); i--;) | |
| 507 delete kill_list[i]; | |
| 508 MessageLoop::current()->RunAllPending(); | |
| 509 } | |
| 510 | |
| 511 TEST_F(WebSocketServerSocketTest, ConveyData) { | |
| 512 srand(8234523); | |
| 513 std::vector<Socket*> kill_list; | |
| 514 std::vector<ReadWriteTracker*> tracker_list; | |
| 515 Validator validator("/demo", "http://example.com/", "example.com"); | |
| 516 count_ = 0; | |
| 517 const int kNumTests = 150; | |
| 518 for (int run = kNumTests; run--;) { | |
| 519 int bytes_to_read = GetRand(1, 1 << 14); | |
| 520 int bytes_to_write = GetRand(1, 1 << 14); | |
| 521 int frames_limit = GetRand(1, 1 << 10); | |
| 522 int sample_limit = kHandshakeBufBytes + bytes_to_write + frames_limit * 2; | |
| 523 scoped_refptr<DrainableIOBuffer> sample = new DrainableIOBuffer( | |
| 524 new IOBuffer(sample_limit), sample_limit); | |
| 525 | |
| 526 std::vector<size_t> fields_order; | |
| 527 for (size_t i = 0; i < arraysize(kSampleHandshakeRequest); ++i) | |
| 528 fields_order.push_back(i); | |
| 529 // One leading and two trailing lines of request are special, leave them. | |
| 530 std::random_shuffle(fields_order.begin() + 1, | |
| 531 fields_order.begin() + fields_order.size() - 3, | |
| 532 g_rand); | |
| 533 | |
| 534 for (size_t i = 0; i < arraysize(kSampleHandshakeRequest); ++i) { | |
| 535 size_t j = fields_order[i]; | |
| 536 std::copy(kSampleHandshakeRequest[j], | |
| 537 kSampleHandshakeRequest[j] + strlen(kSampleHandshakeRequest[j]), | |
| 538 sample->data()); | |
| 539 sample->DidConsume(strlen(kSampleHandshakeRequest[j])); | |
| 540 if (i != arraysize(kSampleHandshakeRequest) - 1) { | |
| 541 std::copy(kCRLF, kCRLF + strlen(kCRLF), sample->data()); | |
| 542 sample->DidConsume(strlen(kCRLF)); | |
| 543 } | |
| 544 } | |
| 545 { | |
| 546 bool outside_frame = true; | |
| 547 int pos = 0; | |
| 548 for (int i = 0; i < bytes_to_write; ++i) { | |
| 549 if (outside_frame) { | |
| 550 sample->data()[pos++] = '\x00'; | |
| 551 outside_frame = false; | |
| 552 CHECK_GE(frames_limit, 1); | |
| 553 frames_limit -= 1; | |
| 554 } | |
| 555 sample->data()[pos++] = ReferenceSeq(bytes_to_write - i - 1, kReadSalt); | |
| 556 if ((frames_limit > 1 && | |
| 557 GetRand(0, 1 + (bytes_to_write - i) / frames_limit) == 0) || | |
| 558 i == bytes_to_write - 1) { | |
| 559 sample->data()[pos++] = '\xff'; | |
| 560 outside_frame = true; | |
| 561 } | |
| 562 } | |
| 563 sample->DidConsume(pos); | |
| 564 } | |
| 565 | |
| 566 int sample_len = sample->BytesConsumed(); | |
| 567 sample->SetOffset(0); | |
| 568 int answer_limit = kHandshakeBufBytes + bytes_to_read * 3; | |
| 569 DrainableIOBuffer* answer = new DrainableIOBuffer( | |
| 570 new IOBuffer(answer_limit), answer_limit); | |
| 571 TestingTransportSocket* transport = new TestingTransportSocket( | |
| 572 ResizeIOBuffer(sample.get(), sample_len), answer); | |
| 573 WebSocketServerSocket* ws = CreateWebSocketServerSocket( | |
| 574 transport, &validator); | |
| 575 ASSERT_TRUE(ws != NULL); | |
| 576 kill_list.push_back(ws); | |
| 577 | |
| 578 ReadWriteTracker* tracker = new ReadWriteTracker( | |
| 579 ws, bytes_to_write, bytes_to_read); | |
| 580 tracker_list.push_back(tracker); | |
| 581 } | |
| 582 MessageLoop::current()->RunAllPending(); | |
| 583 | |
| 584 for (size_t i = kill_list.size(); i--;) | |
| 585 delete kill_list[i]; | |
| 586 for (size_t i = tracker_list.size(); i--;) | |
| 587 delete tracker_list[i]; | |
| 588 MessageLoop::current()->RunAllPending(); | |
| 589 } | |
| 590 | |
| 591 } // namespace net | |
| OLD | NEW |