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

Side by Side Diff: webkit/support/simple_resource_loader_bridge.cc

Issue 17476002: delete webkit/support/simple_xxx's (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: android Created 7 years, 5 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 | Annotate | Revision Log
OLDNEW
(Empty)
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.
4 //
5 // This file contains an implementation of the ResourceLoaderBridge class.
6 // The class is implemented using net::URLRequest, meaning it is a "simple"
7 // version that directly issues requests. The more complicated one used in the
8 // browser uses IPC.
9 //
10 // Because net::URLRequest only provides an asynchronous resource loading API,
11 // this file makes use of net::URLRequest from a background IO thread. Requests
12 // for cookies and synchronously loaded resources result in the main thread of
13 // the application blocking until the IO thread completes the operation. (See
14 // GetCookies and SyncLoad)
15 //
16 // Main thread IO thread
17 // ----------- ---------
18 // ResourceLoaderBridge <---o---------> RequestProxy (normal case)
19 // \ -> net::URLRequest
20 // o-------> SyncRequestProxy (synchronous case)
21 // -> net::URLRequest
22 // SetCookie <------------------------> CookieSetter
23 // -> net_util::SetCookie
24 // GetCookies <-----------------------> CookieGetter
25 // -> net_util::GetCookies
26 //
27 // NOTE: The implementation in this file may be used to have WebKit fetch
28 // resources in-process. For example, it is handy for building a single-
29 // process WebKit embedding (e.g., test_shell) that can use net::URLRequest to
30 // perform URL loads. See renderer/resource_dispatcher.h for details on an
31 // alternate implementation that defers fetching to another process.
32
33 #include "webkit/support/simple_resource_loader_bridge.h"
34
35 #include "base/bind.h"
36 #include "base/compiler_specific.h"
37 #include "base/file_util.h"
38 #include "base/files/file_path.h"
39 #include "base/logging.h"
40 #include "base/memory/ref_counted.h"
41 #include "base/message_loop.h"
42 #include "base/message_loop/message_loop_proxy.h"
43 #include "base/strings/string_util.h"
44 #include "base/synchronization/waitable_event.h"
45 #include "base/threading/thread.h"
46 #include "base/time.h"
47 #include "base/timer.h"
48 #include "net/base/file_stream.h"
49 #include "net/base/io_buffer.h"
50 #include "net/base/load_flags.h"
51 #include "net/base/mime_util.h"
52 #include "net/base/net_errors.h"
53 #include "net/base/net_util.h"
54 #include "net/base/network_delegate.h"
55 #include "net/base/static_cookie_policy.h"
56 #include "net/base/upload_data_stream.h"
57 #include "net/cookies/cookie_store.h"
58 #include "net/http/http_cache.h"
59 #include "net/http/http_request_headers.h"
60 #include "net/http/http_response_headers.h"
61 #include "net/url_request/url_request.h"
62 #include "net/url_request/url_request_context.h"
63 #include "net/url_request/url_request_job.h"
64 #include "webkit/browser/blob/blob_storage_controller.h"
65 #include "webkit/browser/blob/blob_url_request_job.h"
66 #include "webkit/browser/fileapi/file_system_context.h"
67 #include "webkit/browser/fileapi/file_system_dir_url_request_job.h"
68 #include "webkit/browser/fileapi/file_system_url_request_job.h"
69 #include "webkit/common/appcache/appcache_interfaces.h"
70 #include "webkit/common/blob/shareable_file_reference.h"
71 #include "webkit/glue/resource_loader_bridge.h"
72 #include "webkit/glue/resource_request_body.h"
73 #include "webkit/glue/webkit_glue.h"
74 #include "webkit/support/simple_appcache_system.h"
75 #include "webkit/support/simple_file_system.h"
76 #include "webkit/support/simple_file_writer.h"
77 #include "webkit/support/simple_socket_stream_bridge.h"
78 #include "webkit/support/test_shell_request_context.h"
79 #include "webkit/support/test_shell_webblobregistry_impl.h"
80
81 #if defined(OS_MACOSX) || defined(OS_WIN)
82 #include "crypto/nss_util.h"
83 #endif
84
85 using webkit_glue::ResourceLoaderBridge;
86 using webkit_glue::ResourceRequestBody;
87 using webkit_glue::ResourceResponseInfo;
88 using net::StaticCookiePolicy;
89 using net::HttpResponseHeaders;
90 using webkit_blob::ShareableFileReference;
91
92 namespace {
93
94 struct TestShellRequestContextParams {
95 TestShellRequestContextParams(
96 const base::FilePath& in_cache_path,
97 net::HttpCache::Mode in_cache_mode,
98 bool in_no_proxy)
99 : cache_path(in_cache_path),
100 cache_mode(in_cache_mode),
101 no_proxy(in_no_proxy) {}
102
103 base::FilePath cache_path;
104 net::HttpCache::Mode cache_mode;
105 bool no_proxy;
106 };
107
108 //-----------------------------------------------------------------------------
109
110 bool g_accept_all_cookies = false;
111
112 class TestShellNetworkDelegate : public net::NetworkDelegate {
113 public:
114 virtual ~TestShellNetworkDelegate() {}
115
116 protected:
117 // net::NetworkDelegate implementation.
118 virtual int OnBeforeURLRequest(net::URLRequest* request,
119 const net::CompletionCallback& callback,
120 GURL* new_url) OVERRIDE {
121 return net::OK;
122 }
123 virtual int OnBeforeSendHeaders(net::URLRequest* request,
124 const net::CompletionCallback& callback,
125 net::HttpRequestHeaders* headers) OVERRIDE {
126 return net::OK;
127 }
128 virtual void OnSendHeaders(net::URLRequest* request,
129 const net::HttpRequestHeaders& headers) OVERRIDE {}
130 virtual int OnHeadersReceived(
131 net::URLRequest* request,
132 const net::CompletionCallback& callback,
133 const net::HttpResponseHeaders* original_response_headers,
134 scoped_refptr<net::HttpResponseHeaders>*
135 override_response_headers) OVERRIDE {
136 return net::OK;
137 }
138 virtual void OnBeforeRedirect(net::URLRequest* request,
139 const GURL& new_location) OVERRIDE {}
140 virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE {}
141 virtual void OnRawBytesRead(const net::URLRequest& request,
142 int bytes_read) OVERRIDE {}
143 virtual void OnCompleted(net::URLRequest* request, bool started) OVERRIDE {}
144 virtual void OnURLRequestDestroyed(net::URLRequest* request) OVERRIDE {}
145
146 virtual void OnPACScriptError(int line_number,
147 const base::string16& error) OVERRIDE {
148 }
149 virtual AuthRequiredResponse OnAuthRequired(
150 net::URLRequest* request,
151 const net::AuthChallengeInfo& auth_info,
152 const AuthCallback& callback,
153 net::AuthCredentials* credentials) OVERRIDE {
154 return AUTH_REQUIRED_RESPONSE_NO_ACTION;
155 }
156 virtual bool OnCanGetCookies(const net::URLRequest& request,
157 const net::CookieList& cookie_list) OVERRIDE {
158 StaticCookiePolicy::Type policy_type = g_accept_all_cookies ?
159 StaticCookiePolicy::ALLOW_ALL_COOKIES :
160 StaticCookiePolicy::BLOCK_SETTING_THIRD_PARTY_COOKIES;
161
162 StaticCookiePolicy policy(policy_type);
163 int rv = policy.CanGetCookies(
164 request.url(), request.first_party_for_cookies());
165 return rv == net::OK;
166 }
167 virtual bool OnCanSetCookie(const net::URLRequest& request,
168 const std::string& cookie_line,
169 net::CookieOptions* options) OVERRIDE {
170 StaticCookiePolicy::Type policy_type = g_accept_all_cookies ?
171 StaticCookiePolicy::ALLOW_ALL_COOKIES :
172 StaticCookiePolicy::BLOCK_SETTING_THIRD_PARTY_COOKIES;
173
174 StaticCookiePolicy policy(policy_type);
175 int rv = policy.CanSetCookie(
176 request.url(), request.first_party_for_cookies());
177 return rv == net::OK;
178 }
179 virtual bool OnCanAccessFile(const net::URLRequest& request,
180 const base::FilePath& path) const OVERRIDE {
181 return true;
182 }
183 virtual bool OnCanThrottleRequest(
184 const net::URLRequest& request) const OVERRIDE {
185 return false;
186 }
187
188 virtual int OnBeforeSocketStreamConnect(
189 net::SocketStream* stream,
190 const net::CompletionCallback& callback) OVERRIDE {
191 return net::OK;
192 }
193
194 virtual void OnRequestWaitStateChange(const net::URLRequest& request,
195 RequestWaitState state) OVERRIDE {
196 }
197 };
198
199 TestShellRequestContextParams* g_request_context_params = NULL;
200 TestShellRequestContext* g_request_context = NULL;
201 TestShellNetworkDelegate* g_network_delegate = NULL;
202 base::Thread* g_cache_thread = NULL;
203
204 //-----------------------------------------------------------------------------
205
206 struct FileOverHTTPParams {
207 FileOverHTTPParams(std::string in_file_path_template, GURL in_http_prefix)
208 : file_path_template(in_file_path_template),
209 http_prefix(in_http_prefix) {}
210
211 std::string file_path_template;
212 GURL http_prefix;
213 };
214
215 class FileOverHTTPPathMappings {
216 public:
217 FileOverHTTPPathMappings() : redirections_() {}
218 void AddMapping(std::string file_path_template, GURL http_prefix) {
219 redirections_.push_back(FileOverHTTPParams(file_path_template,
220 http_prefix));
221 }
222
223 const FileOverHTTPParams* ParamsForRequest(std::string request,
224 std::string::size_type& offset) {
225 std::vector<FileOverHTTPParams>::iterator it;
226 for (it = redirections_.begin(); it != redirections_.end(); ++it) {
227 offset = request.find(it->file_path_template);
228 if (offset != std::string::npos)
229 return &*it;
230 }
231 return 0;
232 }
233
234 const FileOverHTTPParams* ParamsForResponse(std::string response_url) {
235 std::vector<FileOverHTTPParams>::iterator it;
236 for (it = redirections_.begin(); it != redirections_.end(); ++it) {
237 if (response_url.find(it->http_prefix.spec()) == 0)
238 return &*it;
239 }
240 return 0;
241 }
242
243 private:
244 std::vector<FileOverHTTPParams> redirections_;
245 };
246
247 FileOverHTTPPathMappings* g_file_over_http_mappings = NULL;
248
249 //-----------------------------------------------------------------------------
250
251 class IOThread : public base::Thread {
252 public:
253 IOThread() : base::Thread("IOThread") {}
254
255 virtual ~IOThread() {
256 Stop();
257 }
258
259 virtual void Init() OVERRIDE {
260 if (g_request_context_params) {
261 g_request_context = new TestShellRequestContext(
262 g_request_context_params->cache_path,
263 g_request_context_params->cache_mode,
264 g_request_context_params->no_proxy);
265 delete g_request_context_params;
266 g_request_context_params = NULL;
267 } else {
268 g_request_context = new TestShellRequestContext();
269 }
270
271 g_network_delegate = new TestShellNetworkDelegate();
272 g_request_context->set_network_delegate(g_network_delegate);
273
274 SimpleAppCacheSystem::InitializeOnIOThread(g_request_context);
275 SimpleSocketStreamBridge::InitializeOnIOThread(g_request_context);
276 SimpleFileWriter::InitializeOnIOThread(g_request_context);
277 SimpleFileSystem::InitializeOnIOThread(
278 g_request_context->blob_storage_controller());
279 TestShellWebBlobRegistryImpl::InitializeOnIOThread(
280 g_request_context->blob_storage_controller());
281 }
282
283 virtual void CleanUp() OVERRIDE {
284 // In reverse order of initialization.
285 TestShellWebBlobRegistryImpl::Cleanup();
286 SimpleFileSystem::CleanupOnIOThread();
287 SimpleFileWriter::CleanupOnIOThread();
288 SimpleSocketStreamBridge::Cleanup();
289 SimpleAppCacheSystem::CleanupOnIOThread();
290
291 if (g_request_context) {
292 g_request_context->set_network_delegate(NULL);
293 delete g_request_context;
294 g_request_context = NULL;
295 }
296
297 if (g_network_delegate) {
298 delete g_network_delegate;
299 g_network_delegate = NULL;
300 }
301 }
302 };
303
304 IOThread* g_io_thread = NULL;
305
306 //-----------------------------------------------------------------------------
307
308 struct RequestParams {
309 std::string method;
310 GURL url;
311 GURL first_party_for_cookies;
312 GURL referrer;
313 WebKit::WebReferrerPolicy referrer_policy;
314 std::string headers;
315 int load_flags;
316 ResourceType::Type request_type;
317 int appcache_host_id;
318 bool download_to_file;
319 scoped_refptr<ResourceRequestBody> request_body;
320 };
321
322 // The interval for calls to RequestProxy::MaybeUpdateUploadProgress
323 static const int kUpdateUploadProgressIntervalMsec = 100;
324
325 // The RequestProxy does most of its work on the IO thread. The Start and
326 // Cancel methods are proxied over to the IO thread, where an net::URLRequest
327 // object is instantiated.
328 struct DeleteOnIOThread; // See below.
329 class RequestProxy
330 : public net::URLRequest::Delegate,
331 public base::RefCountedThreadSafe<RequestProxy, DeleteOnIOThread> {
332 public:
333 // Takes ownership of the params.
334 RequestProxy()
335 : download_to_file_(false),
336 buf_(new net::IOBuffer(kDataSize)),
337 last_upload_position_(0) {
338 }
339
340 void DropPeer() {
341 peer_ = NULL;
342 }
343
344 void Start(ResourceLoaderBridge::Peer* peer, RequestParams* params) {
345 peer_ = peer;
346 owner_loop_ = base::MessageLoop::current();
347
348 ConvertRequestParamsForFileOverHTTPIfNeeded(params);
349 // proxy over to the io thread
350 g_io_thread->message_loop()->PostTask(
351 FROM_HERE,
352 base::Bind(&RequestProxy::AsyncStart, this, params));
353 }
354
355 void Cancel() {
356 // proxy over to the io thread
357 g_io_thread->message_loop()->PostTask(
358 FROM_HERE,
359 base::Bind(&RequestProxy::AsyncCancel, this));
360 }
361
362 protected:
363 friend class base::DeleteHelper<RequestProxy>;
364 friend class base::RefCountedThreadSafe<RequestProxy>;
365 friend struct DeleteOnIOThread;
366
367 virtual ~RequestProxy() {
368 // Ensure we are deleted on the IO thread because base::Timer requires that.
369 // (guaranteed by the Traits class template parameter).
370 DCHECK(base::MessageLoop::current() == g_io_thread->message_loop());
371 }
372
373 // --------------------------------------------------------------------------
374 // The following methods are called on the owner's thread in response to
375 // various net::URLRequest callbacks. The event hooks, defined below, trigger
376 // these methods asynchronously.
377
378 void NotifyReceivedRedirect(const GURL& new_url,
379 const ResourceResponseInfo& info) {
380 bool has_new_first_party_for_cookies = false;
381 GURL new_first_party_for_cookies;
382 if (peer_ && peer_->OnReceivedRedirect(new_url, info,
383 &has_new_first_party_for_cookies,
384 &new_first_party_for_cookies)) {
385 g_io_thread->message_loop()->PostTask(
386 FROM_HERE,
387 base::Bind(&RequestProxy::AsyncFollowDeferredRedirect, this,
388 has_new_first_party_for_cookies,
389 new_first_party_for_cookies));
390 } else {
391 Cancel();
392 }
393 }
394
395 void NotifyReceivedResponse(const ResourceResponseInfo& info) {
396 if (peer_)
397 peer_->OnReceivedResponse(info);
398 }
399
400 void NotifyReceivedData(int bytes_read) {
401 if (!peer_)
402 return;
403
404 // Make a local copy of buf_, since AsyncReadData reuses it.
405 scoped_ptr<char[]> buf_copy(new char[bytes_read]);
406 memcpy(buf_copy.get(), buf_->data(), bytes_read);
407
408 // Continue reading more data into buf_
409 // Note: Doing this before notifying our peer ensures our load events get
410 // dispatched in a manner consistent with DumpRenderTree (and also avoids a
411 // race condition). If the order of the next 2 functions were reversed, the
412 // peer could generate new requests in reponse to the received data, which
413 // when run on the io thread, could race against this function in doing
414 // another InvokeLater. See bug 769249.
415 g_io_thread->message_loop()->PostTask(
416 FROM_HERE,
417 base::Bind(&RequestProxy::AsyncReadData, this));
418
419 peer_->OnReceivedData(buf_copy.get(), bytes_read, -1);
420 }
421
422 void NotifyDownloadedData(int bytes_read) {
423 if (!peer_)
424 return;
425
426 // Continue reading more data, see the comment in NotifyReceivedData.
427 g_io_thread->message_loop()->PostTask(
428 FROM_HERE,
429 base::Bind(&RequestProxy::AsyncReadData, this));
430
431 peer_->OnDownloadedData(bytes_read);
432 }
433
434 void NotifyCompletedRequest(int error_code,
435 const std::string& security_info,
436 const base::TimeTicks& complete_time) {
437 if (peer_) {
438 peer_->OnCompletedRequest(error_code, false, security_info,
439 complete_time);
440 DropPeer(); // ensure no further notifications
441 }
442 }
443
444 void NotifyUploadProgress(uint64 position, uint64 size) {
445 if (peer_)
446 peer_->OnUploadProgress(position, size);
447 }
448
449 // --------------------------------------------------------------------------
450 // The following methods are called on the io thread. They correspond to
451 // actions performed on the owner's thread.
452
453 void AsyncStart(RequestParams* params) {
454 request_.reset(g_request_context->CreateRequest(params->url, this));
455 request_->set_method(params->method);
456 request_->set_first_party_for_cookies(params->first_party_for_cookies);
457 request_->SetReferrer(params->referrer.spec());
458 webkit_glue::ConfigureURLRequestForReferrerPolicy(
459 request_.get(), params->referrer_policy);
460 net::HttpRequestHeaders headers;
461 headers.AddHeadersFromString(params->headers);
462 request_->SetExtraRequestHeaders(headers);
463 request_->set_load_flags(params->load_flags);
464 if (params->request_body.get()) {
465 request_->set_upload(make_scoped_ptr(
466 params->request_body->ResolveElementsAndCreateUploadDataStream(
467 static_cast<TestShellRequestContext*>(g_request_context)
468 ->blob_storage_controller(),
469 static_cast<TestShellRequestContext*>(g_request_context)
470 ->file_system_context(),
471 base::MessageLoopProxy::current().get())));
472 }
473 SimpleAppCacheSystem::SetExtraRequestInfo(
474 request_.get(), params->appcache_host_id, params->request_type);
475
476 download_to_file_ = params->download_to_file;
477 if (download_to_file_) {
478 base::FilePath path;
479 if (file_util::CreateTemporaryFile(&path)) {
480 downloaded_file_ = ShareableFileReference::GetOrCreate(
481 path,
482 ShareableFileReference::DELETE_ON_FINAL_RELEASE,
483 base::MessageLoopProxy::current().get());
484 file_stream_.reset(new net::FileStream(NULL));
485 file_stream_->OpenSync(
486 path, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE);
487 }
488 }
489
490 request_->Start();
491
492 if (request_->has_upload() &&
493 params->load_flags & net::LOAD_ENABLE_UPLOAD_PROGRESS) {
494 upload_progress_timer_.Start(FROM_HERE,
495 base::TimeDelta::FromMilliseconds(kUpdateUploadProgressIntervalMsec),
496 this, &RequestProxy::MaybeUpdateUploadProgress);
497 }
498
499 delete params;
500 }
501
502 void AsyncCancel() {
503 // This can be null in cases where the request is already done.
504 if (!request_)
505 return;
506
507 request_->Cancel();
508 Done();
509 }
510
511 void AsyncFollowDeferredRedirect(bool has_new_first_party_for_cookies,
512 const GURL& new_first_party_for_cookies) {
513 // This can be null in cases where the request is already done.
514 if (!request_)
515 return;
516
517 if (has_new_first_party_for_cookies)
518 request_->set_first_party_for_cookies(new_first_party_for_cookies);
519 request_->FollowDeferredRedirect();
520 }
521
522 void AsyncReadData() {
523 // This can be null in cases where the request is already done.
524 if (!request_)
525 return;
526
527 if (request_->status().is_success()) {
528 int bytes_read;
529 if (request_->Read(buf_.get(), kDataSize, &bytes_read) && bytes_read) {
530 OnReceivedData(bytes_read);
531 } else if (!request_->status().is_io_pending()) {
532 Done();
533 } // else wait for OnReadCompleted
534 } else {
535 Done();
536 }
537 }
538
539 // --------------------------------------------------------------------------
540 // The following methods are event hooks (corresponding to net::URLRequest
541 // callbacks) that run on the IO thread. They are designed to be overridden
542 // by the SyncRequestProxy subclass.
543
544 virtual void OnReceivedRedirect(
545 const GURL& new_url,
546 const ResourceResponseInfo& info,
547 bool* defer_redirect) {
548 *defer_redirect = true; // See AsyncFollowDeferredRedirect
549 owner_loop_->PostTask(
550 FROM_HERE,
551 base::Bind(&RequestProxy::NotifyReceivedRedirect, this, new_url, info));
552 }
553
554 virtual void OnReceivedResponse(
555 const ResourceResponseInfo& info) {
556 owner_loop_->PostTask(
557 FROM_HERE,
558 base::Bind(&RequestProxy::NotifyReceivedResponse, this, info));
559 }
560
561 virtual void OnReceivedData(int bytes_read) {
562 if (download_to_file_) {
563 file_stream_->WriteSync(buf_->data(), bytes_read);
564 owner_loop_->PostTask(
565 FROM_HERE,
566 base::Bind(&RequestProxy::NotifyDownloadedData, this, bytes_read));
567 return;
568 }
569
570 owner_loop_->PostTask(
571 FROM_HERE,
572 base::Bind(&RequestProxy::NotifyReceivedData, this, bytes_read));
573 }
574
575 virtual void OnCompletedRequest(int error_code,
576 const std::string& security_info,
577 const base::TimeTicks& complete_time) {
578 if (download_to_file_)
579 file_stream_.reset();
580 owner_loop_->PostTask(
581 FROM_HERE,
582 base::Bind(&RequestProxy::NotifyCompletedRequest, this, error_code,
583 security_info, complete_time));
584 }
585
586 // --------------------------------------------------------------------------
587 // net::URLRequest::Delegate implementation:
588
589 virtual void OnReceivedRedirect(net::URLRequest* request,
590 const GURL& new_url,
591 bool* defer_redirect) OVERRIDE {
592 DCHECK(request->status().is_success());
593 ResourceResponseInfo info;
594 PopulateResponseInfo(request, &info);
595 // For file protocol, should never have the redirect situation.
596 DCHECK(!ConvertResponseInfoForFileOverHTTPIfNeeded(request, &info));
597 OnReceivedRedirect(new_url, info, defer_redirect);
598 }
599
600 virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE {
601 if (request->status().is_success()) {
602 ResourceResponseInfo info;
603 PopulateResponseInfo(request, &info);
604 // If encountering error when requesting the file, cancel the request.
605 if (ConvertResponseInfoForFileOverHTTPIfNeeded(request, &info) &&
606 failed_file_request_status_.get()) {
607 AsyncCancel();
608 } else {
609 OnReceivedResponse(info);
610 AsyncReadData(); // start reading
611 }
612 } else {
613 Done();
614 }
615 }
616
617 virtual void OnSSLCertificateError(net::URLRequest* request,
618 const net::SSLInfo& ssl_info,
619 bool fatal) OVERRIDE {
620 // Allow all certificate errors.
621 request->ContinueDespiteLastError();
622 }
623
624 virtual void OnReadCompleted(net::URLRequest* request,
625 int bytes_read) OVERRIDE {
626 if (request->status().is_success() && bytes_read > 0) {
627 OnReceivedData(bytes_read);
628 } else {
629 Done();
630 }
631 }
632
633 // --------------------------------------------------------------------------
634 // Helpers and data:
635
636 void Done() {
637 if (upload_progress_timer_.IsRunning()) {
638 MaybeUpdateUploadProgress();
639 upload_progress_timer_.Stop();
640 }
641 DCHECK(request_.get());
642 // If |failed_file_request_status_| is not empty, which means the request
643 // was a file request and encountered an error, then we need to use the
644 // |failed_file_request_status_|. Otherwise use request_'s status.
645 OnCompletedRequest(failed_file_request_status_.get() ?
646 failed_file_request_status_->error() :
647 request_->status().error(),
648 std::string(), base::TimeTicks::Now());
649 request_.reset(); // destroy on the io thread
650 }
651
652 // Called on the IO thread.
653 void MaybeUpdateUploadProgress() {
654 // If a redirect is received upload is cancelled in net::URLRequest, we
655 // should try to stop the |upload_progress_timer_| timer and return.
656 if (!request_->has_upload()) {
657 if (upload_progress_timer_.IsRunning())
658 upload_progress_timer_.Stop();
659 return;
660 }
661
662 net::UploadProgress progress = request_->GetUploadProgress();
663 if (progress.position() == last_upload_position_)
664 return; // no progress made since last time
665
666 const uint64 kHalfPercentIncrements = 200;
667 const base::TimeDelta kOneSecond = base::TimeDelta::FromMilliseconds(1000);
668
669 uint64 amt_since_last = progress.position() - last_upload_position_;
670 base::TimeDelta time_since_last = base::TimeTicks::Now() -
671 last_upload_ticks_;
672
673 bool is_finished = (progress.size() == progress.position());
674 bool enough_new_progress = (amt_since_last > (progress.size() /
675 kHalfPercentIncrements));
676 bool too_much_time_passed = time_since_last > kOneSecond;
677
678 if (is_finished || enough_new_progress || too_much_time_passed) {
679 owner_loop_->PostTask(
680 FROM_HERE,
681 base::Bind(&RequestProxy::NotifyUploadProgress, this,
682 progress.position(), progress.size()));
683 last_upload_ticks_ = base::TimeTicks::Now();
684 last_upload_position_ = progress.position();
685 }
686 }
687
688 void PopulateResponseInfo(net::URLRequest* request,
689 ResourceResponseInfo* info) const {
690 if (request->load_flags() & net::LOAD_ENABLE_LOAD_TIMING)
691 request->GetLoadTimingInfo(&info->load_timing);
692 info->request_time = request->request_time();
693 info->response_time = request->response_time();
694 info->headers = request->response_headers();
695 request->GetMimeType(&info->mime_type);
696 request->GetCharset(&info->charset);
697 info->content_length = request->GetExpectedContentSize();
698 if (downloaded_file_.get())
699 info->download_file_path = downloaded_file_->path();
700 SimpleAppCacheSystem::GetExtraResponseInfo(
701 request,
702 &info->appcache_id,
703 &info->appcache_manifest_url);
704 }
705
706 // Called on owner thread
707 void ConvertRequestParamsForFileOverHTTPIfNeeded(RequestParams* params) {
708 // Reset the status.
709 file_url_prefix_ .clear();
710 failed_file_request_status_.reset();
711 // Only do this when enabling file-over-http and request is file scheme.
712 if (!g_file_over_http_mappings || !params->url.SchemeIsFile())
713 return;
714
715 // For file protocol, method must be GET, POST or NULL.
716 DCHECK(params->method == "GET" || params->method == "POST" ||
717 params->method.empty());
718 DCHECK(!params->download_to_file);
719
720 if (params->method.empty())
721 params->method = "GET";
722 std::string original_request = params->url.spec();
723
724 std::string::size_type offset = 0;
725 const FileOverHTTPParams* redirection_params =
726 g_file_over_http_mappings->ParamsForRequest(original_request, offset);
727 if (!redirection_params)
728 return;
729
730 offset += redirection_params->file_path_template.size();
731 file_url_prefix_ = original_request.substr(0, offset);
732 original_request.replace(0, offset,
733 redirection_params->http_prefix.spec());
734 params->url = GURL(original_request);
735 params->first_party_for_cookies = params->url;
736 // For file protocol, nerver use cache.
737 params->load_flags = net::LOAD_BYPASS_CACHE;
738 }
739
740 // Called on IO thread.
741 bool ConvertResponseInfoForFileOverHTTPIfNeeded(net::URLRequest* request,
742 ResourceResponseInfo* info) {
743 // Only do this when enabling file-over-http and request url
744 // matches the http prefix for file-over-http feature.
745 if (!g_file_over_http_mappings || file_url_prefix_.empty())
746 return false;
747
748 std::string original_request = request->url().spec();
749 DCHECK(!original_request.empty());
750
751 const FileOverHTTPParams* redirection_params =
752 g_file_over_http_mappings->ParamsForResponse(original_request);
753 DCHECK(redirection_params);
754
755 std::string http_prefix = redirection_params->http_prefix.spec();
756 DCHECK(StartsWithASCII(original_request, http_prefix, true));
757
758 // Get the File URL.
759 original_request.replace(0, http_prefix.size(), file_url_prefix_);
760
761 base::FilePath file_path;
762 if (!net::FileURLToFilePath(GURL(original_request), &file_path)) {
763 NOTREACHED();
764 }
765
766 info->mime_type.clear();
767 DCHECK(info->headers.get());
768 int status_code = info->headers->response_code();
769 // File protocol does not support response headers.
770 info->headers = NULL;
771 if (200 == status_code) {
772 // Don't use the MIME type from HTTP server, use net::GetMimeTypeFromFile
773 // instead.
774 net::GetMimeTypeFromFile(file_path, &info->mime_type);
775 } else {
776 // If the file does not exist, immediately call OnCompletedRequest with
777 // setting URLRequestStatus to FAILED.
778 DCHECK(status_code == 404 || status_code == 403);
779 if (status_code == 404) {
780 failed_file_request_status_.reset(
781 new net::URLRequestStatus(net::URLRequestStatus::FAILED,
782 net::ERR_FILE_NOT_FOUND));
783 } else {
784 failed_file_request_status_.reset(
785 new net::URLRequestStatus(net::URLRequestStatus::FAILED,
786 net::ERR_ACCESS_DENIED));
787 }
788 }
789 return true;
790 }
791
792 scoped_ptr<net::URLRequest> request_;
793
794 // Support for request.download_to_file behavior.
795 bool download_to_file_;
796 scoped_ptr<net::FileStream> file_stream_;
797 scoped_refptr<ShareableFileReference> downloaded_file_;
798
799 // Size of our async IO data buffers
800 static const int kDataSize = 16*1024;
801
802 // read buffer for async IO
803 scoped_refptr<net::IOBuffer> buf_;
804
805 base::MessageLoop* owner_loop_;
806
807 // This is our peer in WebKit (implemented as ResourceHandleInternal). We do
808 // not manage its lifetime, and we may only access it from the owner's
809 // message loop (owner_loop_).
810 ResourceLoaderBridge::Peer* peer_;
811
812 // Timer used to pull upload progress info.
813 base::RepeatingTimer<RequestProxy> upload_progress_timer_;
814
815 // Info used to determine whether or not to send an upload progress update.
816 uint64 last_upload_position_;
817 base::TimeTicks last_upload_ticks_;
818
819 // Save the real FILE URL prefix for the FILE URL which converts to HTTP URL.
820 std::string file_url_prefix_;
821 // Save a failed file request status to pass it to webkit.
822 scoped_ptr<net::URLRequestStatus> failed_file_request_status_;
823 };
824
825 // Helper guaranteeing deletion on the IO thread (like
826 // content::BrowserThread::DeleteOnIOThread, but without the dependency).
827 struct DeleteOnIOThread {
828 static void Destruct(const RequestProxy* obj) {
829 if (base::MessageLoop::current() == g_io_thread->message_loop())
830 delete obj;
831 else
832 g_io_thread->message_loop()->DeleteSoon(FROM_HERE, obj);
833 }
834 };
835
836 //-----------------------------------------------------------------------------
837
838 class SyncRequestProxy : public RequestProxy {
839 public:
840 explicit SyncRequestProxy(ResourceLoaderBridge::SyncLoadResponse* result)
841 : result_(result), event_(true, false) {
842 }
843
844 void WaitForCompletion() {
845 event_.Wait();
846 }
847
848 // --------------------------------------------------------------------------
849 // RequestProxy event hooks that run on the IO thread:
850
851 virtual void OnReceivedRedirect(
852 const GURL& new_url,
853 const ResourceResponseInfo& info,
854 bool* defer_redirect) OVERRIDE {
855 // TODO(darin): It would be much better if this could live in WebCore, but
856 // doing so requires API changes at all levels. Similar code exists in
857 // WebCore/platform/network/cf/ResourceHandleCFNet.cpp :-(
858 if (new_url.GetOrigin() != result_->url.GetOrigin()) {
859 DLOG(WARNING) << "Cross origin redirect denied";
860 Cancel();
861 return;
862 }
863 result_->url = new_url;
864 }
865
866 virtual void OnReceivedResponse(const ResourceResponseInfo& info) OVERRIDE {
867 *static_cast<ResourceResponseInfo*>(result_) = info;
868 }
869
870 virtual void OnReceivedData(int bytes_read) OVERRIDE {
871 if (download_to_file_)
872 file_stream_->WriteSync(buf_->data(), bytes_read);
873 else
874 result_->data.append(buf_->data(), bytes_read);
875 AsyncReadData(); // read more (may recurse)
876 }
877
878 virtual void OnCompletedRequest(
879 int error_code,
880 const std::string& security_info,
881 const base::TimeTicks& complete_time) OVERRIDE {
882 if (download_to_file_)
883 file_stream_.reset();
884 result_->error_code = error_code;
885 event_.Signal();
886 }
887
888 protected:
889 virtual ~SyncRequestProxy() {}
890
891 private:
892 ResourceLoaderBridge::SyncLoadResponse* result_;
893 base::WaitableEvent event_;
894 };
895
896 //-----------------------------------------------------------------------------
897
898 class ResourceLoaderBridgeImpl : public ResourceLoaderBridge {
899 public:
900 ResourceLoaderBridgeImpl(
901 const webkit_glue::ResourceLoaderBridge::RequestInfo& request_info)
902 : params_(new RequestParams),
903 proxy_(NULL) {
904 params_->method = request_info.method;
905 params_->url = request_info.url;
906 params_->first_party_for_cookies = request_info.first_party_for_cookies;
907 params_->referrer = request_info.referrer;
908 params_->referrer_policy = request_info.referrer_policy;
909 params_->headers = request_info.headers;
910 params_->load_flags = request_info.load_flags;
911 params_->request_type = request_info.request_type;
912 params_->appcache_host_id = request_info.appcache_host_id;
913 params_->download_to_file = request_info.download_to_file;
914 }
915
916 virtual ~ResourceLoaderBridgeImpl() {
917 if (proxy_) {
918 proxy_->DropPeer();
919 // Let the proxy die on the IO thread
920 g_io_thread->message_loop()->ReleaseSoon(FROM_HERE, proxy_);
921 }
922 }
923
924 // --------------------------------------------------------------------------
925 // ResourceLoaderBridge implementation:
926
927 virtual void SetRequestBody(ResourceRequestBody* request_body) OVERRIDE {
928 DCHECK(params_.get());
929 DCHECK(!params_->request_body.get());
930 params_->request_body = request_body;
931 }
932
933 virtual bool Start(Peer* peer) OVERRIDE {
934 DCHECK(!proxy_);
935
936 if (!SimpleResourceLoaderBridge::EnsureIOThread())
937 return false;
938
939 proxy_ = new RequestProxy();
940 proxy_->AddRef();
941
942 proxy_->Start(peer, params_.release());
943
944 return true; // Any errors will be reported asynchronously.
945 }
946
947 virtual void Cancel() OVERRIDE {
948 DCHECK(proxy_);
949 proxy_->Cancel();
950 }
951
952 virtual void SetDefersLoading(bool value) OVERRIDE {
953 // TODO(darin): implement me
954 }
955
956 virtual void SyncLoad(SyncLoadResponse* response) OVERRIDE {
957 DCHECK(!proxy_);
958
959 if (!SimpleResourceLoaderBridge::EnsureIOThread())
960 return;
961
962 // this may change as the result of a redirect
963 response->url = params_->url;
964
965 proxy_ = new SyncRequestProxy(response);
966 proxy_->AddRef();
967
968 proxy_->Start(NULL, params_.release());
969
970 static_cast<SyncRequestProxy*>(proxy_)->WaitForCompletion();
971 }
972
973 virtual void DidChangePriority(net::RequestPriority new_priority) OVERRIDE {
974 // Not really needed for DRT.
975 }
976
977 private:
978 // Ownership of params_ is transfered to the proxy when the proxy is created.
979 scoped_ptr<RequestParams> params_;
980
981 // The request proxy is allocated when we start the request, and then it
982 // sticks around until this ResourceLoaderBridge is destroyed.
983 RequestProxy* proxy_;
984 };
985
986 //-----------------------------------------------------------------------------
987
988 class CookieSetter : public base::RefCountedThreadSafe<CookieSetter> {
989 public:
990 void Set(const GURL& url, const std::string& cookie) {
991 DCHECK(base::MessageLoop::current() == g_io_thread->message_loop());
992 g_request_context->cookie_store()->SetCookieWithOptionsAsync(
993 url, cookie, net::CookieOptions(),
994 net::CookieStore::SetCookiesCallback());
995 }
996
997 private:
998 friend class base::RefCountedThreadSafe<CookieSetter>;
999 ~CookieSetter() {}
1000 };
1001
1002 class CookieGetter : public base::RefCountedThreadSafe<CookieGetter> {
1003 public:
1004 CookieGetter() : event_(false, false) {
1005 }
1006
1007 void Get(const GURL& url) {
1008 g_request_context->cookie_store()->GetCookiesWithOptionsAsync(
1009 url, net::CookieOptions(),
1010 base::Bind(&CookieGetter::OnGetCookies, this));
1011 }
1012
1013 std::string GetResult() {
1014 event_.Wait();
1015 return result_;
1016 }
1017
1018 private:
1019 friend class base::RefCountedThreadSafe<CookieGetter>;
1020 ~CookieGetter() {}
1021
1022 void OnGetCookies(const std::string& cookie_line) {
1023 result_ = cookie_line;
1024 event_.Signal();
1025 }
1026
1027 base::WaitableEvent event_;
1028 std::string result_;
1029 };
1030
1031 } // anonymous namespace
1032
1033 //-----------------------------------------------------------------------------
1034
1035 // static
1036 void SimpleResourceLoaderBridge::Init(
1037 const base::FilePath& cache_path,
1038 net::HttpCache::Mode cache_mode,
1039 bool no_proxy) {
1040 // Make sure to stop any existing IO thread since it may be using the
1041 // current request context.
1042 Shutdown();
1043
1044 DCHECK(!g_request_context_params);
1045 DCHECK(!g_request_context);
1046 DCHECK(!g_network_delegate);
1047 DCHECK(!g_io_thread);
1048
1049 g_request_context_params = new TestShellRequestContextParams(
1050 cache_path, cache_mode, no_proxy);
1051 }
1052
1053 // static
1054 void SimpleResourceLoaderBridge::Shutdown() {
1055 if (g_io_thread) {
1056 delete g_io_thread;
1057 g_io_thread = NULL;
1058
1059 DCHECK(g_cache_thread);
1060 delete g_cache_thread;
1061 g_cache_thread = NULL;
1062
1063 DCHECK(!g_request_context) << "should have been nulled by thread dtor";
1064 DCHECK(!g_network_delegate) << "should have been nulled by thread dtor";
1065 } else {
1066 delete g_request_context_params;
1067 g_request_context_params = NULL;
1068
1069 delete g_file_over_http_mappings;
1070 g_file_over_http_mappings = NULL;
1071 }
1072 }
1073
1074 // static
1075 void SimpleResourceLoaderBridge::SetCookie(const GURL& url,
1076 const GURL& first_party_for_cookies,
1077 const std::string& cookie) {
1078 // Proxy to IO thread to synchronize w/ network loading.
1079
1080 if (!EnsureIOThread()) {
1081 NOTREACHED();
1082 return;
1083 }
1084
1085 scoped_refptr<CookieSetter> cookie_setter(new CookieSetter());
1086 g_io_thread->message_loop()->PostTask(
1087 FROM_HERE,
1088 base::Bind(&CookieSetter::Set, cookie_setter.get(), url, cookie));
1089 }
1090
1091 // static
1092 std::string SimpleResourceLoaderBridge::GetCookies(
1093 const GURL& url, const GURL& first_party_for_cookies) {
1094 // Proxy to IO thread to synchronize w/ network loading
1095
1096 if (!EnsureIOThread()) {
1097 NOTREACHED();
1098 return std::string();
1099 }
1100
1101 scoped_refptr<CookieGetter> getter(new CookieGetter());
1102
1103 g_io_thread->message_loop()->PostTask(
1104 FROM_HERE,
1105 base::Bind(&CookieGetter::Get, getter.get(), url));
1106
1107 return getter->GetResult();
1108 }
1109
1110 // static
1111 bool SimpleResourceLoaderBridge::EnsureIOThread() {
1112 if (g_io_thread)
1113 return true;
1114
1115 #if defined(OS_MACOSX) || defined(OS_WIN)
1116 // We want to be sure to init NSPR on the main thread.
1117 crypto::EnsureNSPRInit();
1118 #endif
1119
1120 // Create the cache thread. We want the cache thread to outlive the IO thread,
1121 // so its lifetime is bonded to the IO thread lifetime.
1122 DCHECK(!g_cache_thread);
1123 g_cache_thread = new base::Thread("cache");
1124 CHECK(g_cache_thread->StartWithOptions(
1125 base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
1126
1127 g_io_thread = new IOThread();
1128 base::Thread::Options options;
1129 options.message_loop_type = base::MessageLoop::TYPE_IO;
1130 return g_io_thread->StartWithOptions(options);
1131 }
1132
1133 // static
1134 void SimpleResourceLoaderBridge::SetAcceptAllCookies(bool accept_all_cookies) {
1135 g_accept_all_cookies = accept_all_cookies;
1136 }
1137
1138 // static
1139 scoped_refptr<base::MessageLoopProxy>
1140 SimpleResourceLoaderBridge::GetCacheThread() {
1141 return g_cache_thread->message_loop_proxy();
1142 }
1143
1144 // static
1145 scoped_refptr<base::MessageLoopProxy>
1146 SimpleResourceLoaderBridge::GetIoThread() {
1147 if (!EnsureIOThread()) {
1148 LOG(DFATAL) << "Failed to create IO thread.";
1149 return NULL;
1150 }
1151 return g_io_thread->message_loop_proxy();
1152 }
1153
1154 // static
1155 void SimpleResourceLoaderBridge::AllowFileOverHTTP(
1156 const std::string& file_path_template, const GURL& http_prefix) {
1157 DCHECK(!file_path_template.empty());
1158 DCHECK(http_prefix.is_valid() &&
1159 (http_prefix.SchemeIs("http") || http_prefix.SchemeIs("https")));
1160 if (!g_file_over_http_mappings)
1161 g_file_over_http_mappings = new FileOverHTTPPathMappings();
1162 g_file_over_http_mappings->AddMapping(file_path_template, http_prefix);
1163 }
1164
1165 // static
1166 webkit_glue::ResourceLoaderBridge* SimpleResourceLoaderBridge::Create(
1167 const webkit_glue::ResourceLoaderBridge::RequestInfo& request_info) {
1168 return new ResourceLoaderBridgeImpl(request_info);
1169 }
OLDNEW
« no previous file with comments | « webkit/support/simple_resource_loader_bridge.h ('k') | webkit/support/simple_socket_stream_bridge.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698