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

Side by Side Diff: content/browser/loader/navigation_url_loader_unittest.cc

Issue 648813002: PlzNavigate: Add first version of NavigationURLLoader. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@plz-navigate-prepare
Patch Set: nasko and mmenke comments Created 6 years, 1 month 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 2014 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 "base/command_line.h"
6 #include "base/memory/ref_counted.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/run_loop.h"
9 #include "content/browser/frame_host/navigation_request_info.h"
10 #include "content/browser/loader/navigation_url_loader_delegate.h"
11 #include "content/browser/loader/navigation_url_loader_impl.h"
12 #include "content/browser/loader/resource_dispatcher_host_impl.h"
13 #include "content/browser/streams/stream.h"
14 #include "content/browser/streams/stream_context.h"
15 #include "content/browser/streams/stream_registry.h"
16 #include "content/browser/streams/stream_url_request_job.h"
17 #include "content/common/navigation_params.h"
18 #include "content/public/browser/browser_context.h"
19 #include "content/public/browser/resource_context.h"
20 #include "content/public/browser/resource_dispatcher_host_delegate.h"
21 #include "content/public/browser/stream_handle.h"
22 #include "content/public/common/content_switches.h"
23 #include "content/public/common/resource_response.h"
24 #include "content/public/test/test_browser_context.h"
25 #include "content/public/test/test_browser_thread_bundle.h"
26 #include "net/base/net_errors.h"
27 #include "net/http/http_response_headers.h"
28 #include "net/url_request/redirect_info.h"
29 #include "net/url_request/url_request.h"
30 #include "net/url_request/url_request_context.h"
31 #include "net/url_request/url_request_job_factory_impl.h"
32 #include "net/url_request/url_request_test_job.h"
33 #include "net/url_request/url_request_test_util.h"
34 #include "testing/gtest/include/gtest/gtest.h"
35
36 namespace content {
37
38 namespace {
39
40 class StreamProtocolHandler
41 : public net::URLRequestJobFactory::ProtocolHandler {
42 public:
43 StreamProtocolHandler(StreamRegistry* registry) : registry_(registry) {}
44
45 // net::URLRequestJobFactory::ProtocolHandler implementation.
46 net::URLRequestJob* MaybeCreateJob(
47 net::URLRequest* request,
48 net::NetworkDelegate* network_delegate) const override {
49 scoped_refptr<Stream> stream = registry_->GetStream(request->url());
50 if (stream.get())
51 return new StreamURLRequestJob(request, network_delegate, stream);
52 return nullptr;
53 }
54 private:
mmenke 2014/10/28 16:05:39 nit: Linbreak before private
davidben 2014/10/29 19:10:34 Done.
55 StreamRegistry* registry_;
mmenke 2014/10/28 16:05:39 DISALLOW_COPY_AND_ASSIGN?
davidben 2014/10/29 19:10:34 Done.
56 };
57
58 class TestNavigationURLLoaderDelegate : public NavigationURLLoaderDelegate {
59 public:
60 TestNavigationURLLoaderDelegate()
61 : net_error_(0),
62 request_redirected_(new base::RunLoop),
63 response_started_(new base::RunLoop),
64 request_failed_(new base::RunLoop) {
65 }
66
67 const net::RedirectInfo& redirect_info() const { return redirect_info_; }
68 ResourceResponse* response() const { return response_.get(); }
69 StreamHandle* body() const { return body_.get(); }
70 int net_error() const { return net_error_; }
71
72 void WaitForRequestRedirected() {
73 request_redirected_->Run();
74 request_redirected_.reset(new base::RunLoop);
75 }
76
77 void WaitForResponseStarted() {
78 response_started_->Run();
79 response_started_.reset(new base::RunLoop);
80 }
81
82 void WaitForRequestFailed() {
83 request_failed_->Run();
84 request_failed_.reset(new base::RunLoop);
85 }
86
87 void ReleaseBody() {
88 body_.reset();
89 }
90
91 // NavigationURLLoaderDelegate implementation.
92 void OnRequestRedirected(const net::RedirectInfo& redirect_info,
93 ResourceResponse* response) override {
94 redirect_info_ = redirect_info;
95 response_ = response;
96 request_redirected_->Quit();
97 }
98
99 void OnResponseStarted(ResourceResponse* response,
100 scoped_ptr<StreamHandle> body) override {
101 response_ = response;
102 body_ = body.Pass();
103 response_started_->Quit();
104 }
105
106 void OnRequestFailed(int net_error) override {
107 net_error_ = net_error;
108 request_failed_->Quit();
109 }
110
111 private:
112 net::RedirectInfo redirect_info_;
113 scoped_refptr<ResourceResponse> response_;
114 scoped_ptr<StreamHandle> body_;
115 int net_error_;
116
117 scoped_ptr<base::RunLoop> request_redirected_;
118 scoped_ptr<base::RunLoop> response_started_;
119 scoped_ptr<base::RunLoop> request_failed_;
120 };
121
122 class RequestBlockingResourceDispatcherHostDelegate
123 : public ResourceDispatcherHostDelegate {
124 public:
125 // ResourceDispatcherHostDelegate implementation:
126 bool ShouldBeginRequest(const std::string& method,
127 const GURL& url,
128 ResourceType resource_type,
129 ResourceContext* resource_context) override {
mmenke 2014/10/28 16:05:39 NOTREACHED()?
davidben 2014/10/29 19:10:34 That's supposed to be reached. It's part of a test
mmenke 2014/10/29 19:44:46 Ah, right...was forgetting these requests still go
130 return false;
131 }
132 };
133
134 } // namespace
135
136 class NavigationURLLoaderTest : public testing::Test {
137 public:
138 NavigationURLLoaderTest()
139 : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
140 browser_context_(new TestBrowserContext) {
141 BrowserContext::EnsureResourceContextInitialized(browser_context_.get());
142 base::RunLoop().RunUntilIdle();
143 net::URLRequestContext* request_context =
144 browser_context_->GetResourceContext()->GetRequestContext();
145 // Attach URLRequestTestJob and make streams work.
146 job_factory_.SetProtocolHandler(
147 "test", net::URLRequestTestJob::CreateProtocolHandler());
148 job_factory_.SetProtocolHandler(
149 "blob", new StreamProtocolHandler(
150 StreamContext::GetFor(browser_context_.get())->registry()));
151 request_context->set_job_factory(&job_factory_);
152
153 // NavigationURLLoader is only used for browser-side navigations.
154 CommandLine::ForCurrentProcess()->AppendSwitch(
155 switches::kEnableBrowserSideNavigation);
156 }
157
158 scoped_ptr<NavigationURLLoader> MakeTestLoader(
159 const GURL& url,
160 NavigationURLLoaderDelegate* delegate) {
161 FrameHostMsg_BeginNavigation_Params begin_params;
162 CommonNavigationParams common_params;
163 begin_params.method = "GET";
164 common_params.url = url;
165 scoped_ptr<NavigationRequestInfo> request_info(
166 new NavigationRequestInfo(begin_params));
167 request_info->first_party_for_cookies = url;
168 request_info->is_main_frame = true;
169
170 return NavigationURLLoader::Create(
171 browser_context_.get(), 0,
172 common_params, request_info.Pass(), nullptr, delegate);
173 }
174
175 // Helper function for fetching the body of a URL to a string.
176 std::string FetchURL(const GURL& url) {
177 net::TestDelegate delegate;
178 net::URLRequestContext* request_context =
179 browser_context_->GetResourceContext()->GetRequestContext();
180 scoped_ptr<net::URLRequest> request(request_context->CreateRequest(
181 url, net::DEFAULT_PRIORITY, &delegate, nullptr));
182 request->Start();
183 base::RunLoop().Run();
184
185 EXPECT_TRUE(request->status().is_success());
186 EXPECT_EQ(200, request->response_headers()->response_code());
187 return delegate.data_received();
188 }
189
190 protected:
191 TestBrowserThreadBundle thread_bundle_;
192 net::URLRequestJobFactoryImpl job_factory_;
193 scoped_ptr<TestBrowserContext> browser_context_;
194 ResourceDispatcherHostImpl host_;
195 };
196
197 // Tests that a basic request works.
198 TEST_F(NavigationURLLoaderTest, Basic) {
199 TestNavigationURLLoaderDelegate delegate;
200 scoped_ptr<NavigationURLLoader> loader =
201 MakeTestLoader(net::URLRequestTestJob::test_url_1(), &delegate);
202
203 // Wait for the response to come back.
204 delegate.WaitForResponseStarted();
205
206 // Check the response is correct.
207 EXPECT_EQ("text/html", delegate.response()->head.mime_type);
208 EXPECT_EQ("HTTP/1.1 200 OK",
209 delegate.response()->head.headers->GetStatusLine());
210
211 // Check the body is correct.
212 EXPECT_EQ(net::URLRequestTestJob::test_data_1(),
213 FetchURL(delegate.body()->GetURL()));
mmenke 2014/10/28 16:05:39 Should we make sure only the expected callback is
davidben 2014/10/29 19:10:34 Done. Also split up the responses.
214 }
215
216 // Tests that request failures are propagated correctly.
217 TEST_F(NavigationURLLoaderTest, RequestFailed) {
218 TestNavigationURLLoaderDelegate delegate;
219 scoped_ptr<NavigationURLLoader> loader =
220 MakeTestLoader(GURL("bogus:bogus"), &delegate);
221
222 // Wait for the request to fail as expected.
223 delegate.WaitForRequestFailed();
224 EXPECT_EQ(net::ERR_UNKNOWN_URL_SCHEME, delegate.net_error());
225 }
226
227 // Test that redirects are sent to the delegate.
228 TEST_F(NavigationURLLoaderTest, RequestRedirected) {
229 // Fake a top-level request. Choose a URL which redirects so the request can
230 // be paused before the response comes in.
231 TestNavigationURLLoaderDelegate delegate;
232 scoped_ptr<NavigationURLLoader> loader =
233 MakeTestLoader(net::URLRequestTestJob::test_url_redirect_to_url_2(),
234 &delegate);
235
236 // Wait for the request to redirect.
237 delegate.WaitForRequestRedirected();
238 EXPECT_EQ(net::URLRequestTestJob::test_url_2(),
239 delegate.redirect_info().new_url);
240 EXPECT_EQ("GET", delegate.redirect_info().new_method);
241 EXPECT_EQ(net::URLRequestTestJob::test_url_2(),
242 delegate.redirect_info().new_first_party_for_cookies);
243 EXPECT_EQ("HTTP/1.1 302 MOVED",
mmenke 2014/10/28 16:05:39 Could we just check the response_code instead? Re
davidben 2014/10/29 19:10:34 Done.
244 delegate.response()->head.headers->GetStatusLine());
245
246 // Wait for the response to complete.
247 loader->FollowRedirect();
248 base::RunLoop().RunUntilIdle();
249 EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage());
mmenke 2014/10/28 16:05:39 What does ProcessOnePendingMessage actually do? I
davidben 2014/10/29 19:10:34 Yeah, URLRequestTestJob's documentation is terribl
250 delegate.WaitForResponseStarted();
251
252 // Check the response is correct.
253 EXPECT_EQ("text/html", delegate.response()->head.mime_type);
254 EXPECT_EQ("HTTP/1.1 200 OK",
255 delegate.response()->head.headers->GetStatusLine());
256
257 // Check the body is correct.
258 EXPECT_EQ(net::URLRequestTestJob::test_data_2(),
259 FetchURL(delegate.body()->GetURL()));
260 }
261
262 // Tests that the destroying the loader cancels the request.
263 TEST_F(NavigationURLLoaderTest, CancelOnDestruct) {
264 // Fake a top-level request. Choose a URL which redirects so the request can
265 // be paused before the response comes in.
266 TestNavigationURLLoaderDelegate delegate;
267 scoped_ptr<NavigationURLLoader> loader =
268 MakeTestLoader(net::URLRequestTestJob::test_url_redirect_to_url_2(),
269 &delegate);
270
271 // Wait for the request to redirect.
272 delegate.WaitForRequestRedirected();
273
274 // Destroy the loader and verify that URLRequestTestJob no longer has anything
275 // paused.
276 loader.reset();
277 base::RunLoop().RunUntilIdle();
278 EXPECT_FALSE(net::URLRequestTestJob::ProcessOnePendingMessage());
279 }
280
281 // Test that the delegate is not called if OnResponseStarted and destroying the
282 // loader race.
283 TEST_F(NavigationURLLoaderTest, CancelResponseRace) {
284 TestNavigationURLLoaderDelegate delegate;
285 scoped_ptr<NavigationURLLoader> loader =
286 MakeTestLoader(net::URLRequestTestJob::test_url_redirect_to_url_2(),
287 &delegate);
288
289 // Wait for the request to redirect.
290 delegate.WaitForRequestRedirected();
291
292 // In the same event loop iteration, follow the redirect (allowing the
293 // response to go through) and destroy the loader.
294 loader->FollowRedirect();
295 loader.reset();
296
297 // Verify the URLRequestTestJob no longer has anything paused and that no
298 // response body was received.
299 base::RunLoop().RunUntilIdle();
300 EXPECT_FALSE(net::URLRequestTestJob::ProcessOnePendingMessage());
301 EXPECT_FALSE(delegate.body());
302 }
303
304 // Tests that the loader may be canceled by context.
305 TEST_F(NavigationURLLoaderTest, CancelByContext) {
306 TestNavigationURLLoaderDelegate delegate;
307 scoped_ptr<NavigationURLLoader> loader =
308 MakeTestLoader(net::URLRequestTestJob::test_url_redirect_to_url_2(),
309 &delegate);
310
311 // Wait for the request to redirect.
312 delegate.WaitForRequestRedirected();
313
314 // Cancel all requests.
315 host_.CancelRequestsForContext(browser_context_->GetResourceContext());
316
317 // Wait for the request to now be aborted.
318 delegate.WaitForRequestFailed();
319 EXPECT_EQ(net::ERR_ABORTED, delegate.net_error());
320 }
321
322 // Tests that, if the request is blocked by the ResourceDispatcherHostDelegate,
323 // the caller is informed appropriately.
324 TEST_F(NavigationURLLoaderTest, RequestBlocked) {
325 RequestBlockingResourceDispatcherHostDelegate rdh_delegate;
326 host_.SetDelegate(&rdh_delegate);
327
328 TestNavigationURLLoaderDelegate delegate;
329 scoped_ptr<NavigationURLLoader> loader =
330 MakeTestLoader(net::URLRequestTestJob::test_url_1(), &delegate);
331
332 // Wait for the request to fail as expected.
333 delegate.WaitForRequestFailed();
334 EXPECT_EQ(net::ERR_ABORTED, delegate.net_error());
335
336 host_.SetDelegate(nullptr);
337 }
338
339 // Tests that ownership leaves the loader once the response is received.
340 TEST_F(NavigationURLLoaderTest, LoaderDetached) {
341 // Fake a top-level request to a URL whose body does not load immediately.
342 TestNavigationURLLoaderDelegate delegate;
343 scoped_ptr<NavigationURLLoader> loader =
344 MakeTestLoader(net::URLRequestTestJob::test_url_2(), &delegate);
345
346 // Wait for the response to come back.
347 delegate.WaitForResponseStarted();
348
349 // Check the response is correct.
350 EXPECT_EQ("text/html", delegate.response()->head.mime_type);
351 EXPECT_EQ("HTTP/1.1 200 OK",
352 delegate.response()->head.headers->GetStatusLine());
353
354 // Destroy the loader.
355 loader.reset();
356 base::RunLoop().RunUntilIdle();
357
358 // Check the body can still be fetched through the StreamHandle.
359 EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage());
360 EXPECT_EQ(net::URLRequestTestJob::test_data_2(),
361 FetchURL(delegate.body()->GetURL()));
362 }
363
364 // Tests that the request is owned by the body StreamHandle.
365 TEST_F(NavigationURLLoaderTest, OwnedByHandle) {
366 // Fake a top-level request to a URL whose body does not load immediately.
367 TestNavigationURLLoaderDelegate delegate;
368 scoped_ptr<NavigationURLLoader> loader =
369 MakeTestLoader(net::URLRequestTestJob::test_url_2(), &delegate);
370
371 // Wait for the response to come back.
372 delegate.WaitForResponseStarted();
373
374 // Release the body.
375 delegate.ReleaseBody();
376 base::RunLoop().RunUntilIdle();
377
378 // Verify that URLRequestTestJob no longer has anything paused.
379 EXPECT_FALSE(net::URLRequestTestJob::ProcessOnePendingMessage());
380 }
381
382 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698