| Index: webkit/tools/test_shell/simple_resource_loader_bridge.cc
|
| diff --git a/webkit/tools/test_shell/simple_resource_loader_bridge.cc b/webkit/tools/test_shell/simple_resource_loader_bridge.cc
|
| deleted file mode 100644
|
| index 127c858851c7cb292d77d10d6bc1d993b64f9e56..0000000000000000000000000000000000000000
|
| --- a/webkit/tools/test_shell/simple_resource_loader_bridge.cc
|
| +++ /dev/null
|
| @@ -1,1168 +0,0 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -//
|
| -// This file contains an implementation of the ResourceLoaderBridge class.
|
| -// The class is implemented using net::URLRequest, meaning it is a "simple"
|
| -// version that directly issues requests. The more complicated one used in the
|
| -// browser uses IPC.
|
| -//
|
| -// Because net::URLRequest only provides an asynchronous resource loading API,
|
| -// this file makes use of net::URLRequest from a background IO thread. Requests
|
| -// for cookies and synchronously loaded resources result in the main thread of
|
| -// the application blocking until the IO thread completes the operation. (See
|
| -// GetCookies and SyncLoad)
|
| -//
|
| -// Main thread IO thread
|
| -// ----------- ---------
|
| -// ResourceLoaderBridge <---o---------> RequestProxy (normal case)
|
| -// \ -> net::URLRequest
|
| -// o-------> SyncRequestProxy (synchronous case)
|
| -// -> net::URLRequest
|
| -// SetCookie <------------------------> CookieSetter
|
| -// -> net_util::SetCookie
|
| -// GetCookies <-----------------------> CookieGetter
|
| -// -> net_util::GetCookies
|
| -//
|
| -// NOTE: The implementation in this file may be used to have WebKit fetch
|
| -// resources in-process. For example, it is handy for building a single-
|
| -// process WebKit embedding (e.g., test_shell) that can use net::URLRequest to
|
| -// perform URL loads. See renderer/resource_dispatcher.h for details on an
|
| -// alternate implementation that defers fetching to another process.
|
| -
|
| -#include "webkit/tools/test_shell/simple_resource_loader_bridge.h"
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/compiler_specific.h"
|
| -#include "base/file_util.h"
|
| -#include "base/files/file_path.h"
|
| -#include "base/logging.h"
|
| -#include "base/memory/ref_counted.h"
|
| -#include "base/message_loop.h"
|
| -#include "base/message_loop_proxy.h"
|
| -#include "base/string_util.h"
|
| -#include "base/synchronization/waitable_event.h"
|
| -#include "base/threading/thread.h"
|
| -#include "base/time.h"
|
| -#include "base/timer.h"
|
| -#include "net/base/file_stream.h"
|
| -#include "net/base/io_buffer.h"
|
| -#include "net/base/load_flags.h"
|
| -#include "net/base/mime_util.h"
|
| -#include "net/base/net_errors.h"
|
| -#include "net/base/net_util.h"
|
| -#include "net/base/network_delegate.h"
|
| -#include "net/base/static_cookie_policy.h"
|
| -#include "net/base/upload_data_stream.h"
|
| -#include "net/cookies/cookie_store.h"
|
| -#include "net/http/http_cache.h"
|
| -#include "net/http/http_request_headers.h"
|
| -#include "net/http/http_response_headers.h"
|
| -#include "net/url_request/url_request.h"
|
| -#include "net/url_request/url_request_context.h"
|
| -#include "net/url_request/url_request_job.h"
|
| -#include "webkit/appcache/appcache_interfaces.h"
|
| -#include "webkit/browser/blob/blob_storage_controller.h"
|
| -#include "webkit/browser/blob/blob_url_request_job.h"
|
| -#include "webkit/browser/fileapi/file_system_context.h"
|
| -#include "webkit/browser/fileapi/file_system_dir_url_request_job.h"
|
| -#include "webkit/browser/fileapi/file_system_url_request_job.h"
|
| -#include "webkit/common/blob/shareable_file_reference.h"
|
| -#include "webkit/glue/resource_loader_bridge.h"
|
| -#include "webkit/glue/resource_request_body.h"
|
| -#include "webkit/glue/webkit_glue.h"
|
| -#include "webkit/tools/test_shell/simple_appcache_system.h"
|
| -#include "webkit/tools/test_shell/simple_file_system.h"
|
| -#include "webkit/tools/test_shell/simple_file_writer.h"
|
| -#include "webkit/tools/test_shell/simple_socket_stream_bridge.h"
|
| -#include "webkit/tools/test_shell/test_shell_request_context.h"
|
| -#include "webkit/tools/test_shell/test_shell_webblobregistry_impl.h"
|
| -
|
| -#if defined(OS_MACOSX) || defined(OS_WIN)
|
| -#include "crypto/nss_util.h"
|
| -#endif
|
| -
|
| -using webkit_glue::ResourceLoaderBridge;
|
| -using webkit_glue::ResourceRequestBody;
|
| -using webkit_glue::ResourceResponseInfo;
|
| -using net::StaticCookiePolicy;
|
| -using net::HttpResponseHeaders;
|
| -using webkit_blob::ShareableFileReference;
|
| -
|
| -namespace {
|
| -
|
| -struct TestShellRequestContextParams {
|
| - TestShellRequestContextParams(
|
| - const base::FilePath& in_cache_path,
|
| - net::HttpCache::Mode in_cache_mode,
|
| - bool in_no_proxy)
|
| - : cache_path(in_cache_path),
|
| - cache_mode(in_cache_mode),
|
| - no_proxy(in_no_proxy) {}
|
| -
|
| - base::FilePath cache_path;
|
| - net::HttpCache::Mode cache_mode;
|
| - bool no_proxy;
|
| -};
|
| -
|
| -//-----------------------------------------------------------------------------
|
| -
|
| -bool g_accept_all_cookies = false;
|
| -
|
| -class TestShellNetworkDelegate : public net::NetworkDelegate {
|
| - public:
|
| - virtual ~TestShellNetworkDelegate() {}
|
| -
|
| - protected:
|
| - // net::NetworkDelegate implementation.
|
| - virtual int OnBeforeURLRequest(net::URLRequest* request,
|
| - const net::CompletionCallback& callback,
|
| - GURL* new_url) OVERRIDE {
|
| - return net::OK;
|
| - }
|
| - virtual int OnBeforeSendHeaders(net::URLRequest* request,
|
| - const net::CompletionCallback& callback,
|
| - net::HttpRequestHeaders* headers) OVERRIDE {
|
| - return net::OK;
|
| - }
|
| - virtual void OnSendHeaders(net::URLRequest* request,
|
| - const net::HttpRequestHeaders& headers) OVERRIDE {}
|
| - virtual int OnHeadersReceived(
|
| - net::URLRequest* request,
|
| - const net::CompletionCallback& callback,
|
| - const net::HttpResponseHeaders* original_response_headers,
|
| - scoped_refptr<net::HttpResponseHeaders>*
|
| - override_response_headers) OVERRIDE {
|
| - return net::OK;
|
| - }
|
| - virtual void OnBeforeRedirect(net::URLRequest* request,
|
| - const GURL& new_location) OVERRIDE {}
|
| - virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE {}
|
| - virtual void OnRawBytesRead(const net::URLRequest& request,
|
| - int bytes_read) OVERRIDE {}
|
| - virtual void OnCompleted(net::URLRequest* request, bool started) OVERRIDE {}
|
| - virtual void OnURLRequestDestroyed(net::URLRequest* request) OVERRIDE {}
|
| -
|
| - virtual void OnPACScriptError(int line_number,
|
| - const base::string16& error) OVERRIDE {
|
| - }
|
| - virtual AuthRequiredResponse OnAuthRequired(
|
| - net::URLRequest* request,
|
| - const net::AuthChallengeInfo& auth_info,
|
| - const AuthCallback& callback,
|
| - net::AuthCredentials* credentials) OVERRIDE {
|
| - return AUTH_REQUIRED_RESPONSE_NO_ACTION;
|
| - }
|
| - virtual bool OnCanGetCookies(const net::URLRequest& request,
|
| - const net::CookieList& cookie_list) OVERRIDE {
|
| - StaticCookiePolicy::Type policy_type = g_accept_all_cookies ?
|
| - StaticCookiePolicy::ALLOW_ALL_COOKIES :
|
| - StaticCookiePolicy::BLOCK_SETTING_THIRD_PARTY_COOKIES;
|
| -
|
| - StaticCookiePolicy policy(policy_type);
|
| - int rv = policy.CanGetCookies(
|
| - request.url(), request.first_party_for_cookies());
|
| - return rv == net::OK;
|
| - }
|
| - virtual bool OnCanSetCookie(const net::URLRequest& request,
|
| - const std::string& cookie_line,
|
| - net::CookieOptions* options) OVERRIDE {
|
| - StaticCookiePolicy::Type policy_type = g_accept_all_cookies ?
|
| - StaticCookiePolicy::ALLOW_ALL_COOKIES :
|
| - StaticCookiePolicy::BLOCK_SETTING_THIRD_PARTY_COOKIES;
|
| -
|
| - StaticCookiePolicy policy(policy_type);
|
| - int rv = policy.CanSetCookie(
|
| - request.url(), request.first_party_for_cookies());
|
| - return rv == net::OK;
|
| - }
|
| - virtual bool OnCanAccessFile(const net::URLRequest& request,
|
| - const base::FilePath& path) const OVERRIDE {
|
| - return true;
|
| - }
|
| - virtual bool OnCanThrottleRequest(
|
| - const net::URLRequest& request) const OVERRIDE {
|
| - return false;
|
| - }
|
| -
|
| - virtual int OnBeforeSocketStreamConnect(
|
| - net::SocketStream* stream,
|
| - const net::CompletionCallback& callback) OVERRIDE {
|
| - return net::OK;
|
| - }
|
| -
|
| - virtual void OnRequestWaitStateChange(const net::URLRequest& request,
|
| - RequestWaitState state) OVERRIDE {
|
| - }
|
| -};
|
| -
|
| -TestShellRequestContextParams* g_request_context_params = NULL;
|
| -TestShellRequestContext* g_request_context = NULL;
|
| -TestShellNetworkDelegate* g_network_delegate = NULL;
|
| -base::Thread* g_cache_thread = NULL;
|
| -
|
| -//-----------------------------------------------------------------------------
|
| -
|
| -struct FileOverHTTPParams {
|
| - FileOverHTTPParams(std::string in_file_path_template, GURL in_http_prefix)
|
| - : file_path_template(in_file_path_template),
|
| - http_prefix(in_http_prefix) {}
|
| -
|
| - std::string file_path_template;
|
| - GURL http_prefix;
|
| -};
|
| -
|
| -class FileOverHTTPPathMappings {
|
| - public:
|
| - FileOverHTTPPathMappings() : redirections_() {}
|
| - void AddMapping(std::string file_path_template, GURL http_prefix) {
|
| - redirections_.push_back(FileOverHTTPParams(file_path_template,
|
| - http_prefix));
|
| - }
|
| -
|
| - const FileOverHTTPParams* ParamsForRequest(std::string request,
|
| - std::string::size_type& offset) {
|
| - std::vector<FileOverHTTPParams>::iterator it;
|
| - for (it = redirections_.begin(); it != redirections_.end(); ++it) {
|
| - offset = request.find(it->file_path_template);
|
| - if (offset != std::string::npos)
|
| - return &*it;
|
| - }
|
| - return 0;
|
| - }
|
| -
|
| - const FileOverHTTPParams* ParamsForResponse(std::string response_url) {
|
| - std::vector<FileOverHTTPParams>::iterator it;
|
| - for (it = redirections_.begin(); it != redirections_.end(); ++it) {
|
| - if (response_url.find(it->http_prefix.spec()) == 0)
|
| - return &*it;
|
| - }
|
| - return 0;
|
| - }
|
| -
|
| - private:
|
| - std::vector<FileOverHTTPParams> redirections_;
|
| -};
|
| -
|
| -FileOverHTTPPathMappings* g_file_over_http_mappings = NULL;
|
| -
|
| -//-----------------------------------------------------------------------------
|
| -
|
| -class IOThread : public base::Thread {
|
| - public:
|
| - IOThread() : base::Thread("IOThread") {}
|
| -
|
| - virtual ~IOThread() {
|
| - Stop();
|
| - }
|
| -
|
| - virtual void Init() OVERRIDE {
|
| - if (g_request_context_params) {
|
| - g_request_context = new TestShellRequestContext(
|
| - g_request_context_params->cache_path,
|
| - g_request_context_params->cache_mode,
|
| - g_request_context_params->no_proxy);
|
| - delete g_request_context_params;
|
| - g_request_context_params = NULL;
|
| - } else {
|
| - g_request_context = new TestShellRequestContext();
|
| - }
|
| -
|
| - g_network_delegate = new TestShellNetworkDelegate();
|
| - g_request_context->set_network_delegate(g_network_delegate);
|
| -
|
| - SimpleAppCacheSystem::InitializeOnIOThread(g_request_context);
|
| - SimpleSocketStreamBridge::InitializeOnIOThread(g_request_context);
|
| - SimpleFileWriter::InitializeOnIOThread(g_request_context);
|
| - SimpleFileSystem::InitializeOnIOThread(
|
| - g_request_context->blob_storage_controller());
|
| - TestShellWebBlobRegistryImpl::InitializeOnIOThread(
|
| - g_request_context->blob_storage_controller());
|
| - }
|
| -
|
| - virtual void CleanUp() OVERRIDE {
|
| - // In reverse order of initialization.
|
| - TestShellWebBlobRegistryImpl::Cleanup();
|
| - SimpleFileSystem::CleanupOnIOThread();
|
| - SimpleFileWriter::CleanupOnIOThread();
|
| - SimpleSocketStreamBridge::Cleanup();
|
| - SimpleAppCacheSystem::CleanupOnIOThread();
|
| -
|
| - if (g_request_context) {
|
| - g_request_context->set_network_delegate(NULL);
|
| - delete g_request_context;
|
| - g_request_context = NULL;
|
| - }
|
| -
|
| - if (g_network_delegate) {
|
| - delete g_network_delegate;
|
| - g_network_delegate = NULL;
|
| - }
|
| - }
|
| -};
|
| -
|
| -IOThread* g_io_thread = NULL;
|
| -
|
| -//-----------------------------------------------------------------------------
|
| -
|
| -struct RequestParams {
|
| - std::string method;
|
| - GURL url;
|
| - GURL first_party_for_cookies;
|
| - GURL referrer;
|
| - WebKit::WebReferrerPolicy referrer_policy;
|
| - std::string headers;
|
| - int load_flags;
|
| - ResourceType::Type request_type;
|
| - int appcache_host_id;
|
| - bool download_to_file;
|
| - scoped_refptr<ResourceRequestBody> request_body;
|
| -};
|
| -
|
| -// The interval for calls to RequestProxy::MaybeUpdateUploadProgress
|
| -static const int kUpdateUploadProgressIntervalMsec = 100;
|
| -
|
| -// The RequestProxy does most of its work on the IO thread. The Start and
|
| -// Cancel methods are proxied over to the IO thread, where an net::URLRequest
|
| -// object is instantiated.
|
| -struct DeleteOnIOThread; // See below.
|
| -class RequestProxy
|
| - : public net::URLRequest::Delegate,
|
| - public base::RefCountedThreadSafe<RequestProxy, DeleteOnIOThread> {
|
| - public:
|
| - // Takes ownership of the params.
|
| - RequestProxy()
|
| - : download_to_file_(false),
|
| - buf_(new net::IOBuffer(kDataSize)),
|
| - last_upload_position_(0) {
|
| - }
|
| -
|
| - void DropPeer() {
|
| - peer_ = NULL;
|
| - }
|
| -
|
| - void Start(ResourceLoaderBridge::Peer* peer, RequestParams* params) {
|
| - peer_ = peer;
|
| - owner_loop_ = base::MessageLoop::current();
|
| -
|
| - ConvertRequestParamsForFileOverHTTPIfNeeded(params);
|
| - // proxy over to the io thread
|
| - g_io_thread->message_loop()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&RequestProxy::AsyncStart, this, params));
|
| - }
|
| -
|
| - void Cancel() {
|
| - // proxy over to the io thread
|
| - g_io_thread->message_loop()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&RequestProxy::AsyncCancel, this));
|
| - }
|
| -
|
| - protected:
|
| - friend class base::DeleteHelper<RequestProxy>;
|
| - friend class base::RefCountedThreadSafe<RequestProxy>;
|
| - friend struct DeleteOnIOThread;
|
| -
|
| - virtual ~RequestProxy() {
|
| - // Ensure we are deleted on the IO thread because base::Timer requires that.
|
| - // (guaranteed by the Traits class template parameter).
|
| - DCHECK(base::MessageLoop::current() == g_io_thread->message_loop());
|
| - }
|
| -
|
| - // --------------------------------------------------------------------------
|
| - // The following methods are called on the owner's thread in response to
|
| - // various net::URLRequest callbacks. The event hooks, defined below, trigger
|
| - // these methods asynchronously.
|
| -
|
| - void NotifyReceivedRedirect(const GURL& new_url,
|
| - const ResourceResponseInfo& info) {
|
| - bool has_new_first_party_for_cookies = false;
|
| - GURL new_first_party_for_cookies;
|
| - if (peer_ && peer_->OnReceivedRedirect(new_url, info,
|
| - &has_new_first_party_for_cookies,
|
| - &new_first_party_for_cookies)) {
|
| - g_io_thread->message_loop()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&RequestProxy::AsyncFollowDeferredRedirect, this,
|
| - has_new_first_party_for_cookies,
|
| - new_first_party_for_cookies));
|
| - } else {
|
| - Cancel();
|
| - }
|
| - }
|
| -
|
| - void NotifyReceivedResponse(const ResourceResponseInfo& info) {
|
| - if (peer_)
|
| - peer_->OnReceivedResponse(info);
|
| - }
|
| -
|
| - void NotifyReceivedData(int bytes_read) {
|
| - if (!peer_)
|
| - return;
|
| -
|
| - // Make a local copy of buf_, since AsyncReadData reuses it.
|
| - scoped_ptr<char[]> buf_copy(new char[bytes_read]);
|
| - memcpy(buf_copy.get(), buf_->data(), bytes_read);
|
| -
|
| - // Continue reading more data into buf_
|
| - // Note: Doing this before notifying our peer ensures our load events get
|
| - // dispatched in a manner consistent with DumpRenderTree (and also avoids a
|
| - // race condition). If the order of the next 2 functions were reversed, the
|
| - // peer could generate new requests in reponse to the received data, which
|
| - // when run on the io thread, could race against this function in doing
|
| - // another InvokeLater. See bug 769249.
|
| - g_io_thread->message_loop()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&RequestProxy::AsyncReadData, this));
|
| -
|
| - peer_->OnReceivedData(buf_copy.get(), bytes_read, -1);
|
| - }
|
| -
|
| - void NotifyDownloadedData(int bytes_read) {
|
| - if (!peer_)
|
| - return;
|
| -
|
| - // Continue reading more data, see the comment in NotifyReceivedData.
|
| - g_io_thread->message_loop()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&RequestProxy::AsyncReadData, this));
|
| -
|
| - peer_->OnDownloadedData(bytes_read);
|
| - }
|
| -
|
| - void NotifyCompletedRequest(int error_code,
|
| - const std::string& security_info,
|
| - const base::TimeTicks& complete_time) {
|
| - if (peer_) {
|
| - peer_->OnCompletedRequest(error_code, false, security_info,
|
| - complete_time);
|
| - DropPeer(); // ensure no further notifications
|
| - }
|
| - }
|
| -
|
| - void NotifyUploadProgress(uint64 position, uint64 size) {
|
| - if (peer_)
|
| - peer_->OnUploadProgress(position, size);
|
| - }
|
| -
|
| - // --------------------------------------------------------------------------
|
| - // The following methods are called on the io thread. They correspond to
|
| - // actions performed on the owner's thread.
|
| -
|
| - void AsyncStart(RequestParams* params) {
|
| - request_.reset(g_request_context->CreateRequest(params->url, this));
|
| - request_->set_method(params->method);
|
| - request_->set_first_party_for_cookies(params->first_party_for_cookies);
|
| - request_->SetReferrer(params->referrer.spec());
|
| - webkit_glue::ConfigureURLRequestForReferrerPolicy(
|
| - request_.get(), params->referrer_policy);
|
| - net::HttpRequestHeaders headers;
|
| - headers.AddHeadersFromString(params->headers);
|
| - request_->SetExtraRequestHeaders(headers);
|
| - request_->set_load_flags(params->load_flags);
|
| - if (params->request_body.get()) {
|
| - request_->set_upload(make_scoped_ptr(
|
| - params->request_body->ResolveElementsAndCreateUploadDataStream(
|
| - static_cast<TestShellRequestContext*>(g_request_context)
|
| - ->blob_storage_controller(),
|
| - static_cast<TestShellRequestContext*>(g_request_context)
|
| - ->file_system_context(),
|
| - base::MessageLoopProxy::current())));
|
| - }
|
| - SimpleAppCacheSystem::SetExtraRequestInfo(
|
| - request_.get(), params->appcache_host_id, params->request_type);
|
| -
|
| - download_to_file_ = params->download_to_file;
|
| - if (download_to_file_) {
|
| - base::FilePath path;
|
| - if (file_util::CreateTemporaryFile(&path)) {
|
| - downloaded_file_ = ShareableFileReference::GetOrCreate(
|
| - path, ShareableFileReference::DELETE_ON_FINAL_RELEASE,
|
| - base::MessageLoopProxy::current());
|
| - file_stream_.reset(new net::FileStream(NULL));
|
| - file_stream_->OpenSync(
|
| - path, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE);
|
| - }
|
| - }
|
| -
|
| - request_->Start();
|
| -
|
| - if (request_->has_upload() &&
|
| - params->load_flags & net::LOAD_ENABLE_UPLOAD_PROGRESS) {
|
| - upload_progress_timer_.Start(FROM_HERE,
|
| - base::TimeDelta::FromMilliseconds(kUpdateUploadProgressIntervalMsec),
|
| - this, &RequestProxy::MaybeUpdateUploadProgress);
|
| - }
|
| -
|
| - delete params;
|
| - }
|
| -
|
| - void AsyncCancel() {
|
| - // This can be null in cases where the request is already done.
|
| - if (!request_)
|
| - return;
|
| -
|
| - request_->Cancel();
|
| - Done();
|
| - }
|
| -
|
| - void AsyncFollowDeferredRedirect(bool has_new_first_party_for_cookies,
|
| - const GURL& new_first_party_for_cookies) {
|
| - // This can be null in cases where the request is already done.
|
| - if (!request_)
|
| - return;
|
| -
|
| - if (has_new_first_party_for_cookies)
|
| - request_->set_first_party_for_cookies(new_first_party_for_cookies);
|
| - request_->FollowDeferredRedirect();
|
| - }
|
| -
|
| - void AsyncReadData() {
|
| - // This can be null in cases where the request is already done.
|
| - if (!request_)
|
| - return;
|
| -
|
| - if (request_->status().is_success()) {
|
| - int bytes_read;
|
| - if (request_->Read(buf_.get(), kDataSize, &bytes_read) && bytes_read) {
|
| - OnReceivedData(bytes_read);
|
| - } else if (!request_->status().is_io_pending()) {
|
| - Done();
|
| - } // else wait for OnReadCompleted
|
| - } else {
|
| - Done();
|
| - }
|
| - }
|
| -
|
| - // --------------------------------------------------------------------------
|
| - // The following methods are event hooks (corresponding to net::URLRequest
|
| - // callbacks) that run on the IO thread. They are designed to be overridden
|
| - // by the SyncRequestProxy subclass.
|
| -
|
| - virtual void OnReceivedRedirect(
|
| - const GURL& new_url,
|
| - const ResourceResponseInfo& info,
|
| - bool* defer_redirect) {
|
| - *defer_redirect = true; // See AsyncFollowDeferredRedirect
|
| - owner_loop_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&RequestProxy::NotifyReceivedRedirect, this, new_url, info));
|
| - }
|
| -
|
| - virtual void OnReceivedResponse(
|
| - const ResourceResponseInfo& info) {
|
| - owner_loop_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&RequestProxy::NotifyReceivedResponse, this, info));
|
| - }
|
| -
|
| - virtual void OnReceivedData(int bytes_read) {
|
| - if (download_to_file_) {
|
| - file_stream_->WriteSync(buf_->data(), bytes_read);
|
| - owner_loop_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&RequestProxy::NotifyDownloadedData, this, bytes_read));
|
| - return;
|
| - }
|
| -
|
| - owner_loop_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&RequestProxy::NotifyReceivedData, this, bytes_read));
|
| - }
|
| -
|
| - virtual void OnCompletedRequest(int error_code,
|
| - const std::string& security_info,
|
| - const base::TimeTicks& complete_time) {
|
| - if (download_to_file_)
|
| - file_stream_.reset();
|
| - owner_loop_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&RequestProxy::NotifyCompletedRequest, this, error_code,
|
| - security_info, complete_time));
|
| - }
|
| -
|
| - // --------------------------------------------------------------------------
|
| - // net::URLRequest::Delegate implementation:
|
| -
|
| - virtual void OnReceivedRedirect(net::URLRequest* request,
|
| - const GURL& new_url,
|
| - bool* defer_redirect) OVERRIDE {
|
| - DCHECK(request->status().is_success());
|
| - ResourceResponseInfo info;
|
| - PopulateResponseInfo(request, &info);
|
| - // For file protocol, should never have the redirect situation.
|
| - DCHECK(!ConvertResponseInfoForFileOverHTTPIfNeeded(request, &info));
|
| - OnReceivedRedirect(new_url, info, defer_redirect);
|
| - }
|
| -
|
| - virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE {
|
| - if (request->status().is_success()) {
|
| - ResourceResponseInfo info;
|
| - PopulateResponseInfo(request, &info);
|
| - // If encountering error when requesting the file, cancel the request.
|
| - if (ConvertResponseInfoForFileOverHTTPIfNeeded(request, &info) &&
|
| - failed_file_request_status_.get()) {
|
| - AsyncCancel();
|
| - } else {
|
| - OnReceivedResponse(info);
|
| - AsyncReadData(); // start reading
|
| - }
|
| - } else {
|
| - Done();
|
| - }
|
| - }
|
| -
|
| - virtual void OnSSLCertificateError(net::URLRequest* request,
|
| - const net::SSLInfo& ssl_info,
|
| - bool fatal) OVERRIDE {
|
| - // Allow all certificate errors.
|
| - request->ContinueDespiteLastError();
|
| - }
|
| -
|
| - virtual void OnReadCompleted(net::URLRequest* request,
|
| - int bytes_read) OVERRIDE {
|
| - if (request->status().is_success() && bytes_read > 0) {
|
| - OnReceivedData(bytes_read);
|
| - } else {
|
| - Done();
|
| - }
|
| - }
|
| -
|
| - // --------------------------------------------------------------------------
|
| - // Helpers and data:
|
| -
|
| - void Done() {
|
| - if (upload_progress_timer_.IsRunning()) {
|
| - MaybeUpdateUploadProgress();
|
| - upload_progress_timer_.Stop();
|
| - }
|
| - DCHECK(request_.get());
|
| - // If |failed_file_request_status_| is not empty, which means the request
|
| - // was a file request and encountered an error, then we need to use the
|
| - // |failed_file_request_status_|. Otherwise use request_'s status.
|
| - OnCompletedRequest(failed_file_request_status_.get() ?
|
| - failed_file_request_status_->error() :
|
| - request_->status().error(),
|
| - std::string(), base::TimeTicks::Now());
|
| - request_.reset(); // destroy on the io thread
|
| - }
|
| -
|
| - // Called on the IO thread.
|
| - void MaybeUpdateUploadProgress() {
|
| - // If a redirect is received upload is cancelled in net::URLRequest, we
|
| - // should try to stop the |upload_progress_timer_| timer and return.
|
| - if (!request_->has_upload()) {
|
| - if (upload_progress_timer_.IsRunning())
|
| - upload_progress_timer_.Stop();
|
| - return;
|
| - }
|
| -
|
| - net::UploadProgress progress = request_->GetUploadProgress();
|
| - if (progress.position() == last_upload_position_)
|
| - return; // no progress made since last time
|
| -
|
| - const uint64 kHalfPercentIncrements = 200;
|
| - const base::TimeDelta kOneSecond = base::TimeDelta::FromMilliseconds(1000);
|
| -
|
| - uint64 amt_since_last = progress.position() - last_upload_position_;
|
| - base::TimeDelta time_since_last = base::TimeTicks::Now() -
|
| - last_upload_ticks_;
|
| -
|
| - bool is_finished = (progress.size() == progress.position());
|
| - bool enough_new_progress = (amt_since_last > (progress.size() /
|
| - kHalfPercentIncrements));
|
| - bool too_much_time_passed = time_since_last > kOneSecond;
|
| -
|
| - if (is_finished || enough_new_progress || too_much_time_passed) {
|
| - owner_loop_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&RequestProxy::NotifyUploadProgress, this,
|
| - progress.position(), progress.size()));
|
| - last_upload_ticks_ = base::TimeTicks::Now();
|
| - last_upload_position_ = progress.position();
|
| - }
|
| - }
|
| -
|
| - void PopulateResponseInfo(net::URLRequest* request,
|
| - ResourceResponseInfo* info) const {
|
| - if (request->load_flags() & net::LOAD_ENABLE_LOAD_TIMING)
|
| - request->GetLoadTimingInfo(&info->load_timing);
|
| - info->request_time = request->request_time();
|
| - info->response_time = request->response_time();
|
| - info->headers = request->response_headers();
|
| - request->GetMimeType(&info->mime_type);
|
| - request->GetCharset(&info->charset);
|
| - info->content_length = request->GetExpectedContentSize();
|
| - if (downloaded_file_.get())
|
| - info->download_file_path = downloaded_file_->path();
|
| - SimpleAppCacheSystem::GetExtraResponseInfo(
|
| - request,
|
| - &info->appcache_id,
|
| - &info->appcache_manifest_url);
|
| - }
|
| -
|
| - // Called on owner thread
|
| - void ConvertRequestParamsForFileOverHTTPIfNeeded(RequestParams* params) {
|
| - // Reset the status.
|
| - file_url_prefix_ .clear();
|
| - failed_file_request_status_.reset();
|
| - // Only do this when enabling file-over-http and request is file scheme.
|
| - if (!g_file_over_http_mappings || !params->url.SchemeIsFile())
|
| - return;
|
| -
|
| - // For file protocol, method must be GET, POST or NULL.
|
| - DCHECK(params->method == "GET" || params->method == "POST" ||
|
| - params->method.empty());
|
| - DCHECK(!params->download_to_file);
|
| -
|
| - if (params->method.empty())
|
| - params->method = "GET";
|
| - std::string original_request = params->url.spec();
|
| -
|
| - std::string::size_type offset = 0;
|
| - const FileOverHTTPParams* redirection_params =
|
| - g_file_over_http_mappings->ParamsForRequest(original_request, offset);
|
| - if (!redirection_params)
|
| - return;
|
| -
|
| - offset += redirection_params->file_path_template.size();
|
| - file_url_prefix_ = original_request.substr(0, offset);
|
| - original_request.replace(0, offset,
|
| - redirection_params->http_prefix.spec());
|
| - params->url = GURL(original_request);
|
| - params->first_party_for_cookies = params->url;
|
| - // For file protocol, nerver use cache.
|
| - params->load_flags = net::LOAD_BYPASS_CACHE;
|
| - }
|
| -
|
| - // Called on IO thread.
|
| - bool ConvertResponseInfoForFileOverHTTPIfNeeded(net::URLRequest* request,
|
| - ResourceResponseInfo* info) {
|
| - // Only do this when enabling file-over-http and request url
|
| - // matches the http prefix for file-over-http feature.
|
| - if (!g_file_over_http_mappings || file_url_prefix_.empty())
|
| - return false;
|
| -
|
| - std::string original_request = request->url().spec();
|
| - DCHECK(!original_request.empty());
|
| -
|
| - const FileOverHTTPParams* redirection_params =
|
| - g_file_over_http_mappings->ParamsForResponse(original_request);
|
| - DCHECK(redirection_params);
|
| -
|
| - std::string http_prefix = redirection_params->http_prefix.spec();
|
| - DCHECK(StartsWithASCII(original_request, http_prefix, true));
|
| -
|
| - // Get the File URL.
|
| - original_request.replace(0, http_prefix.size(), file_url_prefix_);
|
| -
|
| - base::FilePath file_path;
|
| - if (!net::FileURLToFilePath(GURL(original_request), &file_path)) {
|
| - NOTREACHED();
|
| - }
|
| -
|
| - info->mime_type.clear();
|
| - DCHECK(info->headers.get());
|
| - int status_code = info->headers->response_code();
|
| - // File protocol does not support response headers.
|
| - info->headers = NULL;
|
| - if (200 == status_code) {
|
| - // Don't use the MIME type from HTTP server, use net::GetMimeTypeFromFile
|
| - // instead.
|
| - net::GetMimeTypeFromFile(file_path, &info->mime_type);
|
| - } else {
|
| - // If the file does not exist, immediately call OnCompletedRequest with
|
| - // setting URLRequestStatus to FAILED.
|
| - DCHECK(status_code == 404 || status_code == 403);
|
| - if (status_code == 404) {
|
| - failed_file_request_status_.reset(
|
| - new net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| - net::ERR_FILE_NOT_FOUND));
|
| - } else {
|
| - failed_file_request_status_.reset(
|
| - new net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| - net::ERR_ACCESS_DENIED));
|
| - }
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - scoped_ptr<net::URLRequest> request_;
|
| -
|
| - // Support for request.download_to_file behavior.
|
| - bool download_to_file_;
|
| - scoped_ptr<net::FileStream> file_stream_;
|
| - scoped_refptr<ShareableFileReference> downloaded_file_;
|
| -
|
| - // Size of our async IO data buffers
|
| - static const int kDataSize = 16*1024;
|
| -
|
| - // read buffer for async IO
|
| - scoped_refptr<net::IOBuffer> buf_;
|
| -
|
| - base::MessageLoop* owner_loop_;
|
| -
|
| - // This is our peer in WebKit (implemented as ResourceHandleInternal). We do
|
| - // not manage its lifetime, and we may only access it from the owner's
|
| - // message loop (owner_loop_).
|
| - ResourceLoaderBridge::Peer* peer_;
|
| -
|
| - // Timer used to pull upload progress info.
|
| - base::RepeatingTimer<RequestProxy> upload_progress_timer_;
|
| -
|
| - // Info used to determine whether or not to send an upload progress update.
|
| - uint64 last_upload_position_;
|
| - base::TimeTicks last_upload_ticks_;
|
| -
|
| - // Save the real FILE URL prefix for the FILE URL which converts to HTTP URL.
|
| - std::string file_url_prefix_;
|
| - // Save a failed file request status to pass it to webkit.
|
| - scoped_ptr<net::URLRequestStatus> failed_file_request_status_;
|
| -};
|
| -
|
| -// Helper guaranteeing deletion on the IO thread (like
|
| -// content::BrowserThread::DeleteOnIOThread, but without the dependency).
|
| -struct DeleteOnIOThread {
|
| - static void Destruct(const RequestProxy* obj) {
|
| - if (base::MessageLoop::current() == g_io_thread->message_loop())
|
| - delete obj;
|
| - else
|
| - g_io_thread->message_loop()->DeleteSoon(FROM_HERE, obj);
|
| - }
|
| -};
|
| -
|
| -//-----------------------------------------------------------------------------
|
| -
|
| -class SyncRequestProxy : public RequestProxy {
|
| - public:
|
| - explicit SyncRequestProxy(ResourceLoaderBridge::SyncLoadResponse* result)
|
| - : result_(result), event_(true, false) {
|
| - }
|
| -
|
| - void WaitForCompletion() {
|
| - event_.Wait();
|
| - }
|
| -
|
| - // --------------------------------------------------------------------------
|
| - // RequestProxy event hooks that run on the IO thread:
|
| -
|
| - virtual void OnReceivedRedirect(
|
| - const GURL& new_url,
|
| - const ResourceResponseInfo& info,
|
| - bool* defer_redirect) OVERRIDE {
|
| - // TODO(darin): It would be much better if this could live in WebCore, but
|
| - // doing so requires API changes at all levels. Similar code exists in
|
| - // WebCore/platform/network/cf/ResourceHandleCFNet.cpp :-(
|
| - if (new_url.GetOrigin() != result_->url.GetOrigin()) {
|
| - DLOG(WARNING) << "Cross origin redirect denied";
|
| - Cancel();
|
| - return;
|
| - }
|
| - result_->url = new_url;
|
| - }
|
| -
|
| - virtual void OnReceivedResponse(const ResourceResponseInfo& info) OVERRIDE {
|
| - *static_cast<ResourceResponseInfo*>(result_) = info;
|
| - }
|
| -
|
| - virtual void OnReceivedData(int bytes_read) OVERRIDE {
|
| - if (download_to_file_)
|
| - file_stream_->WriteSync(buf_->data(), bytes_read);
|
| - else
|
| - result_->data.append(buf_->data(), bytes_read);
|
| - AsyncReadData(); // read more (may recurse)
|
| - }
|
| -
|
| - virtual void OnCompletedRequest(
|
| - int error_code,
|
| - const std::string& security_info,
|
| - const base::TimeTicks& complete_time) OVERRIDE {
|
| - if (download_to_file_)
|
| - file_stream_.reset();
|
| - result_->error_code = error_code;
|
| - event_.Signal();
|
| - }
|
| -
|
| - protected:
|
| - virtual ~SyncRequestProxy() {}
|
| -
|
| - private:
|
| - ResourceLoaderBridge::SyncLoadResponse* result_;
|
| - base::WaitableEvent event_;
|
| -};
|
| -
|
| -//-----------------------------------------------------------------------------
|
| -
|
| -class ResourceLoaderBridgeImpl : public ResourceLoaderBridge {
|
| - public:
|
| - ResourceLoaderBridgeImpl(
|
| - const webkit_glue::ResourceLoaderBridge::RequestInfo& request_info)
|
| - : params_(new RequestParams),
|
| - proxy_(NULL) {
|
| - params_->method = request_info.method;
|
| - params_->url = request_info.url;
|
| - params_->first_party_for_cookies = request_info.first_party_for_cookies;
|
| - params_->referrer = request_info.referrer;
|
| - params_->referrer_policy = request_info.referrer_policy;
|
| - params_->headers = request_info.headers;
|
| - params_->load_flags = request_info.load_flags;
|
| - params_->request_type = request_info.request_type;
|
| - params_->appcache_host_id = request_info.appcache_host_id;
|
| - params_->download_to_file = request_info.download_to_file;
|
| - }
|
| -
|
| - virtual ~ResourceLoaderBridgeImpl() {
|
| - if (proxy_) {
|
| - proxy_->DropPeer();
|
| - // Let the proxy die on the IO thread
|
| - g_io_thread->message_loop()->ReleaseSoon(FROM_HERE, proxy_);
|
| - }
|
| - }
|
| -
|
| - // --------------------------------------------------------------------------
|
| - // ResourceLoaderBridge implementation:
|
| -
|
| - virtual void SetRequestBody(ResourceRequestBody* request_body) OVERRIDE {
|
| - DCHECK(params_.get());
|
| - DCHECK(!params_->request_body.get());
|
| - params_->request_body = request_body;
|
| - }
|
| -
|
| - virtual bool Start(Peer* peer) OVERRIDE {
|
| - DCHECK(!proxy_);
|
| -
|
| - if (!SimpleResourceLoaderBridge::EnsureIOThread())
|
| - return false;
|
| -
|
| - proxy_ = new RequestProxy();
|
| - proxy_->AddRef();
|
| -
|
| - proxy_->Start(peer, params_.release());
|
| -
|
| - return true; // Any errors will be reported asynchronously.
|
| - }
|
| -
|
| - virtual void Cancel() OVERRIDE {
|
| - DCHECK(proxy_);
|
| - proxy_->Cancel();
|
| - }
|
| -
|
| - virtual void SetDefersLoading(bool value) OVERRIDE {
|
| - // TODO(darin): implement me
|
| - }
|
| -
|
| - virtual void SyncLoad(SyncLoadResponse* response) OVERRIDE {
|
| - DCHECK(!proxy_);
|
| -
|
| - if (!SimpleResourceLoaderBridge::EnsureIOThread())
|
| - return;
|
| -
|
| - // this may change as the result of a redirect
|
| - response->url = params_->url;
|
| -
|
| - proxy_ = new SyncRequestProxy(response);
|
| - proxy_->AddRef();
|
| -
|
| - proxy_->Start(NULL, params_.release());
|
| -
|
| - static_cast<SyncRequestProxy*>(proxy_)->WaitForCompletion();
|
| - }
|
| -
|
| - virtual void DidChangePriority(net::RequestPriority new_priority) OVERRIDE {
|
| - // Not really needed for DRT.
|
| - }
|
| -
|
| - private:
|
| - // Ownership of params_ is transfered to the proxy when the proxy is created.
|
| - scoped_ptr<RequestParams> params_;
|
| -
|
| - // The request proxy is allocated when we start the request, and then it
|
| - // sticks around until this ResourceLoaderBridge is destroyed.
|
| - RequestProxy* proxy_;
|
| -};
|
| -
|
| -//-----------------------------------------------------------------------------
|
| -
|
| -class CookieSetter : public base::RefCountedThreadSafe<CookieSetter> {
|
| - public:
|
| - void Set(const GURL& url, const std::string& cookie) {
|
| - DCHECK(base::MessageLoop::current() == g_io_thread->message_loop());
|
| - g_request_context->cookie_store()->SetCookieWithOptionsAsync(
|
| - url, cookie, net::CookieOptions(),
|
| - net::CookieStore::SetCookiesCallback());
|
| - }
|
| -
|
| - private:
|
| - friend class base::RefCountedThreadSafe<CookieSetter>;
|
| - ~CookieSetter() {}
|
| -};
|
| -
|
| -class CookieGetter : public base::RefCountedThreadSafe<CookieGetter> {
|
| - public:
|
| - CookieGetter() : event_(false, false) {
|
| - }
|
| -
|
| - void Get(const GURL& url) {
|
| - g_request_context->cookie_store()->GetCookiesWithOptionsAsync(
|
| - url, net::CookieOptions(),
|
| - base::Bind(&CookieGetter::OnGetCookies, this));
|
| - }
|
| -
|
| - std::string GetResult() {
|
| - event_.Wait();
|
| - return result_;
|
| - }
|
| -
|
| - private:
|
| - friend class base::RefCountedThreadSafe<CookieGetter>;
|
| - ~CookieGetter() {}
|
| -
|
| - void OnGetCookies(const std::string& cookie_line) {
|
| - result_ = cookie_line;
|
| - event_.Signal();
|
| - }
|
| -
|
| - base::WaitableEvent event_;
|
| - std::string result_;
|
| -};
|
| -
|
| -} // anonymous namespace
|
| -
|
| -//-----------------------------------------------------------------------------
|
| -
|
| -// static
|
| -void SimpleResourceLoaderBridge::Init(
|
| - const base::FilePath& cache_path,
|
| - net::HttpCache::Mode cache_mode,
|
| - bool no_proxy) {
|
| - // Make sure to stop any existing IO thread since it may be using the
|
| - // current request context.
|
| - Shutdown();
|
| -
|
| - DCHECK(!g_request_context_params);
|
| - DCHECK(!g_request_context);
|
| - DCHECK(!g_network_delegate);
|
| - DCHECK(!g_io_thread);
|
| -
|
| - g_request_context_params = new TestShellRequestContextParams(
|
| - cache_path, cache_mode, no_proxy);
|
| -}
|
| -
|
| -// static
|
| -void SimpleResourceLoaderBridge::Shutdown() {
|
| - if (g_io_thread) {
|
| - delete g_io_thread;
|
| - g_io_thread = NULL;
|
| -
|
| - DCHECK(g_cache_thread);
|
| - delete g_cache_thread;
|
| - g_cache_thread = NULL;
|
| -
|
| - DCHECK(!g_request_context) << "should have been nulled by thread dtor";
|
| - DCHECK(!g_network_delegate) << "should have been nulled by thread dtor";
|
| - } else {
|
| - delete g_request_context_params;
|
| - g_request_context_params = NULL;
|
| -
|
| - delete g_file_over_http_mappings;
|
| - g_file_over_http_mappings = NULL;
|
| - }
|
| -}
|
| -
|
| -// static
|
| -void SimpleResourceLoaderBridge::SetCookie(const GURL& url,
|
| - const GURL& first_party_for_cookies,
|
| - const std::string& cookie) {
|
| - // Proxy to IO thread to synchronize w/ network loading.
|
| -
|
| - if (!EnsureIOThread()) {
|
| - NOTREACHED();
|
| - return;
|
| - }
|
| -
|
| - scoped_refptr<CookieSetter> cookie_setter(new CookieSetter());
|
| - g_io_thread->message_loop()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&CookieSetter::Set, cookie_setter.get(), url, cookie));
|
| -}
|
| -
|
| -// static
|
| -std::string SimpleResourceLoaderBridge::GetCookies(
|
| - const GURL& url, const GURL& first_party_for_cookies) {
|
| - // Proxy to IO thread to synchronize w/ network loading
|
| -
|
| - if (!EnsureIOThread()) {
|
| - NOTREACHED();
|
| - return std::string();
|
| - }
|
| -
|
| - scoped_refptr<CookieGetter> getter(new CookieGetter());
|
| -
|
| - g_io_thread->message_loop()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&CookieGetter::Get, getter.get(), url));
|
| -
|
| - return getter->GetResult();
|
| -}
|
| -
|
| -// static
|
| -bool SimpleResourceLoaderBridge::EnsureIOThread() {
|
| - if (g_io_thread)
|
| - return true;
|
| -
|
| -#if defined(OS_MACOSX) || defined(OS_WIN)
|
| - // We want to be sure to init NSPR on the main thread.
|
| - crypto::EnsureNSPRInit();
|
| -#endif
|
| -
|
| - // Create the cache thread. We want the cache thread to outlive the IO thread,
|
| - // so its lifetime is bonded to the IO thread lifetime.
|
| - DCHECK(!g_cache_thread);
|
| - g_cache_thread = new base::Thread("cache");
|
| - CHECK(g_cache_thread->StartWithOptions(
|
| - base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
|
| -
|
| - g_io_thread = new IOThread();
|
| - base::Thread::Options options;
|
| - options.message_loop_type = base::MessageLoop::TYPE_IO;
|
| - return g_io_thread->StartWithOptions(options);
|
| -}
|
| -
|
| -// static
|
| -void SimpleResourceLoaderBridge::SetAcceptAllCookies(bool accept_all_cookies) {
|
| - g_accept_all_cookies = accept_all_cookies;
|
| -}
|
| -
|
| -// static
|
| -scoped_refptr<base::MessageLoopProxy>
|
| - SimpleResourceLoaderBridge::GetCacheThread() {
|
| - return g_cache_thread->message_loop_proxy();
|
| -}
|
| -
|
| -// static
|
| -scoped_refptr<base::MessageLoopProxy>
|
| - SimpleResourceLoaderBridge::GetIoThread() {
|
| - if (!EnsureIOThread()) {
|
| - LOG(DFATAL) << "Failed to create IO thread.";
|
| - return NULL;
|
| - }
|
| - return g_io_thread->message_loop_proxy();
|
| -}
|
| -
|
| -// static
|
| -void SimpleResourceLoaderBridge::AllowFileOverHTTP(
|
| - const std::string& file_path_template, const GURL& http_prefix) {
|
| - DCHECK(!file_path_template.empty());
|
| - DCHECK(http_prefix.is_valid() &&
|
| - (http_prefix.SchemeIs("http") || http_prefix.SchemeIs("https")));
|
| - if (!g_file_over_http_mappings)
|
| - g_file_over_http_mappings = new FileOverHTTPPathMappings();
|
| - g_file_over_http_mappings->AddMapping(file_path_template, http_prefix);
|
| -}
|
| -
|
| -// static
|
| -webkit_glue::ResourceLoaderBridge* SimpleResourceLoaderBridge::Create(
|
| - const webkit_glue::ResourceLoaderBridge::RequestInfo& request_info) {
|
| - return new ResourceLoaderBridgeImpl(request_info);
|
| -}
|
|
|