OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/loader/resource_loader.h" | 5 #include "content/browser/loader/resource_loader.h" |
6 | 6 |
| 7 #include "base/file_util.h" |
| 8 #include "base/files/file.h" |
| 9 #include "base/message_loop/message_loop_proxy.h" |
| 10 #include "base/platform_file.h" |
7 #include "base/run_loop.h" | 11 #include "base/run_loop.h" |
8 #include "content/browser/browser_thread_impl.h" | 12 #include "content/browser/browser_thread_impl.h" |
| 13 #include "content/browser/loader/redirect_to_file_resource_handler.h" |
9 #include "content/browser/loader/resource_loader_delegate.h" | 14 #include "content/browser/loader/resource_loader_delegate.h" |
10 #include "content/public/browser/resource_request_info.h" | 15 #include "content/public/browser/resource_request_info.h" |
| 16 #include "content/public/common/resource_response.h" |
11 #include "content/public/test/mock_resource_context.h" | 17 #include "content/public/test/mock_resource_context.h" |
12 #include "content/public/test/test_browser_thread_bundle.h" | 18 #include "content/public/test/test_browser_thread_bundle.h" |
13 #include "content/test/test_content_browser_client.h" | 19 #include "content/test/test_content_browser_client.h" |
14 #include "ipc/ipc_message.h" | 20 #include "ipc/ipc_message.h" |
| 21 #include "net/base/mock_file_stream.h" |
15 #include "net/base/request_priority.h" | 22 #include "net/base/request_priority.h" |
16 #include "net/cert/x509_certificate.h" | 23 #include "net/cert/x509_certificate.h" |
17 #include "net/ssl/client_cert_store.h" | 24 #include "net/ssl/client_cert_store.h" |
18 #include "net/ssl/ssl_cert_request_info.h" | 25 #include "net/ssl/ssl_cert_request_info.h" |
19 #include "net/url_request/url_request.h" | 26 #include "net/url_request/url_request.h" |
| 27 #include "net/url_request/url_request_job_factory_impl.h" |
| 28 #include "net/url_request/url_request_test_job.h" |
20 #include "net/url_request/url_request_test_util.h" | 29 #include "net/url_request/url_request_test_util.h" |
21 #include "testing/gtest/include/gtest/gtest.h" | 30 #include "testing/gtest/include/gtest/gtest.h" |
| 31 #include "webkit/common/blob/shareable_file_reference.h" |
| 32 |
| 33 using webkit_blob::ShareableFileReference; |
22 | 34 |
23 namespace content { | 35 namespace content { |
24 namespace { | 36 namespace { |
25 | 37 |
26 // Stub client certificate store that returns a preset list of certificates for | 38 // Stub client certificate store that returns a preset list of certificates for |
27 // each request and records the arguments of the most recent request for later | 39 // each request and records the arguments of the most recent request for later |
28 // inspection. | 40 // inspection. |
29 class ClientCertStoreStub : public net::ClientCertStore { | 41 class ClientCertStoreStub : public net::ClientCertStore { |
30 public: | 42 public: |
31 ClientCertStoreStub(const net::CertificateList& certs) | 43 ClientCertStoreStub(const net::CertificateList& certs) |
(...skipping 30 matching lines...) Expand all Loading... |
62 private: | 74 private: |
63 const net::CertificateList response_; | 75 const net::CertificateList response_; |
64 int request_count_; | 76 int request_count_; |
65 std::vector<std::string> requested_authorities_; | 77 std::vector<std::string> requested_authorities_; |
66 }; | 78 }; |
67 | 79 |
68 // Dummy implementation of ResourceHandler, instance of which is needed to | 80 // Dummy implementation of ResourceHandler, instance of which is needed to |
69 // initialize ResourceLoader. | 81 // initialize ResourceLoader. |
70 class ResourceHandlerStub : public ResourceHandler { | 82 class ResourceHandlerStub : public ResourceHandler { |
71 public: | 83 public: |
72 ResourceHandlerStub() | 84 explicit ResourceHandlerStub(net::URLRequest* request) |
73 : ResourceHandler(NULL), defer_request_on_will_start_(false) {} | 85 : ResourceHandler(request), |
| 86 defer_request_on_will_start_(false), |
| 87 received_response_completed_(false), |
| 88 total_bytes_downloaded_(0) { |
| 89 } |
74 | 90 |
75 void set_defer_request_on_will_start(bool defer_request_on_will_start) { | 91 void set_defer_request_on_will_start(bool defer_request_on_will_start) { |
76 defer_request_on_will_start_ = defer_request_on_will_start; | 92 defer_request_on_will_start_ = defer_request_on_will_start; |
77 } | 93 } |
78 | 94 |
| 95 const GURL& start_url() const { return start_url_; } |
| 96 ResourceResponse* response() const { return response_.get(); } |
| 97 bool received_response_completed() const { |
| 98 return received_response_completed_; |
| 99 } |
| 100 const net::URLRequestStatus& status() const { return status_; } |
| 101 int total_bytes_downloaded() const { return total_bytes_downloaded_; } |
| 102 |
| 103 void Resume() { |
| 104 controller()->Resume(); |
| 105 } |
| 106 |
| 107 // ResourceHandler implementation: |
79 virtual bool OnUploadProgress(int request_id, | 108 virtual bool OnUploadProgress(int request_id, |
80 uint64 position, | 109 uint64 position, |
81 uint64 size) OVERRIDE { | 110 uint64 size) OVERRIDE { |
| 111 NOTREACHED(); |
82 return true; | 112 return true; |
83 } | 113 } |
84 | 114 |
85 virtual bool OnRequestRedirected(int request_id, | 115 virtual bool OnRequestRedirected(int request_id, |
86 const GURL& url, | 116 const GURL& url, |
87 ResourceResponse* response, | 117 ResourceResponse* response, |
88 bool* defer) OVERRIDE { | 118 bool* defer) OVERRIDE { |
| 119 NOTREACHED(); |
89 return true; | 120 return true; |
90 } | 121 } |
91 | 122 |
92 virtual bool OnResponseStarted(int request_id, | 123 virtual bool OnResponseStarted(int request_id, |
93 ResourceResponse* response, | 124 ResourceResponse* response, |
94 bool* defer) OVERRIDE { | 125 bool* defer) OVERRIDE { |
| 126 EXPECT_FALSE(response_); |
| 127 response_ = response; |
95 return true; | 128 return true; |
96 } | 129 } |
97 | 130 |
98 virtual bool OnWillStart(int request_id, | 131 virtual bool OnWillStart(int request_id, |
99 const GURL& url, | 132 const GURL& url, |
100 bool* defer) OVERRIDE { | 133 bool* defer) OVERRIDE { |
| 134 EXPECT_TRUE(start_url_.is_empty()); |
| 135 start_url_ = url; |
101 *defer = defer_request_on_will_start_; | 136 *defer = defer_request_on_will_start_; |
102 return true; | 137 return true; |
103 } | 138 } |
104 | 139 |
105 virtual bool OnBeforeNetworkStart(int request_id, | 140 virtual bool OnBeforeNetworkStart(int request_id, |
106 const GURL& url, | 141 const GURL& url, |
107 bool* defer) OVERRIDE { | 142 bool* defer) OVERRIDE { |
108 return true; | 143 return true; |
109 } | 144 } |
110 | 145 |
111 virtual bool OnWillRead(int request_id, | 146 virtual bool OnWillRead(int request_id, |
112 scoped_refptr<net::IOBuffer>* buf, | 147 scoped_refptr<net::IOBuffer>* buf, |
113 int* buf_size, | 148 int* buf_size, |
114 int min_size) OVERRIDE { | 149 int min_size) OVERRIDE { |
115 return true; | 150 NOTREACHED(); |
| 151 return false; |
116 } | 152 } |
117 | 153 |
118 virtual bool OnReadCompleted(int request_id, | 154 virtual bool OnReadCompleted(int request_id, |
119 int bytes_read, | 155 int bytes_read, |
120 bool* defer) OVERRIDE { | 156 bool* defer) OVERRIDE { |
121 return true; | 157 NOTREACHED(); |
| 158 return false; |
122 } | 159 } |
123 | 160 |
124 virtual void OnResponseCompleted(int request_id, | 161 virtual void OnResponseCompleted(int request_id, |
125 const net::URLRequestStatus& status, | 162 const net::URLRequestStatus& status, |
126 const std::string& security_info, | 163 const std::string& security_info, |
127 bool* defer) OVERRIDE { | 164 bool* defer) OVERRIDE { |
| 165 // TODO(davidben): This DCHECK currently fires everywhere. Fix the places in |
| 166 // ResourceLoader where OnResponseCompleted is signaled twice. |
| 167 // DCHECK(!received_response_completed_); |
| 168 received_response_completed_ = true; |
| 169 status_ = status; |
128 } | 170 } |
129 | 171 |
130 virtual void OnDataDownloaded(int request_id, | 172 virtual void OnDataDownloaded(int request_id, |
131 int bytes_downloaded) OVERRIDE {} | 173 int bytes_downloaded) OVERRIDE { |
| 174 total_bytes_downloaded_ += bytes_downloaded; |
| 175 } |
132 | 176 |
133 private: | 177 private: |
134 bool defer_request_on_will_start_; | 178 bool defer_request_on_will_start_; |
| 179 GURL start_url_; |
| 180 scoped_refptr<ResourceResponse> response_; |
| 181 bool received_response_completed_; |
| 182 net::URLRequestStatus status_; |
| 183 int total_bytes_downloaded_; |
135 }; | 184 }; |
136 | 185 |
137 // Test browser client that captures calls to SelectClientCertificates and | 186 // Test browser client that captures calls to SelectClientCertificates and |
138 // records the arguments of the most recent call for later inspection. | 187 // records the arguments of the most recent call for later inspection. |
139 class SelectCertificateBrowserClient : public TestContentBrowserClient { | 188 class SelectCertificateBrowserClient : public TestContentBrowserClient { |
140 public: | 189 public: |
141 SelectCertificateBrowserClient() : call_count_(0) {} | 190 SelectCertificateBrowserClient() : call_count_(0) {} |
142 | 191 |
143 virtual void SelectClientCertificate( | 192 virtual void SelectClientCertificate( |
144 int render_process_id, | 193 int render_process_id, |
(...skipping 28 matching lines...) Expand all Loading... |
173 } | 222 } |
174 | 223 |
175 void SetClientCertStore(scoped_ptr<net::ClientCertStore> store) { | 224 void SetClientCertStore(scoped_ptr<net::ClientCertStore> store) { |
176 dummy_cert_store_ = store.Pass(); | 225 dummy_cert_store_ = store.Pass(); |
177 } | 226 } |
178 | 227 |
179 private: | 228 private: |
180 scoped_ptr<net::ClientCertStore> dummy_cert_store_; | 229 scoped_ptr<net::ClientCertStore> dummy_cert_store_; |
181 }; | 230 }; |
182 | 231 |
| 232 // Fails to create a temporary file with the given error. |
| 233 void CreateTemporaryError( |
| 234 base::File::Error error, |
| 235 const CreateTemporaryFileStreamCallback& callback) { |
| 236 base::MessageLoop::current()->PostTask( |
| 237 FROM_HERE, |
| 238 base::Bind(callback, error, base::Passed(scoped_ptr<net::FileStream>()), |
| 239 scoped_refptr<ShareableFileReference>())); |
| 240 } |
| 241 |
183 } // namespace | 242 } // namespace |
184 | 243 |
185 class ResourceLoaderTest : public testing::Test, | 244 class ResourceLoaderTest : public testing::Test, |
186 public ResourceLoaderDelegate { | 245 public ResourceLoaderDelegate { |
187 protected: | 246 protected: |
188 ResourceLoaderTest() | 247 ResourceLoaderTest() |
189 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), | 248 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), |
190 resource_context_(&test_url_request_context_) { | 249 resource_context_(&test_url_request_context_), |
| 250 raw_ptr_resource_handler_(NULL), |
| 251 raw_ptr_to_request_(NULL) { |
| 252 job_factory_.SetProtocolHandler( |
| 253 "test", net::URLRequestTestJob::CreateProtocolHandler()); |
| 254 test_url_request_context_.set_job_factory(&job_factory_); |
| 255 } |
| 256 |
| 257 GURL test_url() const { |
| 258 return net::URLRequestTestJob::test_url_1(); |
| 259 } |
| 260 |
| 261 std::string test_data() const { |
| 262 return net::URLRequestTestJob::test_data_1(); |
| 263 } |
| 264 |
| 265 virtual scoped_ptr<ResourceHandler> WrapResourceHandler( |
| 266 scoped_ptr<ResourceHandlerStub> leaf_handler, |
| 267 net::URLRequest* request) { |
| 268 return leaf_handler.PassAs<ResourceHandler>(); |
191 } | 269 } |
192 | 270 |
193 virtual void SetUp() OVERRIDE { | 271 virtual void SetUp() OVERRIDE { |
194 const int kRenderProcessId = 1; | 272 const int kRenderProcessId = 1; |
195 const int kRenderViewId = 2; | 273 const int kRenderViewId = 2; |
196 | 274 |
197 scoped_ptr<net::URLRequest> request( | 275 scoped_ptr<net::URLRequest> request( |
198 new net::URLRequest(GURL("dummy"), | 276 new net::URLRequest(test_url(), |
199 net::DEFAULT_PRIORITY, | 277 net::DEFAULT_PRIORITY, |
200 NULL, | 278 NULL, |
201 resource_context_.GetRequestContext())); | 279 resource_context_.GetRequestContext())); |
202 raw_ptr_to_request_ = request.get(); | 280 raw_ptr_to_request_ = request.get(); |
203 ResourceRequestInfo::AllocateForTesting(request.get(), | 281 ResourceRequestInfo::AllocateForTesting(request.get(), |
204 ResourceType::MAIN_FRAME, | 282 ResourceType::MAIN_FRAME, |
205 &resource_context_, | 283 &resource_context_, |
206 kRenderProcessId, | 284 kRenderProcessId, |
207 kRenderViewId, | 285 kRenderViewId, |
208 MSG_ROUTING_NONE, | 286 MSG_ROUTING_NONE, |
209 false); | 287 false); |
210 scoped_ptr<ResourceHandlerStub> resource_handler(new ResourceHandlerStub()); | 288 scoped_ptr<ResourceHandlerStub> resource_handler( |
| 289 new ResourceHandlerStub(request.get())); |
211 raw_ptr_resource_handler_ = resource_handler.get(); | 290 raw_ptr_resource_handler_ = resource_handler.get(); |
212 loader_.reset(new ResourceLoader( | 291 loader_.reset(new ResourceLoader( |
213 request.Pass(), resource_handler.PassAs<ResourceHandler>(), this)); | 292 request.Pass(), |
| 293 WrapResourceHandler(resource_handler.Pass(), raw_ptr_to_request_), |
| 294 this)); |
214 } | 295 } |
215 | 296 |
216 // ResourceLoaderDelegate: | 297 // ResourceLoaderDelegate: |
217 virtual ResourceDispatcherHostLoginDelegate* CreateLoginDelegate( | 298 virtual ResourceDispatcherHostLoginDelegate* CreateLoginDelegate( |
218 ResourceLoader* loader, | 299 ResourceLoader* loader, |
219 net::AuthChallengeInfo* auth_info) OVERRIDE { | 300 net::AuthChallengeInfo* auth_info) OVERRIDE { |
220 return NULL; | 301 return NULL; |
221 } | 302 } |
222 virtual bool HandleExternalProtocol(ResourceLoader* loader, | 303 virtual bool HandleExternalProtocol(ResourceLoader* loader, |
223 const GURL& url) OVERRIDE { | 304 const GURL& url) OVERRIDE { |
224 return false; | 305 return false; |
225 } | 306 } |
226 virtual void DidStartRequest(ResourceLoader* loader) OVERRIDE {} | 307 virtual void DidStartRequest(ResourceLoader* loader) OVERRIDE {} |
227 virtual void DidReceiveRedirect(ResourceLoader* loader, | 308 virtual void DidReceiveRedirect(ResourceLoader* loader, |
228 const GURL& new_url) OVERRIDE {} | 309 const GURL& new_url) OVERRIDE {} |
229 virtual void DidReceiveResponse(ResourceLoader* loader) OVERRIDE {} | 310 virtual void DidReceiveResponse(ResourceLoader* loader) OVERRIDE {} |
230 virtual void DidFinishLoading(ResourceLoader* loader) OVERRIDE {} | 311 virtual void DidFinishLoading(ResourceLoader* loader) OVERRIDE {} |
231 | 312 |
232 content::TestBrowserThreadBundle thread_bundle_; | 313 content::TestBrowserThreadBundle thread_bundle_; |
233 | 314 |
| 315 net::URLRequestJobFactoryImpl job_factory_; |
234 net::TestURLRequestContext test_url_request_context_; | 316 net::TestURLRequestContext test_url_request_context_; |
235 ResourceContextStub resource_context_; | 317 ResourceContextStub resource_context_; |
236 | 318 |
237 // The ResourceLoader owns the URLRequest and the ResourceHandler. | 319 // The ResourceLoader owns the URLRequest and the ResourceHandler. |
238 ResourceHandlerStub* raw_ptr_resource_handler_; | 320 ResourceHandlerStub* raw_ptr_resource_handler_; |
239 net::URLRequest* raw_ptr_to_request_; | 321 net::URLRequest* raw_ptr_to_request_; |
240 scoped_ptr<ResourceLoader> loader_; | 322 scoped_ptr<ResourceLoader> loader_; |
241 }; | 323 }; |
242 | 324 |
243 // Verifies if a call to net::UrlRequest::Delegate::OnCertificateRequested() | 325 // Verifies if a call to net::UrlRequest::Delegate::OnCertificateRequested() |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
315 } | 397 } |
316 | 398 |
317 TEST_F(ResourceLoaderTest, ResumeCancelledRequest) { | 399 TEST_F(ResourceLoaderTest, ResumeCancelledRequest) { |
318 raw_ptr_resource_handler_->set_defer_request_on_will_start(true); | 400 raw_ptr_resource_handler_->set_defer_request_on_will_start(true); |
319 | 401 |
320 loader_->StartRequest(); | 402 loader_->StartRequest(); |
321 loader_->CancelRequest(true); | 403 loader_->CancelRequest(true); |
322 static_cast<ResourceController*>(loader_.get())->Resume(); | 404 static_cast<ResourceController*>(loader_.get())->Resume(); |
323 } | 405 } |
324 | 406 |
| 407 class ResourceLoaderRedirectToFileTest : public ResourceLoaderTest { |
| 408 public: |
| 409 ResourceLoaderRedirectToFileTest() |
| 410 : file_stream_(NULL), |
| 411 redirect_to_file_resource_handler_(NULL) { |
| 412 } |
| 413 |
| 414 base::FilePath temp_path() const { return temp_path_; } |
| 415 ShareableFileReference* deletable_file() const { |
| 416 return deletable_file_.get(); |
| 417 } |
| 418 net::testing::MockFileStream* file_stream() const { return file_stream_; } |
| 419 RedirectToFileResourceHandler* redirect_to_file_resource_handler() const { |
| 420 return redirect_to_file_resource_handler_; |
| 421 } |
| 422 |
| 423 void ReleaseLoader() { |
| 424 file_stream_ = NULL; |
| 425 deletable_file_ = NULL; |
| 426 loader_.reset(); |
| 427 } |
| 428 |
| 429 virtual scoped_ptr<ResourceHandler> WrapResourceHandler( |
| 430 scoped_ptr<ResourceHandlerStub> leaf_handler, |
| 431 net::URLRequest* request) OVERRIDE { |
| 432 // Make a temporary file. |
| 433 CHECK(base::CreateTemporaryFile(&temp_path_)); |
| 434 base::PlatformFile platform_file = |
| 435 base::CreatePlatformFile(temp_path_, |
| 436 base::PLATFORM_FILE_WRITE | |
| 437 base::PLATFORM_FILE_TEMPORARY | |
| 438 base::PLATFORM_FILE_CREATE_ALWAYS | |
| 439 base::PLATFORM_FILE_ASYNC, |
| 440 NULL, NULL); |
| 441 CHECK_NE(base::kInvalidPlatformFileValue, platform_file); |
| 442 |
| 443 // Create mock file streams and a ShareableFileReference. |
| 444 scoped_ptr<net::testing::MockFileStream> file_stream( |
| 445 new net::testing::MockFileStream( |
| 446 platform_file, |
| 447 base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_ASYNC, |
| 448 NULL, base::MessageLoopProxy::current())); |
| 449 file_stream_ = file_stream.get(); |
| 450 deletable_file_ = ShareableFileReference::GetOrCreate( |
| 451 temp_path_, |
| 452 ShareableFileReference::DELETE_ON_FINAL_RELEASE, |
| 453 BrowserThread::GetMessageLoopProxyForThread( |
| 454 BrowserThread::FILE).get()); |
| 455 |
| 456 // Inject them into the handler. |
| 457 scoped_ptr<RedirectToFileResourceHandler> handler( |
| 458 new RedirectToFileResourceHandler( |
| 459 leaf_handler.PassAs<ResourceHandler>(), request)); |
| 460 redirect_to_file_resource_handler_ = handler.get(); |
| 461 handler->SetCreateTemporaryFileStreamFunctionForTesting( |
| 462 base::Bind(&ResourceLoaderRedirectToFileTest::PostCallback, |
| 463 base::Unretained(this), |
| 464 base::Passed(file_stream.PassAs<net::FileStream>()))); |
| 465 return handler.PassAs<ResourceHandler>(); |
| 466 } |
| 467 |
| 468 private: |
| 469 void PostCallback( |
| 470 scoped_ptr<net::FileStream> file_stream, |
| 471 const CreateTemporaryFileStreamCallback& callback) { |
| 472 base::MessageLoop::current()->PostTask( |
| 473 FROM_HERE, |
| 474 base::Bind(callback, base::File::FILE_OK, |
| 475 base::Passed(&file_stream), deletable_file_)); |
| 476 } |
| 477 |
| 478 base::FilePath temp_path_; |
| 479 scoped_refptr<ShareableFileReference> deletable_file_; |
| 480 // These are owned by the ResourceLoader. |
| 481 net::testing::MockFileStream* file_stream_; |
| 482 RedirectToFileResourceHandler* redirect_to_file_resource_handler_; |
| 483 }; |
| 484 |
| 485 // Tests that a RedirectToFileResourceHandler works and forwards everything |
| 486 // downstream. |
| 487 TEST_F(ResourceLoaderRedirectToFileTest, Basic) { |
| 488 // Run it to completion. |
| 489 loader_->StartRequest(); |
| 490 base::RunLoop().RunUntilIdle(); |
| 491 |
| 492 // Check that the handler forwarded all information to the downstream handler. |
| 493 EXPECT_EQ(temp_path(), |
| 494 raw_ptr_resource_handler_->response()->head.download_file_path); |
| 495 EXPECT_EQ(test_url(), raw_ptr_resource_handler_->start_url()); |
| 496 EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed()); |
| 497 EXPECT_EQ(net::URLRequestStatus::SUCCESS, |
| 498 raw_ptr_resource_handler_->status().status()); |
| 499 EXPECT_EQ(test_data().size(), static_cast<size_t>( |
| 500 raw_ptr_resource_handler_->total_bytes_downloaded())); |
| 501 |
| 502 // Check that the data was written to the file. |
| 503 std::string contents; |
| 504 ASSERT_TRUE(base::ReadFileToString(temp_path(), &contents)); |
| 505 EXPECT_EQ(test_data(), contents); |
| 506 |
| 507 // Release the loader and the saved reference to file. The file should be gone |
| 508 // now. |
| 509 ReleaseLoader(); |
| 510 base::RunLoop().RunUntilIdle(); |
| 511 EXPECT_FALSE(base::PathExists(temp_path())); |
| 512 } |
| 513 |
| 514 // Tests that RedirectToFileResourceHandler handles errors in creating the |
| 515 // temporary file. |
| 516 TEST_F(ResourceLoaderRedirectToFileTest, CreateTemporaryError) { |
| 517 // Swap out the create temporary function. |
| 518 redirect_to_file_resource_handler()-> |
| 519 SetCreateTemporaryFileStreamFunctionForTesting( |
| 520 base::Bind(&CreateTemporaryError, base::File::FILE_ERROR_FAILED)); |
| 521 |
| 522 // Run it to completion. |
| 523 loader_->StartRequest(); |
| 524 base::RunLoop().RunUntilIdle(); |
| 525 |
| 526 // To downstream, the request was canceled. |
| 527 EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed()); |
| 528 EXPECT_EQ(net::URLRequestStatus::CANCELED, |
| 529 raw_ptr_resource_handler_->status().status()); |
| 530 EXPECT_EQ(0, raw_ptr_resource_handler_->total_bytes_downloaded()); |
| 531 } |
| 532 |
| 533 // Tests that RedirectToFileResourceHandler handles synchronous write errors. |
| 534 TEST_F(ResourceLoaderRedirectToFileTest, WriteError) { |
| 535 file_stream()->set_forced_error(net::ERR_FAILED); |
| 536 |
| 537 // Run it to completion. |
| 538 loader_->StartRequest(); |
| 539 base::RunLoop().RunUntilIdle(); |
| 540 |
| 541 // To downstream, the request was canceled sometime after it started, but |
| 542 // before any data was written. |
| 543 EXPECT_EQ(temp_path(), |
| 544 raw_ptr_resource_handler_->response()->head.download_file_path); |
| 545 EXPECT_EQ(test_url(), raw_ptr_resource_handler_->start_url()); |
| 546 EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed()); |
| 547 EXPECT_EQ(net::URLRequestStatus::CANCELED, |
| 548 raw_ptr_resource_handler_->status().status()); |
| 549 EXPECT_EQ(0, raw_ptr_resource_handler_->total_bytes_downloaded()); |
| 550 |
| 551 // Release the loader. The file should be gone now. |
| 552 ReleaseLoader(); |
| 553 base::RunLoop().RunUntilIdle(); |
| 554 EXPECT_FALSE(base::PathExists(temp_path())); |
| 555 } |
| 556 |
| 557 // Tests that RedirectToFileResourceHandler handles asynchronous write errors. |
| 558 TEST_F(ResourceLoaderRedirectToFileTest, WriteErrorAsync) { |
| 559 file_stream()->set_forced_error_async(net::ERR_FAILED); |
| 560 |
| 561 // Run it to completion. |
| 562 loader_->StartRequest(); |
| 563 base::RunLoop().RunUntilIdle(); |
| 564 |
| 565 // To downstream, the request was canceled sometime after it started, but |
| 566 // before any data was written. |
| 567 EXPECT_EQ(temp_path(), |
| 568 raw_ptr_resource_handler_->response()->head.download_file_path); |
| 569 EXPECT_EQ(test_url(), raw_ptr_resource_handler_->start_url()); |
| 570 EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed()); |
| 571 EXPECT_EQ(net::URLRequestStatus::CANCELED, |
| 572 raw_ptr_resource_handler_->status().status()); |
| 573 EXPECT_EQ(0, raw_ptr_resource_handler_->total_bytes_downloaded()); |
| 574 |
| 575 // Release the loader. The file should be gone now. |
| 576 ReleaseLoader(); |
| 577 base::RunLoop().RunUntilIdle(); |
| 578 EXPECT_FALSE(base::PathExists(temp_path())); |
| 579 } |
| 580 |
| 581 // Tests that RedirectToFileHandler defers completion if there are outstanding |
| 582 // writes and accounts for errors which occur in that time. |
| 583 TEST_F(ResourceLoaderRedirectToFileTest, DeferCompletion) { |
| 584 // Program the MockFileStream to error asynchronously, but throttle the |
| 585 // callback. |
| 586 file_stream()->set_forced_error_async(net::ERR_FAILED); |
| 587 file_stream()->ThrottleCallbacks(); |
| 588 |
| 589 // Run it as far as it will go. |
| 590 loader_->StartRequest(); |
| 591 base::RunLoop().RunUntilIdle(); |
| 592 |
| 593 // At this point, the request should have completed. |
| 594 EXPECT_EQ(net::URLRequestStatus::SUCCESS, |
| 595 raw_ptr_to_request_->status().status()); |
| 596 |
| 597 // However, the resource loader stack is stuck somewhere after receiving the |
| 598 // response. |
| 599 EXPECT_EQ(temp_path(), |
| 600 raw_ptr_resource_handler_->response()->head.download_file_path); |
| 601 EXPECT_EQ(test_url(), raw_ptr_resource_handler_->start_url()); |
| 602 EXPECT_FALSE(raw_ptr_resource_handler_->received_response_completed()); |
| 603 EXPECT_EQ(0, raw_ptr_resource_handler_->total_bytes_downloaded()); |
| 604 |
| 605 // Now, release the floodgates. |
| 606 file_stream()->ReleaseCallbacks(); |
| 607 base::RunLoop().RunUntilIdle(); |
| 608 |
| 609 // Although the URLRequest was successful, the leaf handler sees a failure |
| 610 // because the write never completed. |
| 611 EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed()); |
| 612 EXPECT_EQ(net::URLRequestStatus::CANCELED, |
| 613 raw_ptr_resource_handler_->status().status()); |
| 614 |
| 615 // Release the loader. The file should be gone now. |
| 616 ReleaseLoader(); |
| 617 base::RunLoop().RunUntilIdle(); |
| 618 EXPECT_FALSE(base::PathExists(temp_path())); |
| 619 } |
| 620 |
| 621 // Tests that a RedirectToFileResourceHandler behaves properly when the |
| 622 // downstream handler defers OnWillStart. |
| 623 TEST_F(ResourceLoaderRedirectToFileTest, DownstreamDeferStart) { |
| 624 // Defer OnWillStart. |
| 625 raw_ptr_resource_handler_->set_defer_request_on_will_start(true); |
| 626 |
| 627 // Run as far as we'll go. |
| 628 loader_->StartRequest(); |
| 629 base::RunLoop().RunUntilIdle(); |
| 630 |
| 631 // The request should have stopped at OnWillStart. |
| 632 EXPECT_EQ(test_url(), raw_ptr_resource_handler_->start_url()); |
| 633 EXPECT_FALSE(raw_ptr_resource_handler_->response()); |
| 634 EXPECT_FALSE(raw_ptr_resource_handler_->received_response_completed()); |
| 635 EXPECT_EQ(0, raw_ptr_resource_handler_->total_bytes_downloaded()); |
| 636 |
| 637 // Now resume the request. Now we complete. |
| 638 raw_ptr_resource_handler_->Resume(); |
| 639 base::RunLoop().RunUntilIdle(); |
| 640 |
| 641 // Check that the handler forwarded all information to the downstream handler. |
| 642 EXPECT_EQ(temp_path(), |
| 643 raw_ptr_resource_handler_->response()->head.download_file_path); |
| 644 EXPECT_EQ(test_url(), raw_ptr_resource_handler_->start_url()); |
| 645 EXPECT_TRUE(raw_ptr_resource_handler_->received_response_completed()); |
| 646 EXPECT_EQ(net::URLRequestStatus::SUCCESS, |
| 647 raw_ptr_resource_handler_->status().status()); |
| 648 EXPECT_EQ(test_data().size(), static_cast<size_t>( |
| 649 raw_ptr_resource_handler_->total_bytes_downloaded())); |
| 650 |
| 651 // Check that the data was written to the file. |
| 652 std::string contents; |
| 653 ASSERT_TRUE(base::ReadFileToString(temp_path(), &contents)); |
| 654 EXPECT_EQ(test_data(), contents); |
| 655 |
| 656 // Release the loader. The file should be gone now. |
| 657 ReleaseLoader(); |
| 658 base::RunLoop().RunUntilIdle(); |
| 659 EXPECT_FALSE(base::PathExists(temp_path())); |
| 660 } |
| 661 |
325 } // namespace content | 662 } // namespace content |
OLD | NEW |