| OLD | NEW |
| (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 } | |
| OLD | NEW |