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 |