Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Side by Side Diff: content/browser/renderer_host/websocket_dispatcher_host_unittest.cc

Issue 2119973002: Port WebSockets to Mojo IPC (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix compile error Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2013 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 "content/browser/renderer_host/websocket_dispatcher_host.h"
6
7 #include <algorithm>
8 #include <vector>
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/message_loop.h"
15 #include "content/browser/renderer_host/websocket_host.h"
16 #include "content/common/websocket.h"
17 #include "content/common/websocket_messages.h"
18 #include "ipc/ipc_message.h"
19 #include "net/websockets/websocket_errors.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "url/gurl.h"
22 #include "url/origin.h"
23
24 namespace content {
25 namespace {
26
27 // This number is unlikely to occur by chance.
28 static const int kMagicRenderProcessId = 506116062;
29
30 class WebSocketDispatcherHostTest;
31
32 // A mock of WebsocketHost which records received messages.
33 class MockWebSocketHost : public WebSocketHost {
34 public:
35 MockWebSocketHost(int routing_id,
36 WebSocketDispatcherHost* dispatcher,
37 net::URLRequestContext* url_request_context,
38 base::TimeDelta delay,
39 WebSocketDispatcherHostTest* owner);
40
41 ~MockWebSocketHost() override {}
42
43 bool OnMessageReceived(const IPC::Message& message) override {
44 received_messages_.push_back(message);
45 switch (message.type()) {
46 case WebSocketMsg_DropChannel::ID:
47 // Needed for PerRendererThrottlingFailedHandshakes, because without
48 // calling WebSocketHost::OnMessageReceived() (and thus
49 // WebSocketHost::OnDropChannel()), the connection stays pending and
50 // we cannot test per-renderer throttling with failed connections.
51 return WebSocketHost::OnMessageReceived(message);
52
53 default:
54 return true;
55 }
56 }
57
58 void GoAway() override;
59
60 std::vector<IPC::Message> received_messages_;
61 base::WeakPtr<WebSocketDispatcherHostTest> owner_;
62 base::TimeDelta delay_;
63 };
64
65 class TestingWebSocketDispatcherHost : public WebSocketDispatcherHost {
66 public:
67 TestingWebSocketDispatcherHost(
68 int process_id,
69 const GetRequestContextCallback& get_context_callback,
70 const WebSocketHostFactory& websocket_host_factory)
71 : WebSocketDispatcherHost(process_id,
72 get_context_callback,
73 websocket_host_factory) {}
74
75 // This is needed because BrowserMessageFilter::Send() tries post the task to
76 // the IO thread, which doesn't exist in the context of these tests.
77 bool Send(IPC::Message* message) override {
78 delete message;
79 return true;
80 }
81
82 using WebSocketDispatcherHost::num_pending_connections;
83 using WebSocketDispatcherHost::num_failed_connections;
84 using WebSocketDispatcherHost::num_succeeded_connections;
85
86 private:
87 ~TestingWebSocketDispatcherHost() override {}
88 };
89
90 class WebSocketDispatcherHostTest : public ::testing::Test {
91 public:
92 WebSocketDispatcherHostTest()
93 : next_routing_id_(123),
94 weak_ptr_factory_(this) {
95 dispatcher_host_ = new TestingWebSocketDispatcherHost(
96 kMagicRenderProcessId,
97 base::Bind(&WebSocketDispatcherHostTest::OnGetRequestContext,
98 base::Unretained(this)),
99 base::Bind(&WebSocketDispatcherHostTest::CreateWebSocketHost,
100 base::Unretained(this)));
101 }
102
103 ~WebSocketDispatcherHostTest() override {
104 // We need to invalidate the issued WeakPtrs at the beginning of the
105 // destructor in order not to access destructed member variables.
106 weak_ptr_factory_.InvalidateWeakPtrs();
107 }
108
109 void GoAway(int routing_id) {
110 gone_hosts_.push_back(routing_id);
111 }
112
113 base::WeakPtr<WebSocketDispatcherHostTest> GetWeakPtr() {
114 return weak_ptr_factory_.GetWeakPtr();
115 }
116
117 protected:
118 // Adds |n| connections. Returns true if succeeded.
119 bool AddMultipleChannels(int number_of_channels) {
120 for (int i = 0; i < number_of_channels; ++i) {
121 int routing_id = next_routing_id_++;
122
123 WebSocketHostMsg_AddChannelRequest_Params params;
124 params.socket_url = GURL("ws://example.com/test");
125 params.origin = url::Origin(GURL("http://example.com"));
126 params.first_party_for_cookies = GURL("http://example.com");
127 params.user_agent_override = "";
128 params.render_frame_id = -3;
129
130 WebSocketHostMsg_AddChannelRequest message(routing_id, params);
131 if (!dispatcher_host_->OnMessageReceived(message))
132 return false;
133 }
134
135 return true;
136 }
137
138 // Adds and cancels |n| connections. Returns true if succeeded.
139 bool AddAndCancelMultipleChannels(int number_of_channels) {
140 for (int i = 0; i < number_of_channels; ++i) {
141 int routing_id = next_routing_id_++;
142
143 WebSocketHostMsg_AddChannelRequest_Params params;
144 params.socket_url = GURL("ws://example.com/test");
145 params.origin = url::Origin(GURL("http://example.com"));
146 params.first_party_for_cookies = GURL("http://example.com");
147 params.user_agent_override = "";
148 params.render_frame_id = -3;
149
150 WebSocketHostMsg_AddChannelRequest messageAddChannelRequest(
151 routing_id, params);
152 if (!dispatcher_host_->OnMessageReceived(messageAddChannelRequest))
153 return false;
154
155 WebSocketMsg_DropChannel messageDropChannel(
156 routing_id, false, net::kWebSocketErrorAbnormalClosure, "");
157 if (!dispatcher_host_->OnMessageReceived(messageDropChannel))
158 return false;
159 }
160
161 return true;
162 }
163
164 scoped_refptr<TestingWebSocketDispatcherHost> dispatcher_host_;
165
166 // Stores allocated MockWebSocketHost instances. Doesn't take ownership of
167 // them.
168 std::vector<MockWebSocketHost*> mock_hosts_;
169 std::vector<int> gone_hosts_;
170
171 private:
172 net::URLRequestContext* OnGetRequestContext() {
173 return NULL;
174 }
175
176 WebSocketHost* CreateWebSocketHost(int routing_id, base::TimeDelta delay) {
177 MockWebSocketHost* host = new MockWebSocketHost(
178 routing_id, dispatcher_host_.get(), NULL, delay, this);
179 mock_hosts_.push_back(host);
180 return host;
181 }
182
183 base::MessageLoop message_loop_;
184
185 int next_routing_id_;
186
187 base::WeakPtrFactory<WebSocketDispatcherHostTest> weak_ptr_factory_;
188 };
189
190 MockWebSocketHost::MockWebSocketHost(
191 int routing_id,
192 WebSocketDispatcherHost* dispatcher,
193 net::URLRequestContext* url_request_context,
194 base::TimeDelta delay,
195 WebSocketDispatcherHostTest* owner)
196 : WebSocketHost(routing_id, dispatcher, url_request_context, delay),
197 owner_(owner->GetWeakPtr()),
198 delay_(delay) {}
199
200 void MockWebSocketHost::GoAway() {
201 if (owner_)
202 owner_->GoAway(routing_id());
203 }
204
205 TEST_F(WebSocketDispatcherHostTest, Construct) {
206 // Do nothing.
207 }
208
209 TEST_F(WebSocketDispatcherHostTest, UnrelatedMessage) {
210 IPC::Message message;
211 EXPECT_FALSE(dispatcher_host_->OnMessageReceived(message));
212 }
213
214 TEST_F(WebSocketDispatcherHostTest, RenderProcessIdGetter) {
215 EXPECT_EQ(kMagicRenderProcessId, dispatcher_host_->render_process_id());
216 }
217
218 TEST_F(WebSocketDispatcherHostTest, AddChannelRequest) {
219 int routing_id = 123;
220 std::vector<std::string> requested_protocols;
221 requested_protocols.push_back("hello");
222
223 WebSocketHostMsg_AddChannelRequest_Params params;
224 params.socket_url = GURL("ws://example.com/test");
225 params.requested_protocols = requested_protocols;
226 params.origin = url::Origin(GURL("http://example.com"));
227 params.first_party_for_cookies = GURL("http://example.com");
228 params.user_agent_override = "";
229 params.render_frame_id = -2;
230
231 WebSocketHostMsg_AddChannelRequest message(routing_id, params);
232
233 ASSERT_TRUE(dispatcher_host_->OnMessageReceived(message));
234
235 ASSERT_EQ(1U, mock_hosts_.size());
236 MockWebSocketHost* host = mock_hosts_[0];
237
238 ASSERT_EQ(1U, host->received_messages_.size());
239 const IPC::Message& forwarded_message = host->received_messages_[0];
240 EXPECT_EQ(WebSocketHostMsg_AddChannelRequest::ID, forwarded_message.type());
241 EXPECT_EQ(routing_id, forwarded_message.routing_id());
242 }
243
244 TEST_F(WebSocketDispatcherHostTest, SendFrameButNoHostYet) {
245 int routing_id = 123;
246 std::vector<char> data;
247 WebSocketMsg_SendFrame message(
248 routing_id, true, WEB_SOCKET_MESSAGE_TYPE_TEXT, data);
249
250 // Expected to be ignored.
251 EXPECT_TRUE(dispatcher_host_->OnMessageReceived(message));
252
253 EXPECT_EQ(0U, mock_hosts_.size());
254 }
255
256 TEST_F(WebSocketDispatcherHostTest, SendFrame) {
257 int routing_id = 123;
258
259 std::vector<std::string> requested_protocols;
260 requested_protocols.push_back("hello");
261
262 WebSocketHostMsg_AddChannelRequest_Params params;
263 params.socket_url = GURL("ws://example.com/test");
264 params.requested_protocols = requested_protocols;
265 params.origin = url::Origin(GURL("http://example.com"));
266 params.first_party_for_cookies = GURL("http://example.com");
267 params.user_agent_override = "";
268 params.render_frame_id = -2;
269
270 WebSocketHostMsg_AddChannelRequest add_channel_message(routing_id, params);
271
272 ASSERT_TRUE(dispatcher_host_->OnMessageReceived(add_channel_message));
273
274 std::vector<char> data;
275 WebSocketMsg_SendFrame send_frame_message(
276 routing_id, true, WEB_SOCKET_MESSAGE_TYPE_TEXT, data);
277
278 EXPECT_TRUE(dispatcher_host_->OnMessageReceived(send_frame_message));
279
280 ASSERT_EQ(1U, mock_hosts_.size());
281 MockWebSocketHost* host = mock_hosts_[0];
282
283 ASSERT_EQ(2U, host->received_messages_.size());
284 {
285 const IPC::Message& forwarded_message = host->received_messages_[0];
286 EXPECT_EQ(WebSocketHostMsg_AddChannelRequest::ID, forwarded_message.type());
287 EXPECT_EQ(routing_id, forwarded_message.routing_id());
288 }
289 {
290 const IPC::Message& forwarded_message = host->received_messages_[1];
291 EXPECT_EQ(WebSocketMsg_SendFrame::ID, forwarded_message.type());
292 EXPECT_EQ(routing_id, forwarded_message.routing_id());
293 }
294 }
295
296 TEST_F(WebSocketDispatcherHostTest, Destruct) {
297 WebSocketHostMsg_AddChannelRequest_Params params1;
298 params1.socket_url = GURL("ws://example.com/test");
299 params1.requested_protocols = std::vector<std::string>();
300 params1.origin = url::Origin(GURL("http://example.com"));
301 params1.first_party_for_cookies = GURL("http://example.com");
302 params1.user_agent_override = "";
303 params1.render_frame_id = -1;
304
305 WebSocketHostMsg_AddChannelRequest message1(123, params1);
306
307 WebSocketHostMsg_AddChannelRequest_Params params2;
308 params2.socket_url = GURL("ws://example.com/test2");
309 params2.requested_protocols = std::vector<std::string>();
310 params2.origin = url::Origin(GURL("http://example.com"));
311 params2.first_party_for_cookies = GURL("http://example.com");
312 params2.user_agent_override = "";
313 params2.render_frame_id = -1;
314
315 WebSocketHostMsg_AddChannelRequest message2(456, params2);
316
317 ASSERT_TRUE(dispatcher_host_->OnMessageReceived(message1));
318 ASSERT_TRUE(dispatcher_host_->OnMessageReceived(message2));
319
320 ASSERT_EQ(2u, mock_hosts_.size());
321
322 mock_hosts_.clear();
323 dispatcher_host_ = NULL;
324
325 ASSERT_EQ(2u, gone_hosts_.size());
326 // The gone_hosts_ ordering is not predictable because it depends on the
327 // hash_map ordering.
328 std::sort(gone_hosts_.begin(), gone_hosts_.end());
329 EXPECT_EQ(123, gone_hosts_[0]);
330 EXPECT_EQ(456, gone_hosts_[1]);
331 }
332
333 TEST_F(WebSocketDispatcherHostTest, DelayFor4thPendingConnectionIsZero) {
334 ASSERT_TRUE(AddMultipleChannels(4));
335
336 EXPECT_EQ(4, dispatcher_host_->num_pending_connections());
337 EXPECT_EQ(0, dispatcher_host_->num_failed_connections());
338 EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections());
339
340 ASSERT_EQ(4U, mock_hosts_.size());
341 EXPECT_EQ(base::TimeDelta(), mock_hosts_[3]->delay_);
342 }
343
344 TEST_F(WebSocketDispatcherHostTest, DelayFor8thPendingConnectionIsNonZero) {
345 ASSERT_TRUE(AddMultipleChannels(8));
346
347 EXPECT_EQ(8, dispatcher_host_->num_pending_connections());
348 EXPECT_EQ(0, dispatcher_host_->num_failed_connections());
349 EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections());
350
351 ASSERT_EQ(8U, mock_hosts_.size());
352 EXPECT_LT(base::TimeDelta(), mock_hosts_[7]->delay_);
353 }
354
355 TEST_F(WebSocketDispatcherHostTest, DelayFor17thPendingConnection) {
356 ASSERT_TRUE(AddMultipleChannels(17));
357
358 EXPECT_EQ(17, dispatcher_host_->num_pending_connections());
359 EXPECT_EQ(0, dispatcher_host_->num_failed_connections());
360 EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections());
361
362 ASSERT_EQ(17U, mock_hosts_.size());
363 EXPECT_LE(base::TimeDelta::FromMilliseconds(1000), mock_hosts_[16]->delay_);
364 EXPECT_GE(base::TimeDelta::FromMilliseconds(5000), mock_hosts_[16]->delay_);
365 }
366
367 // The 256th connection is rejected by per-renderer WebSocket throttling.
368 // This is not counted as a failure.
369 TEST_F(WebSocketDispatcherHostTest, Rejects256thPendingConnection) {
370 ASSERT_TRUE(AddMultipleChannels(256));
371
372 EXPECT_EQ(255, dispatcher_host_->num_pending_connections());
373 EXPECT_EQ(0, dispatcher_host_->num_failed_connections());
374 EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections());
375
376 ASSERT_EQ(255U, mock_hosts_.size());
377 }
378
379 TEST_F(WebSocketDispatcherHostTest, DelayIsZeroAfter3FailedConnections) {
380 ASSERT_TRUE(AddAndCancelMultipleChannels(3));
381
382 EXPECT_EQ(0, dispatcher_host_->num_pending_connections());
383 EXPECT_EQ(3, dispatcher_host_->num_failed_connections());
384 EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections());
385
386 ASSERT_TRUE(AddMultipleChannels(1));
387
388 ASSERT_EQ(4U, mock_hosts_.size());
389 EXPECT_EQ(base::TimeDelta(), mock_hosts_[3]->delay_);
390 }
391
392 TEST_F(WebSocketDispatcherHostTest, DelayIsNonZeroAfter7FailedConnections) {
393 ASSERT_TRUE(AddAndCancelMultipleChannels(7));
394
395 EXPECT_EQ(0, dispatcher_host_->num_pending_connections());
396 EXPECT_EQ(7, dispatcher_host_->num_failed_connections());
397 EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections());
398
399 ASSERT_TRUE(AddMultipleChannels(1));
400
401 ASSERT_EQ(8U, mock_hosts_.size());
402 EXPECT_LT(base::TimeDelta(), mock_hosts_[7]->delay_);
403 }
404
405 TEST_F(WebSocketDispatcherHostTest, DelayAfter16FailedConnections) {
406 ASSERT_TRUE(AddAndCancelMultipleChannels(16));
407
408 EXPECT_EQ(0, dispatcher_host_->num_pending_connections());
409 EXPECT_EQ(16, dispatcher_host_->num_failed_connections());
410 EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections());
411
412 ASSERT_TRUE(AddMultipleChannels(1));
413
414 ASSERT_EQ(17U, mock_hosts_.size());
415 EXPECT_LE(base::TimeDelta::FromMilliseconds(1000), mock_hosts_[16]->delay_);
416 EXPECT_GE(base::TimeDelta::FromMilliseconds(5000), mock_hosts_[16]->delay_);
417 }
418
419 TEST_F(WebSocketDispatcherHostTest, NotRejectedAfter255FailedConnections) {
420 ASSERT_TRUE(AddAndCancelMultipleChannels(255));
421
422 EXPECT_EQ(0, dispatcher_host_->num_pending_connections());
423 EXPECT_EQ(255, dispatcher_host_->num_failed_connections());
424 EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections());
425
426 ASSERT_TRUE(AddMultipleChannels(1));
427
428 EXPECT_EQ(1, dispatcher_host_->num_pending_connections());
429 EXPECT_EQ(255, dispatcher_host_->num_failed_connections());
430 EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections());
431 }
432
433 // This is a regression test for https://crrev.com/998173003/.
434 TEST_F(WebSocketDispatcherHostTest, InvalidScheme) {
435 int routing_id = 123;
436
437 std::vector<std::string> requested_protocols;
438 requested_protocols.push_back("hello");
439
440 WebSocketHostMsg_AddChannelRequest_Params params;
441 params.socket_url = GURL("http://example.com/test");
442 params.requested_protocols = requested_protocols;
443 params.origin = url::Origin(GURL("http://example.com"));
444 params.first_party_for_cookies = GURL("http://example.com");
445 params.user_agent_override = "";
446 params.render_frame_id = -2;
447
448 WebSocketHostMsg_AddChannelRequest message(routing_id, params);
449
450 ASSERT_TRUE(dispatcher_host_->OnMessageReceived(message));
451
452 ASSERT_EQ(1U, mock_hosts_.size());
453 MockWebSocketHost* host = mock_hosts_[0];
454
455 // Tests that WebSocketHost::OnMessageReceived() doesn't cause a crash and
456 // the connection with an invalid scheme fails here.
457 // We call WebSocketHost::OnMessageReceived() here explicitly because
458 // MockWebSocketHost does not call WebSocketHost::OnMessageReceived() for
459 // WebSocketHostMsg_AddChannelRequest.
460 host->WebSocketHost::OnMessageReceived(message);
461
462 EXPECT_EQ(0, dispatcher_host_->num_pending_connections());
463 EXPECT_EQ(1, dispatcher_host_->num_failed_connections());
464 EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections());
465 }
466
467 } // namespace
468 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698