Disable firewall check. It takes signifficant time, need to be on FILE thread.
[chromium-blink-merge.git] / components / navigation_interception / intercept_navigation_resource_throttle_unittest.cc
blobfd6f9daecbaa836c85cbc15b5886dc24d331ce69
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.
5 #include "base/bind.h"
6 #include "base/bind_helpers.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/run_loop.h"
9 #include "base/synchronization/waitable_event.h"
10 #include "components/navigation_interception/intercept_navigation_resource_throttle.h"
11 #include "components/navigation_interception/navigation_params.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/render_frame_host.h"
14 #include "content/public/browser/render_process_host.h"
15 #include "content/public/browser/resource_context.h"
16 #include "content/public/browser/resource_controller.h"
17 #include "content/public/browser/resource_dispatcher_host.h"
18 #include "content/public/browser/resource_dispatcher_host_delegate.h"
19 #include "content/public/browser/resource_request_info.h"
20 #include "content/public/browser/resource_throttle.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/browser/web_contents_delegate.h"
23 #include "content/public/common/page_transition_types.h"
24 #include "content/public/test/mock_resource_context.h"
25 #include "content/public/test/test_renderer_host.h"
26 #include "net/base/request_priority.h"
27 #include "net/http/http_response_headers.h"
28 #include "net/http/http_response_info.h"
29 #include "net/url_request/url_request.h"
30 #include "net/url_request/url_request_test_util.h"
31 #include "testing/gmock/include/gmock/gmock.h"
32 #include "testing/gtest/include/gtest/gtest.h"
34 using testing::_;
35 using testing::Eq;
36 using testing::Ne;
37 using testing::Property;
38 using testing::Return;
40 namespace navigation_interception {
42 namespace {
44 const char kTestUrl[] = "http://www.test.com/";
45 const char kUnsafeTestUrl[] = "about:crash";
47 // The MS C++ compiler complains about not being able to resolve which url()
48 // method (const or non-const) to use if we use the Property matcher to check
49 // the return value of the NavigationParams::url() method.
50 // It is possible to suppress the error by specifying the types directly but
51 // that results in very ugly syntax, which is why these custom matchers are
52 // used instead.
53 MATCHER(NavigationParamsUrlIsTest, "") {
54 return arg.url() == GURL(kTestUrl);
57 MATCHER(NavigationParamsUrlIsSafe, "") {
58 return arg.url() != GURL(kUnsafeTestUrl);
61 } // namespace
64 // MockInterceptCallbackReceiver ----------------------------------------------
66 class MockInterceptCallbackReceiver {
67 public:
68 MOCK_METHOD2(ShouldIgnoreNavigation,
69 bool(content::WebContents* source,
70 const NavigationParams& navigation_params));
73 // MockResourceController -----------------------------------------------------
74 class MockResourceController : public content::ResourceController {
75 public:
76 enum Status {
77 UNKNOWN,
78 RESUMED,
79 CANCELLED
82 MockResourceController()
83 : status_(UNKNOWN) {
86 Status status() const { return status_; }
88 // ResourceController:
89 virtual void Cancel() OVERRIDE {
90 NOTREACHED();
92 virtual void CancelAndIgnore() OVERRIDE {
93 status_ = CANCELLED;
95 virtual void CancelWithError(int error_code) OVERRIDE {
96 NOTREACHED();
98 virtual void Resume() OVERRIDE {
99 DCHECK(status_ == UNKNOWN);
100 status_ = RESUMED;
103 private:
104 Status status_;
107 // TestIOThreadState ----------------------------------------------------------
109 enum RedirectMode {
110 REDIRECT_MODE_NO_REDIRECT,
111 REDIRECT_MODE_302,
114 class TestIOThreadState {
115 public:
116 TestIOThreadState(const GURL& url,
117 int render_process_id,
118 int render_frame_id,
119 const std::string& request_method,
120 RedirectMode redirect_mode,
121 MockInterceptCallbackReceiver* callback_receiver)
122 : resource_context_(&test_url_request_context_),
123 request_(url,
124 net::DEFAULT_PRIORITY,
125 NULL,
126 resource_context_.GetRequestContext()) {
127 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
128 if (render_process_id != MSG_ROUTING_NONE &&
129 render_frame_id != MSG_ROUTING_NONE) {
130 content::ResourceRequestInfo::AllocateForTesting(
131 &request_,
132 ResourceType::MAIN_FRAME,
133 &resource_context_,
134 render_process_id,
135 MSG_ROUTING_NONE,
136 render_frame_id,
137 false);
139 throttle_.reset(new InterceptNavigationResourceThrottle(
140 &request_,
141 base::Bind(&MockInterceptCallbackReceiver::ShouldIgnoreNavigation,
142 base::Unretained(callback_receiver))));
143 throttle_->set_controller_for_testing(&throttle_controller_);
144 request_.set_method(request_method);
146 if (redirect_mode == REDIRECT_MODE_302) {
147 net::HttpResponseInfo& response_info =
148 const_cast<net::HttpResponseInfo&>(request_.response_info());
149 response_info.headers = new net::HttpResponseHeaders(
150 "Status: 302 Found\0\0");
154 void ThrottleWillStartRequest(bool* defer) {
155 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
156 throttle_->WillStartRequest(defer);
159 void ThrottleWillRedirectRequest(const GURL& new_url, bool* defer) {
160 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
161 throttle_->WillRedirectRequest(new_url, defer);
164 bool request_resumed() const {
165 return throttle_controller_.status() ==
166 MockResourceController::RESUMED;
169 bool request_cancelled() const {
170 return throttle_controller_.status() ==
171 MockResourceController::CANCELLED;
174 private:
175 net::TestURLRequestContext test_url_request_context_;
176 content::MockResourceContext resource_context_;
177 net::URLRequest request_;
178 scoped_ptr<InterceptNavigationResourceThrottle> throttle_;
179 MockResourceController throttle_controller_;
182 // InterceptNavigationResourceThrottleTest ------------------------------------
184 class InterceptNavigationResourceThrottleTest
185 : public content::RenderViewHostTestHarness {
186 public:
187 InterceptNavigationResourceThrottleTest()
188 : mock_callback_receiver_(new MockInterceptCallbackReceiver()),
189 io_thread_state_(NULL) {
192 virtual void SetUp() OVERRIDE {
193 RenderViewHostTestHarness::SetUp();
196 virtual void TearDown() OVERRIDE {
197 if (web_contents())
198 web_contents()->SetDelegate(NULL);
200 content::BrowserThread::DeleteSoon(
201 content::BrowserThread::IO, FROM_HERE, io_thread_state_);
203 RenderViewHostTestHarness::TearDown();
206 void SetIOThreadState(TestIOThreadState* io_thread_state) {
207 io_thread_state_ = io_thread_state;
210 void RunThrottleWillStartRequestOnIOThread(
211 const GURL& url,
212 const std::string& request_method,
213 RedirectMode redirect_mode,
214 int render_process_id,
215 int render_frame_id,
216 bool* defer) {
217 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
218 TestIOThreadState* io_thread_state =
219 new TestIOThreadState(url, render_process_id, render_frame_id,
220 request_method, redirect_mode,
221 mock_callback_receiver_.get());
223 SetIOThreadState(io_thread_state);
225 if (redirect_mode == REDIRECT_MODE_NO_REDIRECT)
226 io_thread_state->ThrottleWillStartRequest(defer);
227 else
228 io_thread_state->ThrottleWillRedirectRequest(url, defer);
231 protected:
232 enum ShouldIgnoreNavigationCallbackAction {
233 IgnoreNavigation,
234 DontIgnoreNavigation
237 void SetUpWebContentsDelegateAndDrainRunLoop(
238 ShouldIgnoreNavigationCallbackAction callback_action,
239 bool* defer) {
240 ON_CALL(*mock_callback_receiver_, ShouldIgnoreNavigation(_, _))
241 .WillByDefault(Return(callback_action == IgnoreNavigation));
242 EXPECT_CALL(*mock_callback_receiver_,
243 ShouldIgnoreNavigation(web_contents(),
244 NavigationParamsUrlIsTest()))
245 .Times(1);
247 content::BrowserThread::PostTask(
248 content::BrowserThread::IO,
249 FROM_HERE,
250 base::Bind(
251 &InterceptNavigationResourceThrottleTest::
252 RunThrottleWillStartRequestOnIOThread,
253 base::Unretained(this),
254 GURL(kTestUrl),
255 "GET",
256 REDIRECT_MODE_NO_REDIRECT,
257 web_contents()->GetRenderViewHost()->GetProcess()->GetID(),
258 web_contents()->GetMainFrame()->GetRoutingID(),
259 base::Unretained(defer)));
261 // Wait for the request to finish processing.
262 base::RunLoop().RunUntilIdle();
265 void WaitForPreviouslyScheduledIoThreadWork() {
266 base::WaitableEvent io_thread_work_done(true, false);
267 content::BrowserThread::PostTask(
268 content::BrowserThread::IO,
269 FROM_HERE,
270 base::Bind(
271 &base::WaitableEvent::Signal,
272 base::Unretained(&io_thread_work_done)));
273 io_thread_work_done.Wait();
276 scoped_ptr<MockInterceptCallbackReceiver> mock_callback_receiver_;
277 TestIOThreadState* io_thread_state_;
280 TEST_F(InterceptNavigationResourceThrottleTest,
281 RequestDeferredAndResumedIfNavigationNotIgnored) {
282 bool defer = false;
283 SetUpWebContentsDelegateAndDrainRunLoop(DontIgnoreNavigation, &defer);
285 EXPECT_TRUE(defer);
286 ASSERT_TRUE(io_thread_state_);
287 EXPECT_TRUE(io_thread_state_->request_resumed());
290 TEST_F(InterceptNavigationResourceThrottleTest,
291 RequestDeferredAndCancelledIfNavigationIgnored) {
292 bool defer = false;
293 SetUpWebContentsDelegateAndDrainRunLoop(IgnoreNavigation, &defer);
295 EXPECT_TRUE(defer);
296 ASSERT_TRUE(io_thread_state_);
297 EXPECT_TRUE(io_thread_state_->request_cancelled());
300 TEST_F(InterceptNavigationResourceThrottleTest,
301 NoCallbackMadeIfContentsDeletedWhileThrottleRunning) {
302 bool defer = false;
304 // The tested scenario is when the WebContents is deleted after the
305 // ResourceThrottle has finished processing on the IO thread but before the
306 // UI thread callback has been processed. Since both threads in this test
307 // are serviced by one message loop, the post order is the execution order.
308 EXPECT_CALL(*mock_callback_receiver_,
309 ShouldIgnoreNavigation(_, _))
310 .Times(0);
312 content::BrowserThread::PostTask(
313 content::BrowserThread::IO,
314 FROM_HERE,
315 base::Bind(
316 &InterceptNavigationResourceThrottleTest::
317 RunThrottleWillStartRequestOnIOThread,
318 base::Unretained(this),
319 GURL(kTestUrl),
320 "GET",
321 REDIRECT_MODE_NO_REDIRECT,
322 web_contents()->GetRenderViewHost()->GetProcess()->GetID(),
323 web_contents()->GetMainFrame()->GetRoutingID(),
324 base::Unretained(&defer)));
326 content::BrowserThread::PostTask(
327 content::BrowserThread::UI,
328 FROM_HERE,
329 base::Bind(
330 &RenderViewHostTestHarness::DeleteContents,
331 base::Unretained(this)));
333 // The WebContents will now be deleted and only after that will the UI-thread
334 // callback posted by the ResourceThrottle be executed.
335 base::RunLoop().RunUntilIdle();
337 EXPECT_TRUE(defer);
338 ASSERT_TRUE(io_thread_state_);
339 EXPECT_TRUE(io_thread_state_->request_resumed());
342 TEST_F(InterceptNavigationResourceThrottleTest,
343 RequestNotDeferredForRequestNotAssociatedWithARenderView) {
344 bool defer = false;
346 content::BrowserThread::PostTask(
347 content::BrowserThread::IO,
348 FROM_HERE,
349 base::Bind(
350 &InterceptNavigationResourceThrottleTest::
351 RunThrottleWillStartRequestOnIOThread,
352 base::Unretained(this),
353 GURL(kTestUrl),
354 "GET",
355 REDIRECT_MODE_NO_REDIRECT,
356 MSG_ROUTING_NONE,
357 MSG_ROUTING_NONE,
358 base::Unretained(&defer)));
360 // Wait for the request to finish processing.
361 base::RunLoop().RunUntilIdle();
363 EXPECT_FALSE(defer);
366 TEST_F(InterceptNavigationResourceThrottleTest,
367 CallbackCalledWithFilteredUrl) {
368 bool defer = false;
370 ON_CALL(*mock_callback_receiver_,
371 ShouldIgnoreNavigation(_, NavigationParamsUrlIsSafe()))
372 .WillByDefault(Return(false));
373 EXPECT_CALL(*mock_callback_receiver_,
374 ShouldIgnoreNavigation(_, NavigationParamsUrlIsSafe()))
375 .Times(1);
377 content::BrowserThread::PostTask(
378 content::BrowserThread::IO,
379 FROM_HERE,
380 base::Bind(
381 &InterceptNavigationResourceThrottleTest::
382 RunThrottleWillStartRequestOnIOThread,
383 base::Unretained(this),
384 GURL(kUnsafeTestUrl),
385 "GET",
386 REDIRECT_MODE_NO_REDIRECT,
387 web_contents()->GetRenderViewHost()->GetProcess()->GetID(),
388 web_contents()->GetMainFrame()->GetRoutingID(),
389 base::Unretained(&defer)));
391 // Wait for the request to finish processing.
392 base::RunLoop().RunUntilIdle();
395 TEST_F(InterceptNavigationResourceThrottleTest,
396 CallbackIsPostFalseForGet) {
397 bool defer = false;
399 EXPECT_CALL(*mock_callback_receiver_,
400 ShouldIgnoreNavigation(_, AllOf(
401 NavigationParamsUrlIsSafe(),
402 Property(&NavigationParams::is_post, Eq(false)))))
403 .WillOnce(Return(false));
405 content::BrowserThread::PostTask(
406 content::BrowserThread::IO,
407 FROM_HERE,
408 base::Bind(
409 &InterceptNavigationResourceThrottleTest::
410 RunThrottleWillStartRequestOnIOThread,
411 base::Unretained(this),
412 GURL(kTestUrl),
413 "GET",
414 REDIRECT_MODE_NO_REDIRECT,
415 web_contents()->GetRenderViewHost()->GetProcess()->GetID(),
416 web_contents()->GetMainFrame()->GetRoutingID(),
417 base::Unretained(&defer)));
419 // Wait for the request to finish processing.
420 base::RunLoop().RunUntilIdle();
423 TEST_F(InterceptNavigationResourceThrottleTest,
424 CallbackIsPostTrueForPost) {
425 bool defer = false;
427 EXPECT_CALL(*mock_callback_receiver_,
428 ShouldIgnoreNavigation(_, AllOf(
429 NavigationParamsUrlIsSafe(),
430 Property(&NavigationParams::is_post, Eq(true)))))
431 .WillOnce(Return(false));
433 content::BrowserThread::PostTask(
434 content::BrowserThread::IO,
435 FROM_HERE,
436 base::Bind(
437 &InterceptNavigationResourceThrottleTest::
438 RunThrottleWillStartRequestOnIOThread,
439 base::Unretained(this),
440 GURL(kTestUrl),
441 "POST",
442 REDIRECT_MODE_NO_REDIRECT,
443 web_contents()->GetRenderViewHost()->GetProcess()->GetID(),
444 web_contents()->GetMainFrame()->GetRoutingID(),
445 base::Unretained(&defer)));
447 // Wait for the request to finish processing.
448 base::RunLoop().RunUntilIdle();
451 TEST_F(InterceptNavigationResourceThrottleTest,
452 CallbackIsPostFalseForPostConvertedToGetBy302) {
453 bool defer = false;
455 EXPECT_CALL(*mock_callback_receiver_,
456 ShouldIgnoreNavigation(_, AllOf(
457 NavigationParamsUrlIsSafe(),
458 Property(&NavigationParams::is_post, Eq(false)))))
459 .WillOnce(Return(false));
461 content::BrowserThread::PostTask(
462 content::BrowserThread::IO,
463 FROM_HERE,
464 base::Bind(
465 &InterceptNavigationResourceThrottleTest::
466 RunThrottleWillStartRequestOnIOThread,
467 base::Unretained(this),
468 GURL(kTestUrl),
469 "POST",
470 REDIRECT_MODE_302,
471 web_contents()->GetRenderViewHost()->GetProcess()->GetID(),
472 web_contents()->GetMainFrame()->GetRoutingID(),
473 base::Unretained(&defer)));
475 // Wait for the request to finish processing.
476 base::RunLoop().RunUntilIdle();
479 } // namespace navigation_interception