blob: ea3d1fe6c2b4899ea94fedead79fe51aa21b6a9c [file] [log] [blame]
[email protected]6d9fc742009-10-21 07:59:361// Copyright (c) 2009 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 <string>
6#include <vector>
7
[email protected]2041cf342010-02-19 03:15:598#include "base/callback.h"
[email protected]6d9fc742009-10-21 07:59:369#include "net/base/completion_callback.h"
[email protected]92aea482009-10-23 02:25:3810#include "net/base/io_buffer.h"
[email protected]6d9fc742009-10-21 07:59:3611#include "net/base/mock_host_resolver.h"
12#include "net/base/test_completion_callback.h"
13#include "net/socket/socket_test_util.h"
14#include "net/url_request/url_request_unittest.h"
15#include "net/websockets/websocket.h"
16#include "testing/gtest/include/gtest/gtest.h"
[email protected]06489a012009-12-10 08:12:5417#include "testing/gmock/include/gmock/gmock.h"
[email protected]6d9fc742009-10-21 07:59:3618#include "testing/platform_test.h"
19
20struct WebSocketEvent {
21 enum EventType {
22 EVENT_OPEN, EVENT_MESSAGE, EVENT_CLOSE,
23 };
24
25 WebSocketEvent(EventType type, net::WebSocket* websocket,
26 const std::string& websocket_msg)
27 : event_type(type), socket(websocket), msg(websocket_msg) {}
28
29 EventType event_type;
30 net::WebSocket* socket;
31 std::string msg;
32};
33
34class WebSocketEventRecorder : public net::WebSocketDelegate {
35 public:
36 explicit WebSocketEventRecorder(net::CompletionCallback* callback)
37 : onopen_(NULL),
38 onmessage_(NULL),
39 onclose_(NULL),
40 callback_(callback) {}
41 virtual ~WebSocketEventRecorder() {
42 delete onopen_;
43 delete onmessage_;
44 delete onclose_;
45 }
46
47 void SetOnOpen(Callback1<WebSocketEvent*>::Type* callback) {
48 onopen_ = callback;
49 }
50 void SetOnMessage(Callback1<WebSocketEvent*>::Type* callback) {
51 onmessage_ = callback;
52 }
53 void SetOnClose(Callback1<WebSocketEvent*>::Type* callback) {
54 onclose_ = callback;
55 }
56
57 virtual void OnOpen(net::WebSocket* socket) {
58 events_.push_back(
59 WebSocketEvent(WebSocketEvent::EVENT_OPEN, socket, std::string()));
60 if (onopen_)
61 onopen_->Run(&events_.back());
62 }
63
64 virtual void OnMessage(net::WebSocket* socket, const std::string& msg) {
65 events_.push_back(
66 WebSocketEvent(WebSocketEvent::EVENT_MESSAGE, socket, msg));
67 if (onmessage_)
68 onmessage_->Run(&events_.back());
69 }
70 virtual void OnClose(net::WebSocket* socket) {
71 events_.push_back(
72 WebSocketEvent(WebSocketEvent::EVENT_CLOSE, socket, std::string()));
73 if (onclose_)
74 onclose_->Run(&events_.back());
75 if (callback_)
76 callback_->Run(net::OK);
77 }
78
79 void DoClose(WebSocketEvent* event) {
80 event->socket->Close();
81 }
82
83 const std::vector<WebSocketEvent>& GetSeenEvents() const {
84 return events_;
85 }
86
87 private:
88 std::vector<WebSocketEvent> events_;
89 Callback1<WebSocketEvent*>::Type* onopen_;
90 Callback1<WebSocketEvent*>::Type* onmessage_;
91 Callback1<WebSocketEvent*>::Type* onclose_;
92 net::CompletionCallback* callback_;
93
94 DISALLOW_COPY_AND_ASSIGN(WebSocketEventRecorder);
95};
96
[email protected]92aea482009-10-23 02:25:3897namespace net {
98
[email protected]6d9fc742009-10-21 07:59:3699class WebSocketTest : public PlatformTest {
[email protected]92aea482009-10-23 02:25:38100 protected:
101 void InitReadBuf(WebSocket* websocket) {
102 // Set up |current_read_buf_|.
103 websocket->current_read_buf_ = new GrowableIOBuffer();
104 }
105 void SetReadConsumed(WebSocket* websocket, int consumed) {
106 websocket->read_consumed_len_ = consumed;
107 }
108 void AddToReadBuf(WebSocket* websocket, const char* data, int len) {
109 websocket->AddToReadBuffer(data, len);
110 }
111
112 void TestProcessFrameData(WebSocket* websocket,
113 const char* expected_remaining_data,
114 int expected_remaining_len) {
115 websocket->ProcessFrameData();
116
117 const char* actual_remaining_data =
118 websocket->current_read_buf_->StartOfBuffer()
119 + websocket->read_consumed_len_;
120 int actual_remaining_len =
121 websocket->current_read_buf_->offset() - websocket->read_consumed_len_;
122
123 EXPECT_EQ(expected_remaining_len, actual_remaining_len);
124 EXPECT_TRUE(!memcmp(expected_remaining_data, actual_remaining_data,
125 expected_remaining_len));
126 }
[email protected]6d9fc742009-10-21 07:59:36127};
128
129TEST_F(WebSocketTest, Connect) {
[email protected]92aea482009-10-23 02:25:38130 MockClientSocketFactory mock_socket_factory;
131 MockRead data_reads[] = {
[email protected]3e821c4c2009-11-05 10:27:26132 MockRead("HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
[email protected]92aea482009-10-23 02:25:38133 "Upgrade: WebSocket\r\n"
134 "Connection: Upgrade\r\n"
135 "WebSocket-Origin: http://example.com\r\n"
136 "WebSocket-Location: ws://example.com/demo\r\n"
137 "WebSocket-Protocol: sample\r\n"
138 "\r\n"),
[email protected]6d9fc742009-10-21 07:59:36139 // Server doesn't close the connection after handshake.
[email protected]92aea482009-10-23 02:25:38140 MockRead(true, ERR_IO_PENDING),
[email protected]6d9fc742009-10-21 07:59:36141 };
[email protected]92aea482009-10-23 02:25:38142 MockWrite data_writes[] = {
143 MockWrite("GET /demo HTTP/1.1\r\n"
144 "Upgrade: WebSocket\r\n"
145 "Connection: Upgrade\r\n"
146 "Host: example.com\r\n"
147 "Origin: http://example.com\r\n"
148 "WebSocket-Protocol: sample\r\n"
149 "\r\n"),
[email protected]6d9fc742009-10-21 07:59:36150 };
[email protected]31a2bfe2010-02-09 08:03:39151 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
152 data_writes, arraysize(data_writes));
[email protected]5ecc992a42009-11-11 01:41:59153 mock_socket_factory.AddSocketDataProvider(&data);
[email protected]6d9fc742009-10-21 07:59:36154
[email protected]92aea482009-10-23 02:25:38155 WebSocket::Request* request(
156 new WebSocket::Request(GURL("ws://example.com/demo"),
157 "sample",
158 "http://example.com",
159 "ws://example.com/demo",
160 new TestURLRequestContext()));
161 request->SetHostResolver(new MockHostResolver());
[email protected]6d9fc742009-10-21 07:59:36162 request->SetClientSocketFactory(&mock_socket_factory);
163
164 TestCompletionCallback callback;
165
166 scoped_ptr<WebSocketEventRecorder> delegate(
167 new WebSocketEventRecorder(&callback));
168 delegate->SetOnOpen(NewCallback(delegate.get(),
169 &WebSocketEventRecorder::DoClose));
170
[email protected]92aea482009-10-23 02:25:38171 scoped_refptr<WebSocket> websocket(
172 new WebSocket(request, delegate.get()));
[email protected]6d9fc742009-10-21 07:59:36173
[email protected]92aea482009-10-23 02:25:38174 EXPECT_EQ(WebSocket::INITIALIZED, websocket->ready_state());
[email protected]6d9fc742009-10-21 07:59:36175 websocket->Connect();
176
177 callback.WaitForResult();
178
179 const std::vector<WebSocketEvent>& events = delegate->GetSeenEvents();
180 EXPECT_EQ(2U, events.size());
181
182 EXPECT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
183 EXPECT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type);
184}
185
186TEST_F(WebSocketTest, ServerSentData) {
[email protected]92aea482009-10-23 02:25:38187 MockClientSocketFactory mock_socket_factory;
[email protected]6d9fc742009-10-21 07:59:36188 static const char kMessage[] = "Hello";
189 static const char kFrame[] = "\x00Hello\xff";
190 static const int kFrameLen = sizeof(kFrame) - 1;
[email protected]92aea482009-10-23 02:25:38191 MockRead data_reads[] = {
[email protected]3e821c4c2009-11-05 10:27:26192 MockRead("HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
193 "Upgrade: WebSocket\r\n"
194 "Connection: Upgrade\r\n"
195 "WebSocket-Origin: http://example.com\r\n"
196 "WebSocket-Location: ws://example.com/demo\r\n"
197 "WebSocket-Protocol: sample\r\n"
198 "\r\n"),
[email protected]92aea482009-10-23 02:25:38199 MockRead(true, kFrame, kFrameLen),
[email protected]6d9fc742009-10-21 07:59:36200 // Server doesn't close the connection after handshake.
[email protected]92aea482009-10-23 02:25:38201 MockRead(true, ERR_IO_PENDING),
[email protected]6d9fc742009-10-21 07:59:36202 };
[email protected]92aea482009-10-23 02:25:38203 MockWrite data_writes[] = {
204 MockWrite("GET /demo HTTP/1.1\r\n"
205 "Upgrade: WebSocket\r\n"
206 "Connection: Upgrade\r\n"
207 "Host: example.com\r\n"
208 "Origin: http://example.com\r\n"
209 "WebSocket-Protocol: sample\r\n"
210 "\r\n"),
[email protected]6d9fc742009-10-21 07:59:36211 };
[email protected]31a2bfe2010-02-09 08:03:39212 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
213 data_writes, arraysize(data_writes));
[email protected]5ecc992a42009-11-11 01:41:59214 mock_socket_factory.AddSocketDataProvider(&data);
[email protected]6d9fc742009-10-21 07:59:36215
[email protected]92aea482009-10-23 02:25:38216 WebSocket::Request* request(
217 new WebSocket::Request(GURL("ws://example.com/demo"),
218 "sample",
219 "http://example.com",
220 "ws://example.com/demo",
221 new TestURLRequestContext()));
222 request->SetHostResolver(new MockHostResolver());
[email protected]6d9fc742009-10-21 07:59:36223 request->SetClientSocketFactory(&mock_socket_factory);
224
225 TestCompletionCallback callback;
226
227 scoped_ptr<WebSocketEventRecorder> delegate(
228 new WebSocketEventRecorder(&callback));
229 delegate->SetOnMessage(NewCallback(delegate.get(),
230 &WebSocketEventRecorder::DoClose));
231
[email protected]92aea482009-10-23 02:25:38232 scoped_refptr<WebSocket> websocket(
233 new WebSocket(request, delegate.get()));
[email protected]6d9fc742009-10-21 07:59:36234
[email protected]92aea482009-10-23 02:25:38235 EXPECT_EQ(WebSocket::INITIALIZED, websocket->ready_state());
[email protected]6d9fc742009-10-21 07:59:36236 websocket->Connect();
237
238 callback.WaitForResult();
239
240 const std::vector<WebSocketEvent>& events = delegate->GetSeenEvents();
241 EXPECT_EQ(3U, events.size());
242
243 EXPECT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
244 EXPECT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type);
245 EXPECT_EQ(kMessage, events[1].msg);
246 EXPECT_EQ(WebSocketEvent::EVENT_CLOSE, events[2].event_type);
247}
[email protected]92aea482009-10-23 02:25:38248
249TEST_F(WebSocketTest, ProcessFrameDataForLengthCalculation) {
250 WebSocket::Request* request(
251 new WebSocket::Request(GURL("ws://example.com/demo"),
252 "sample",
253 "http://example.com",
254 "ws://example.com/demo",
255 new TestURLRequestContext()));
256 TestCompletionCallback callback;
257 scoped_ptr<WebSocketEventRecorder> delegate(
258 new WebSocketEventRecorder(&callback));
259
260 scoped_refptr<WebSocket> websocket(
261 new WebSocket(request, delegate.get()));
262
263 // Frame data: skip length 1 ('x'), and try to skip length 129
[email protected]b792af762009-12-07 04:32:48264 // (1 * 128 + 1) bytes after \x81\x01, but buffer is too short to skip.
[email protected]92aea482009-10-23 02:25:38265 static const char kTestLengthFrame[] =
[email protected]b792af762009-12-07 04:32:48266 "\x80\x01x\x80\x81\x01\x01\x00unexpected data\xFF";
[email protected]92aea482009-10-23 02:25:38267 const int kTestLengthFrameLength = sizeof(kTestLengthFrame) - 1;
268 InitReadBuf(websocket.get());
269 AddToReadBuf(websocket.get(), kTestLengthFrame, kTestLengthFrameLength);
270 SetReadConsumed(websocket.get(), 0);
271
272 static const char kExpectedRemainingFrame[] =
[email protected]b792af762009-12-07 04:32:48273 "\x80\x81\x01\x01\x00unexpected data\xFF";
[email protected]92aea482009-10-23 02:25:38274 const int kExpectedRemainingLength = sizeof(kExpectedRemainingFrame) - 1;
275 TestProcessFrameData(websocket.get(),
276 kExpectedRemainingFrame, kExpectedRemainingLength);
277 // No onmessage event expected.
278 const std::vector<WebSocketEvent>& events = delegate->GetSeenEvents();
279 EXPECT_EQ(0U, events.size());
[email protected]1ccf985c2009-11-06 10:11:01280
281 websocket->DetachDelegate();
[email protected]92aea482009-10-23 02:25:38282}
283
284TEST_F(WebSocketTest, ProcessFrameDataForUnterminatedString) {
285 WebSocket::Request* request(
286 new WebSocket::Request(GURL("ws://example.com/demo"),
287 "sample",
288 "http://example.com",
289 "ws://example.com/demo",
290 new TestURLRequestContext()));
291 TestCompletionCallback callback;
292 scoped_ptr<WebSocketEventRecorder> delegate(
293 new WebSocketEventRecorder(&callback));
294
295 scoped_refptr<WebSocket> websocket(
296 new WebSocket(request, delegate.get()));
297
298 static const char kTestUnterminatedFrame[] =
299 "\x00unterminated frame";
300 const int kTestUnterminatedFrameLength = sizeof(kTestUnterminatedFrame) - 1;
301 InitReadBuf(websocket.get());
302 AddToReadBuf(websocket.get(), kTestUnterminatedFrame,
303 kTestUnterminatedFrameLength);
304 SetReadConsumed(websocket.get(), 0);
305 TestProcessFrameData(websocket.get(),
306 kTestUnterminatedFrame, kTestUnterminatedFrameLength);
307 {
308 // No onmessage event expected.
309 const std::vector<WebSocketEvent>& events = delegate->GetSeenEvents();
310 EXPECT_EQ(0U, events.size());
311 }
312
313 static const char kTestTerminateFrame[] = " is terminated in next read\xff";
314 const int kTestTerminateFrameLength = sizeof(kTestTerminateFrame) - 1;
315 AddToReadBuf(websocket.get(), kTestTerminateFrame,
316 kTestTerminateFrameLength);
317 TestProcessFrameData(websocket.get(), "", 0);
318
319 static const char kExpectedMsg[] =
320 "unterminated frame is terminated in next read";
321 {
322 const std::vector<WebSocketEvent>& events = delegate->GetSeenEvents();
323 EXPECT_EQ(1U, events.size());
324
325 EXPECT_EQ(WebSocketEvent::EVENT_MESSAGE, events[0].event_type);
326 EXPECT_EQ(kExpectedMsg, events[0].msg);
327 }
[email protected]1ccf985c2009-11-06 10:11:01328
329 websocket->DetachDelegate();
[email protected]92aea482009-10-23 02:25:38330}
331
[email protected]06489a012009-12-10 08:12:54332TEST(WebSocketRequestTest, is_secure_false) {
333 WebSocket::Request request(GURL("ws://example.com/demo"),
334 "sample",
335 "http://example.com",
336 "ws://example.com/demo",
337 NULL);
338 EXPECT_FALSE(request.is_secure());
339}
340
341TEST(WebSocketRequestTest, is_secure_true) {
342 // wss:// is secure.
343 WebSocket::Request request(GURL("wss://example.com/demo"),
344 "sample",
345 "http://example.com",
346 "wss://example.com/demo",
347 NULL);
348 EXPECT_TRUE(request.is_secure());
349}
350
351TEST(WebSocketRequestTest, CreateClientHandshakeMessage_Simple) {
352 WebSocket::Request request(GURL("ws://example.com/demo"),
353 "sample",
354 "http://example.com",
355 "ws://example.com/demo",
356 NULL);
357 EXPECT_EQ("GET /demo HTTP/1.1\r\n"
358 "Upgrade: WebSocket\r\n"
359 "Connection: Upgrade\r\n"
360 "Host: example.com\r\n"
361 "Origin: http://example.com\r\n"
362 "WebSocket-Protocol: sample\r\n"
363 "\r\n",
364 request.CreateClientHandshakeMessage());
365}
366
367TEST(WebSocketRequestTest, CreateClientHandshakeMessage_PathAndQuery) {
368 WebSocket::Request request(GURL("ws://example.com/Test?q=xxx&p=%20"),
369 "sample",
370 "http://example.com",
371 "ws://example.com/demo",
372 NULL);
373 // Path and query should be preserved as-is.
374 EXPECT_THAT(request.CreateClientHandshakeMessage(),
375 testing::HasSubstr("GET /Test?q=xxx&p=%20 HTTP/1.1\r\n"));
376}
377
378TEST(WebSocketRequestTest, CreateClientHandshakeMessage_Host) {
379 WebSocket::Request request(GURL("ws://Example.Com/demo"),
380 "sample",
381 "http://Example.Com",
382 "ws://Example.Com/demo",
383 NULL);
384 // Host should be lowercased
385 EXPECT_THAT(request.CreateClientHandshakeMessage(),
386 testing::HasSubstr("Host: example.com\r\n"));
387 EXPECT_THAT(request.CreateClientHandshakeMessage(),
388 testing::HasSubstr("Origin: http://example.com\r\n"));
389}
390
391TEST(WebSocketRequestTest, CreateClientHandshakeMessage_TrimPort80) {
392 WebSocket::Request request(GURL("ws://example.com:80/demo"),
393 "sample",
394 "http://example.com",
395 "ws://example.com/demo",
396 NULL);
397 // :80 should be trimmed as it's the default port for ws://.
398 EXPECT_THAT(request.CreateClientHandshakeMessage(),
399 testing::HasSubstr("Host: example.com\r\n"));
400}
401
402TEST(WebSocketRequestTest, CreateClientHandshakeMessage_TrimPort443) {
403 WebSocket::Request request(GURL("wss://example.com:443/demo"),
404 "sample",
405 "http://example.com",
406 "wss://example.com/demo",
407 NULL);
408 // :443 should be trimmed as it's the default port for wss://.
409 EXPECT_THAT(request.CreateClientHandshakeMessage(),
410 testing::HasSubstr("Host: example.com\r\n"));
411}
412
413TEST(WebSocketRequestTest, CreateClientHandshakeMessage_NonDefaultPortForWs) {
414 WebSocket::Request request(GURL("ws://example.com:8080/demo"),
415 "sample",
416 "http://example.com",
417 "wss://example.com/demo",
418 NULL);
419 // :8080 should be preserved as it's not the default port for ws://.
420 EXPECT_THAT(request.CreateClientHandshakeMessage(),
421 testing::HasSubstr("Host: example.com:8080\r\n"));
422}
423
424TEST(WebSocketRequestTest, CreateClientHandshakeMessage_NonDefaultPortForWss) {
425 WebSocket::Request request(GURL("wss://example.com:4443/demo"),
426 "sample",
427 "http://example.com",
428 "wss://example.com/demo",
429 NULL);
430 // :4443 should be preserved as it's not the default port for wss://.
431 EXPECT_THAT(request.CreateClientHandshakeMessage(),
432 testing::HasSubstr("Host: example.com:4443\r\n"));
433}
434
435TEST(WebSocketRequestTest, CreateClientHandshakeMessage_WsBut443) {
436 WebSocket::Request request(GURL("ws://example.com:443/demo"),
437 "sample",
438 "http://example.com",
439 "ws://example.com/demo",
440 NULL);
441 // :443 should be preserved as it's not the default port for ws://.
442 EXPECT_THAT(request.CreateClientHandshakeMessage(),
443 testing::HasSubstr("Host: example.com:443\r\n"));
444}
445
446TEST(WebSocketRequestTest, CreateClientHandshakeMessage_WssBut80) {
447 WebSocket::Request request(GURL("wss://example.com:80/demo"),
448 "sample",
449 "http://example.com",
450 "wss://example.com/demo",
451 NULL);
452 // :80 should be preserved as it's not the default port for wss://.
453 EXPECT_THAT(request.CreateClientHandshakeMessage(),
454 testing::HasSubstr("Host: example.com:80\r\n"));
455}
456
[email protected]92aea482009-10-23 02:25:38457} // namespace net