| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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/websockets/websocket.h" | |
| 6 | |
| 7 #include <string> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/bind.h" | |
| 11 #include "base/bind_helpers.h" | |
| 12 #include "base/callback.h" | |
| 13 #include "net/base/completion_callback.h" | |
| 14 #include "net/base/io_buffer.h" | |
| 15 #include "net/base/mock_host_resolver.h" | |
| 16 #include "net/base/test_completion_callback.h" | |
| 17 #include "net/socket/socket_test_util.h" | |
| 18 #include "net/url_request/url_request_test_util.h" | |
| 19 #include "testing/gtest/include/gtest/gtest.h" | |
| 20 #include "testing/gmock/include/gmock/gmock.h" | |
| 21 #include "testing/platform_test.h" | |
| 22 | |
| 23 struct WebSocketEvent { | |
| 24 enum EventType { | |
| 25 EVENT_OPEN, EVENT_MESSAGE, EVENT_ERROR, EVENT_CLOSE, | |
| 26 }; | |
| 27 | |
| 28 WebSocketEvent(EventType type, net::WebSocket* websocket, | |
| 29 const std::string& websocket_msg, bool websocket_flag) | |
| 30 : event_type(type), socket(websocket), msg(websocket_msg), | |
| 31 flag(websocket_flag) {} | |
| 32 | |
| 33 EventType event_type; | |
| 34 net::WebSocket* socket; | |
| 35 std::string msg; | |
| 36 bool flag; | |
| 37 }; | |
| 38 | |
| 39 class WebSocketEventRecorder : public net::WebSocketDelegate { | |
| 40 public: | |
| 41 explicit WebSocketEventRecorder(net::CompletionCallback* callback) | |
| 42 : callback_(callback) {} | |
| 43 virtual ~WebSocketEventRecorder() {} | |
| 44 | |
| 45 void SetOnOpen(const base::Callback<void(WebSocketEvent*)>& callback) { | |
| 46 onopen_ = callback; | |
| 47 } | |
| 48 void SetOnMessage(const base::Callback<void(WebSocketEvent*)>& callback) { | |
| 49 onmessage_ = callback; | |
| 50 } | |
| 51 void SetOnClose(const base::Callback<void(WebSocketEvent*)>& callback) { | |
| 52 onclose_ = callback; | |
| 53 } | |
| 54 | |
| 55 virtual void OnOpen(net::WebSocket* socket) { | |
| 56 events_.push_back( | |
| 57 WebSocketEvent(WebSocketEvent::EVENT_OPEN, socket, | |
| 58 std::string(), false)); | |
| 59 if (!onopen_.is_null()) | |
| 60 onopen_.Run(&events_.back()); | |
| 61 } | |
| 62 | |
| 63 virtual void OnMessage(net::WebSocket* socket, const std::string& msg) { | |
| 64 events_.push_back( | |
| 65 WebSocketEvent(WebSocketEvent::EVENT_MESSAGE, socket, msg, false)); | |
| 66 if (!onmessage_.is_null()) | |
| 67 onmessage_.Run(&events_.back()); | |
| 68 } | |
| 69 virtual void OnError(net::WebSocket* socket) { | |
| 70 events_.push_back( | |
| 71 WebSocketEvent(WebSocketEvent::EVENT_ERROR, socket, | |
| 72 std::string(), false)); | |
| 73 if (!onerror_.is_null()) | |
| 74 onerror_.Run(&events_.back()); | |
| 75 } | |
| 76 virtual void OnClose(net::WebSocket* socket, bool was_clean) { | |
| 77 events_.push_back( | |
| 78 WebSocketEvent(WebSocketEvent::EVENT_CLOSE, socket, | |
| 79 std::string(), was_clean)); | |
| 80 if (!onclose_.is_null()) | |
| 81 onclose_.Run(&events_.back()); | |
| 82 if (callback_) | |
| 83 callback_->Run(net::OK); | |
| 84 } | |
| 85 | |
| 86 void DoClose(WebSocketEvent* event) { | |
| 87 event->socket->Close(); | |
| 88 } | |
| 89 | |
| 90 const std::vector<WebSocketEvent>& GetSeenEvents() const { | |
| 91 return events_; | |
| 92 } | |
| 93 | |
| 94 private: | |
| 95 std::vector<WebSocketEvent> events_; | |
| 96 base::Callback<void(WebSocketEvent*)> onopen_; | |
| 97 base::Callback<void(WebSocketEvent*)> onmessage_; | |
| 98 base::Callback<void(WebSocketEvent*)> onerror_; | |
| 99 base::Callback<void(WebSocketEvent*)> onclose_; | |
| 100 net::CompletionCallback* callback_; | |
| 101 | |
| 102 DISALLOW_COPY_AND_ASSIGN(WebSocketEventRecorder); | |
| 103 }; | |
| 104 | |
| 105 namespace net { | |
| 106 | |
| 107 class WebSocketTest : public PlatformTest { | |
| 108 protected: | |
| 109 void InitReadBuf(WebSocket* websocket) { | |
| 110 // Set up |current_read_buf_|. | |
| 111 websocket->current_read_buf_ = new GrowableIOBuffer(); | |
| 112 } | |
| 113 void SetReadConsumed(WebSocket* websocket, int consumed) { | |
| 114 websocket->read_consumed_len_ = consumed; | |
| 115 } | |
| 116 void AddToReadBuf(WebSocket* websocket, const char* data, int len) { | |
| 117 websocket->AddToReadBuffer(data, len); | |
| 118 } | |
| 119 | |
| 120 void TestProcessFrameData(WebSocket* websocket, | |
| 121 const char* expected_remaining_data, | |
| 122 int expected_remaining_len) { | |
| 123 websocket->ProcessFrameData(); | |
| 124 | |
| 125 const char* actual_remaining_data = | |
| 126 websocket->current_read_buf_->StartOfBuffer() | |
| 127 + websocket->read_consumed_len_; | |
| 128 int actual_remaining_len = | |
| 129 websocket->current_read_buf_->offset() - websocket->read_consumed_len_; | |
| 130 | |
| 131 EXPECT_EQ(expected_remaining_len, actual_remaining_len); | |
| 132 EXPECT_TRUE(!memcmp(expected_remaining_data, actual_remaining_data, | |
| 133 expected_remaining_len)); | |
| 134 } | |
| 135 }; | |
| 136 | |
| 137 TEST_F(WebSocketTest, Connect) { | |
| 138 MockClientSocketFactory mock_socket_factory; | |
| 139 MockRead data_reads[] = { | |
| 140 MockRead("HTTP/1.1 101 Web Socket Protocol Handshake\r\n" | |
| 141 "Upgrade: WebSocket\r\n" | |
| 142 "Connection: Upgrade\r\n" | |
| 143 "WebSocket-Origin: http://example.com\r\n" | |
| 144 "WebSocket-Location: ws://example.com/demo\r\n" | |
| 145 "WebSocket-Protocol: sample\r\n" | |
| 146 "\r\n"), | |
| 147 // Server doesn't close the connection after handshake. | |
| 148 MockRead(true, ERR_IO_PENDING), | |
| 149 }; | |
| 150 MockWrite data_writes[] = { | |
| 151 MockWrite("GET /demo HTTP/1.1\r\n" | |
| 152 "Upgrade: WebSocket\r\n" | |
| 153 "Connection: Upgrade\r\n" | |
| 154 "Host: example.com\r\n" | |
| 155 "Origin: http://example.com\r\n" | |
| 156 "WebSocket-Protocol: sample\r\n" | |
| 157 "\r\n"), | |
| 158 }; | |
| 159 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 160 data_writes, arraysize(data_writes)); | |
| 161 mock_socket_factory.AddSocketDataProvider(&data); | |
| 162 MockHostResolver host_resolver; | |
| 163 | |
| 164 WebSocket::Request* request( | |
| 165 new WebSocket::Request(GURL("ws://example.com/demo"), | |
| 166 "sample", | |
| 167 "http://example.com", | |
| 168 "ws://example.com/demo", | |
| 169 WebSocket::DRAFT75, | |
| 170 new TestURLRequestContext())); | |
| 171 request->SetHostResolver(&host_resolver); | |
| 172 request->SetClientSocketFactory(&mock_socket_factory); | |
| 173 | |
| 174 TestCompletionCallback callback; | |
| 175 | |
| 176 scoped_ptr<WebSocketEventRecorder> delegate( | |
| 177 new WebSocketEventRecorder(&callback)); | |
| 178 delegate->SetOnOpen(base::Bind(&WebSocketEventRecorder::DoClose, | |
| 179 base::Unretained(delegate.get()))); | |
| 180 | |
| 181 scoped_refptr<WebSocket> websocket( | |
| 182 new WebSocket(request, delegate.get())); | |
| 183 | |
| 184 EXPECT_EQ(WebSocket::INITIALIZED, websocket->ready_state()); | |
| 185 websocket->Connect(); | |
| 186 | |
| 187 callback.WaitForResult(); | |
| 188 | |
| 189 const std::vector<WebSocketEvent>& events = delegate->GetSeenEvents(); | |
| 190 EXPECT_EQ(2U, events.size()); | |
| 191 | |
| 192 EXPECT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); | |
| 193 EXPECT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type); | |
| 194 } | |
| 195 | |
| 196 TEST_F(WebSocketTest, ServerSentData) { | |
| 197 MockClientSocketFactory mock_socket_factory; | |
| 198 static const char kMessage[] = "Hello"; | |
| 199 static const char kFrame[] = "\x00Hello\xff"; | |
| 200 static const int kFrameLen = sizeof(kFrame) - 1; | |
| 201 MockRead data_reads[] = { | |
| 202 MockRead("HTTP/1.1 101 Web Socket Protocol Handshake\r\n" | |
| 203 "Upgrade: WebSocket\r\n" | |
| 204 "Connection: Upgrade\r\n" | |
| 205 "WebSocket-Origin: http://example.com\r\n" | |
| 206 "WebSocket-Location: ws://example.com/demo\r\n" | |
| 207 "WebSocket-Protocol: sample\r\n" | |
| 208 "\r\n"), | |
| 209 MockRead(true, kFrame, kFrameLen), | |
| 210 // Server doesn't close the connection after handshake. | |
| 211 MockRead(true, ERR_IO_PENDING), | |
| 212 }; | |
| 213 MockWrite data_writes[] = { | |
| 214 MockWrite("GET /demo HTTP/1.1\r\n" | |
| 215 "Upgrade: WebSocket\r\n" | |
| 216 "Connection: Upgrade\r\n" | |
| 217 "Host: example.com\r\n" | |
| 218 "Origin: http://example.com\r\n" | |
| 219 "WebSocket-Protocol: sample\r\n" | |
| 220 "\r\n"), | |
| 221 }; | |
| 222 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 223 data_writes, arraysize(data_writes)); | |
| 224 mock_socket_factory.AddSocketDataProvider(&data); | |
| 225 MockHostResolver host_resolver; | |
| 226 | |
| 227 WebSocket::Request* request( | |
| 228 new WebSocket::Request(GURL("ws://example.com/demo"), | |
| 229 "sample", | |
| 230 "http://example.com", | |
| 231 "ws://example.com/demo", | |
| 232 WebSocket::DRAFT75, | |
| 233 new TestURLRequestContext())); | |
| 234 request->SetHostResolver(&host_resolver); | |
| 235 request->SetClientSocketFactory(&mock_socket_factory); | |
| 236 | |
| 237 TestCompletionCallback callback; | |
| 238 | |
| 239 scoped_ptr<WebSocketEventRecorder> delegate( | |
| 240 new WebSocketEventRecorder(&callback)); | |
| 241 delegate->SetOnMessage(base::Bind(&WebSocketEventRecorder::DoClose, | |
| 242 base::Unretained(delegate.get()))); | |
| 243 | |
| 244 scoped_refptr<WebSocket> websocket( | |
| 245 new WebSocket(request, delegate.get())); | |
| 246 | |
| 247 EXPECT_EQ(WebSocket::INITIALIZED, websocket->ready_state()); | |
| 248 websocket->Connect(); | |
| 249 | |
| 250 callback.WaitForResult(); | |
| 251 | |
| 252 const std::vector<WebSocketEvent>& events = delegate->GetSeenEvents(); | |
| 253 EXPECT_EQ(3U, events.size()); | |
| 254 | |
| 255 EXPECT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); | |
| 256 EXPECT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type); | |
| 257 EXPECT_EQ(kMessage, events[1].msg); | |
| 258 EXPECT_EQ(WebSocketEvent::EVENT_CLOSE, events[2].event_type); | |
| 259 } | |
| 260 | |
| 261 TEST_F(WebSocketTest, ProcessFrameDataForLengthCalculation) { | |
| 262 WebSocket::Request* request( | |
| 263 new WebSocket::Request(GURL("ws://example.com/demo"), | |
| 264 "sample", | |
| 265 "http://example.com", | |
| 266 "ws://example.com/demo", | |
| 267 WebSocket::DRAFT75, | |
| 268 new TestURLRequestContext())); | |
| 269 TestCompletionCallback callback; | |
| 270 scoped_ptr<WebSocketEventRecorder> delegate( | |
| 271 new WebSocketEventRecorder(&callback)); | |
| 272 | |
| 273 scoped_refptr<WebSocket> websocket( | |
| 274 new WebSocket(request, delegate.get())); | |
| 275 | |
| 276 // Frame data: skip length 1 ('x'), and try to skip length 129 | |
| 277 // (1 * 128 + 1) bytes after \x81\x01, but buffer is too short to skip. | |
| 278 static const char kTestLengthFrame[] = | |
| 279 "\x80\x01x\x80\x81\x01\x01\x00unexpected data\xFF"; | |
| 280 const int kTestLengthFrameLength = sizeof(kTestLengthFrame) - 1; | |
| 281 InitReadBuf(websocket.get()); | |
| 282 AddToReadBuf(websocket.get(), kTestLengthFrame, kTestLengthFrameLength); | |
| 283 SetReadConsumed(websocket.get(), 0); | |
| 284 | |
| 285 static const char kExpectedRemainingFrame[] = | |
| 286 "\x80\x81\x01\x01\x00unexpected data\xFF"; | |
| 287 const int kExpectedRemainingLength = sizeof(kExpectedRemainingFrame) - 1; | |
| 288 TestProcessFrameData(websocket.get(), | |
| 289 kExpectedRemainingFrame, kExpectedRemainingLength); | |
| 290 // No onmessage event expected. | |
| 291 const std::vector<WebSocketEvent>& events = delegate->GetSeenEvents(); | |
| 292 EXPECT_EQ(1U, events.size()); | |
| 293 | |
| 294 EXPECT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type); | |
| 295 | |
| 296 websocket->DetachDelegate(); | |
| 297 } | |
| 298 | |
| 299 TEST_F(WebSocketTest, ProcessFrameDataForUnterminatedString) { | |
| 300 WebSocket::Request* request( | |
| 301 new WebSocket::Request(GURL("ws://example.com/demo"), | |
| 302 "sample", | |
| 303 "http://example.com", | |
| 304 "ws://example.com/demo", | |
| 305 WebSocket::DRAFT75, | |
| 306 new TestURLRequestContext())); | |
| 307 TestCompletionCallback callback; | |
| 308 scoped_ptr<WebSocketEventRecorder> delegate( | |
| 309 new WebSocketEventRecorder(&callback)); | |
| 310 | |
| 311 scoped_refptr<WebSocket> websocket( | |
| 312 new WebSocket(request, delegate.get())); | |
| 313 | |
| 314 static const char kTestUnterminatedFrame[] = | |
| 315 "\x00unterminated frame"; | |
| 316 const int kTestUnterminatedFrameLength = sizeof(kTestUnterminatedFrame) - 1; | |
| 317 InitReadBuf(websocket.get()); | |
| 318 AddToReadBuf(websocket.get(), kTestUnterminatedFrame, | |
| 319 kTestUnterminatedFrameLength); | |
| 320 SetReadConsumed(websocket.get(), 0); | |
| 321 TestProcessFrameData(websocket.get(), | |
| 322 kTestUnterminatedFrame, kTestUnterminatedFrameLength); | |
| 323 { | |
| 324 // No onmessage event expected. | |
| 325 const std::vector<WebSocketEvent>& events = delegate->GetSeenEvents(); | |
| 326 EXPECT_EQ(0U, events.size()); | |
| 327 } | |
| 328 | |
| 329 static const char kTestTerminateFrame[] = " is terminated in next read\xff"; | |
| 330 const int kTestTerminateFrameLength = sizeof(kTestTerminateFrame) - 1; | |
| 331 AddToReadBuf(websocket.get(), kTestTerminateFrame, | |
| 332 kTestTerminateFrameLength); | |
| 333 TestProcessFrameData(websocket.get(), "", 0); | |
| 334 | |
| 335 static const char kExpectedMsg[] = | |
| 336 "unterminated frame is terminated in next read"; | |
| 337 { | |
| 338 const std::vector<WebSocketEvent>& events = delegate->GetSeenEvents(); | |
| 339 EXPECT_EQ(1U, events.size()); | |
| 340 | |
| 341 EXPECT_EQ(WebSocketEvent::EVENT_MESSAGE, events[0].event_type); | |
| 342 EXPECT_EQ(kExpectedMsg, events[0].msg); | |
| 343 } | |
| 344 | |
| 345 websocket->DetachDelegate(); | |
| 346 } | |
| 347 | |
| 348 } // namespace net | |
| OLD | NEW |