summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome_frame/urlmon_url_request.cc230
-rw-r--r--chrome_frame/urlmon_url_request.h42
-rw-r--r--chrome_frame/urlmon_url_request_private.h4
-rw-r--r--chrome_frame/utils.cc5
-rw-r--r--chrome_frame/utils.h1
5 files changed, 238 insertions, 44 deletions
diff --git a/chrome_frame/urlmon_url_request.cc b/chrome_frame/urlmon_url_request.cc
index 42474fd..9bade03 100644
--- a/chrome_frame/urlmon_url_request.cc
+++ b/chrome_frame/urlmon_url_request.cc
@@ -994,7 +994,6 @@ void UrlmonUrlRequestManager::SetInfoForUrl(const std::wstring& url,
void UrlmonUrlRequestManager::StartRequest(int request_id,
const AutomationURLRequest& request_info) {
DVLOG(1) << __FUNCTION__ << " id: " << request_id;
- DCHECK_EQ(0, calling_delegate_);
if (stopping_) {
DLOG(WARNING) << __FUNCTION__ << " request not started (stopping)";
@@ -1002,8 +1001,40 @@ void UrlmonUrlRequestManager::StartRequest(int request_id,
}
DCHECK(request_map_.find(request_id) == request_map_.end());
+#ifndef NDEBUG
+ if (background_worker_thread_enabled_) {
+ base::AutoLock lock(background_resource_map_lock_);
+ DCHECK(background_request_map_.find(request_id) ==
+ background_request_map_.end());
+ }
+#endif // NDEBUG
DCHECK(GURL(request_info.url).is_valid());
+ // Non frame requests like sub resources, images, etc are handled on the
+ // background thread.
+ if (background_worker_thread_enabled_ &&
+ !ResourceType::IsFrame(
+ static_cast<ResourceType::Type>(request_info.resource_type))) {
+ DLOG(INFO) << "Downloading resource type "
+ << request_info.resource_type
+ << " on background thread";
+ background_thread_->message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &UrlmonUrlRequestManager::StartRequestHelper,
+ request_id, request_info, &background_request_map_,
+ &background_resource_map_lock_));
+ return;
+ }
+ StartRequestHelper(request_id, request_info, &request_map_, NULL);
+}
+
+void UrlmonUrlRequestManager::StartRequestHelper(
+ int request_id,
+ const AutomationURLRequest& request_info,
+ RequestMap* request_map,
+ base::Lock* request_map_lock) {
+ DCHECK(request_map);
+ DCHECK(!stopping_);
scoped_refptr<UrlmonUrlRequest> new_request;
bool is_started = false;
if (pending_request_) {
@@ -1042,7 +1073,13 @@ void UrlmonUrlRequestManager::StartRequest(int request_id,
new_request->set_parent_window(notification_window_);
new_request->set_privileged_mode(privileged_mode_);
- request_map_[request_id] = new_request;
+ if (request_map_lock)
+ request_map_lock->Acquire();
+
+ (*request_map)[request_id] = new_request;
+
+ if (request_map_lock)
+ request_map_lock->Release();
if (!is_started) {
// Freshly created, start now.
@@ -1058,28 +1095,61 @@ void UrlmonUrlRequestManager::StartRequest(int request_id,
void UrlmonUrlRequestManager::ReadRequest(int request_id, int bytes_to_read) {
DVLOG(1) << __FUNCTION__ << " id: " << request_id;
- DCHECK_EQ(0, calling_delegate_);
- scoped_refptr<UrlmonUrlRequest> request = LookupRequest(request_id);
- // if zero, it may just have had network error.
- if (request)
+ // if we fail to find the request in the normal map and the background
+ // request map, it may mean that the request could have failed with a
+ // network error.
+ scoped_refptr<UrlmonUrlRequest> request = LookupRequest(request_id,
+ &request_map_);
+ if (request) {
request->Read(bytes_to_read);
+ } else if (background_worker_thread_enabled_) {
+ base::AutoLock lock(background_resource_map_lock_);
+ request = LookupRequest(request_id, &background_request_map_);
+ if (request) {
+ background_thread_->message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(request.get(),
+ &UrlmonUrlRequest::Read, bytes_to_read));
+ }
+ }
+ if (!request)
+ DLOG(ERROR) << __FUNCTION__ << " no request found for " << request_id;
}
void UrlmonUrlRequestManager::DownloadRequestInHost(int request_id) {
DVLOG(1) << __FUNCTION__ << " " << request_id;
- if (IsWindow(notification_window_)) {
- scoped_refptr<UrlmonUrlRequest> request(LookupRequest(request_id));
- if (request) {
- UrlmonUrlRequest::TerminateBindCallback* callback = NewCallback(this,
- &UrlmonUrlRequestManager::BindTerminated);
- request->TerminateBind(callback);
- } else {
- NOTREACHED();
- }
- } else {
+ if (!IsWindow(notification_window_)) {
NOTREACHED() << "Cannot handle download if we don't have anyone to hand it "
"to.";
+ return;
}
+
+ scoped_refptr<UrlmonUrlRequest> request(LookupRequest(request_id,
+ &request_map_));
+ if (request) {
+ DownloadRequestInHostHelper(request);
+ } else if (background_worker_thread_enabled_) {
+ base::AutoLock lock(background_resource_map_lock_);
+ request = LookupRequest(request_id, &background_request_map_);
+ if (request) {
+ background_thread_->message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &UrlmonUrlRequestManager::DownloadRequestInHostHelper,
+ request.get()));
+ }
+ }
+ if (!request)
+ DLOG(ERROR) << __FUNCTION__ << " no request found for " << request_id;
+}
+
+void UrlmonUrlRequestManager::DownloadRequestInHostHelper(
+ UrlmonUrlRequest* request) {
+ DCHECK(request);
+ UrlmonUrlRequest::TerminateBindCallback* callback = NewCallback(this,
+ &UrlmonUrlRequestManager::BindTerminated);
+ request->TerminateBind(callback);
}
void UrlmonUrlRequestManager::BindTerminated(IMoniker* moniker,
@@ -1153,14 +1223,23 @@ void UrlmonUrlRequestManager::SetCookiesForUrl(const GURL& url,
void UrlmonUrlRequestManager::EndRequest(int request_id) {
DVLOG(1) << __FUNCTION__ << " id: " << request_id;
- DCHECK_EQ(0, calling_delegate_);
- scoped_refptr<UrlmonUrlRequest> request = LookupRequest(request_id);
+ scoped_refptr<UrlmonUrlRequest> request = LookupRequest(request_id,
+ &request_map_);
if (request) {
request_map_.erase(request_id);
request->Stop();
- } else {
- DLOG(ERROR) << __FUNCTION__ << " no request found for " << request_id;
+ } else if (background_worker_thread_enabled_) {
+ base::AutoLock lock(background_resource_map_lock_);
+ request = LookupRequest(request_id, &background_request_map_);
+ if (request) {
+ background_request_map_.erase(request_id);
+ background_thread_->message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(request.get(), &UrlmonUrlRequest::Stop));
+ }
}
+ if (!request)
+ DLOG(ERROR) << __FUNCTION__ << " no request found for " << request_id;
}
void UrlmonUrlRequestManager::StopAll() {
@@ -1173,13 +1252,38 @@ void UrlmonUrlRequestManager::StopAll() {
DVLOG(1) << __FUNCTION__ << " stopping " << request_map_.size()
<< " requests";
- for (RequestMap::iterator it = request_map_.begin();
- it != request_map_.end(); ++it) {
+ StopAllRequestsHelper(&request_map_, NULL);
+
+ if (background_worker_thread_enabled_) {
+ DCHECK(background_thread_.get());
+ background_thread_->message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(
+ this, &UrlmonUrlRequestManager::StopAllRequestsHelper,
+ &background_request_map_, &background_resource_map_lock_));
+ }
+}
+
+void UrlmonUrlRequestManager::StopAllRequestsHelper(
+ RequestMap* request_map,
+ base::Lock* request_map_lock) {
+ DCHECK(request_map);
+
+ DVLOG(1) << __FUNCTION__ << " stopping " << request_map->size()
+ << " requests";
+
+ if (request_map_lock)
+ request_map_lock->Acquire();
+
+ for (RequestMap::iterator it = request_map->begin();
+ it != request_map->end(); ++it) {
DCHECK(it->second != NULL);
it->second->Stop();
}
+ request_map->clear();
- request_map_.clear();
+ if (request_map_lock)
+ request_map_lock->Release();
}
void UrlmonUrlRequestManager::OnResponseStarted(int request_id,
@@ -1188,21 +1292,34 @@ void UrlmonUrlRequestManager::OnResponseStarted(int request_id,
int redirect_status, const net::HostPortPair& socket_address) {
DCHECK_NE(request_id, -1);
DVLOG(1) << __FUNCTION__;
- DCHECK(LookupRequest(request_id) != NULL);
- ++calling_delegate_;
+
+#ifndef NDEBUG
+ scoped_refptr<UrlmonUrlRequest> request = LookupRequest(request_id,
+ &request_map_);
+ if (request == NULL && background_worker_thread_enabled_) {
+ base::AutoLock lock(background_resource_map_lock_);
+ request = LookupRequest(request_id, &background_request_map_);
+ }
+ DCHECK(request != NULL);
+#endif // NDEBUG
delegate_->OnResponseStarted(request_id, mime_type, headers, size,
last_modified, redirect_url, redirect_status, socket_address);
- --calling_delegate_;
}
void UrlmonUrlRequestManager::OnReadComplete(int request_id,
const std::string& data) {
DCHECK_NE(request_id, -1);
DVLOG(1) << __FUNCTION__ << " id: " << request_id;
- DCHECK(LookupRequest(request_id) != NULL);
- ++calling_delegate_;
+#ifndef NDEBUG
+ scoped_refptr<UrlmonUrlRequest> request = LookupRequest(request_id,
+ &request_map_);
+ if (request == NULL && background_worker_thread_enabled_) {
+ base::AutoLock lock(background_resource_map_lock_);
+ request = LookupRequest(request_id, &background_request_map_);
+ }
+ DCHECK(request != NULL);
+#endif // NDEBUG
delegate_->OnReadComplete(request_id, data);
- --calling_delegate_;
DVLOG(1) << __FUNCTION__ << " done id: " << request_id;
}
@@ -1212,15 +1329,17 @@ void UrlmonUrlRequestManager::OnResponseEnd(
DCHECK_NE(request_id, -1);
DVLOG(1) << __FUNCTION__;
DCHECK(status.status() != net::URLRequestStatus::CANCELED);
- RequestMap::size_type n = request_map_.erase(request_id);
- if (n != 1u) {
- DLOG(WARNING) << __FUNCTION__
- << " Failed to find request id:"
- << request_id;
+ RequestMap::size_type erased_count = request_map_.erase(request_id);
+ if (erased_count != 1u && background_worker_thread_enabled_) {
+ base::AutoLock lock(background_resource_map_lock_);
+ erased_count = background_request_map_.erase(request_id);
+ if (erased_count != 1u) {
+ DLOG(WARNING) << __FUNCTION__
+ << " Failed to find request id:"
+ << request_id;
+ }
}
- ++calling_delegate_;
delegate_->OnResponseEnd(request_id, status);
- --calling_delegate_;
}
void UrlmonUrlRequestManager::OnCookiesRetrieved(bool success, const GURL& url,
@@ -1230,22 +1349,33 @@ void UrlmonUrlRequestManager::OnCookiesRetrieved(bool success, const GURL& url,
}
scoped_refptr<UrlmonUrlRequest> UrlmonUrlRequestManager::LookupRequest(
- int request_id) {
- RequestMap::iterator it = request_map_.find(request_id);
- if (request_map_.end() != it)
+ int request_id, RequestMap* request_map) {
+ RequestMap::iterator it = request_map->find(request_id);
+ if (request_map->end() != it)
return it->second;
- DLOG(ERROR) << __FUNCTION__ << " no request found for " << request_id;
return NULL;
}
UrlmonUrlRequestManager::UrlmonUrlRequestManager()
- : stopping_(false), calling_delegate_(0), notification_window_(NULL),
+ : stopping_(false), notification_window_(NULL),
privileged_mode_(false),
- container_(NULL) {
+ container_(NULL),
+ background_worker_thread_enabled_(true) {
+ background_thread_.reset(new ResourceFetcherThread(
+ "cf_iexplore_background_thread"));
+ background_worker_thread_enabled_ =
+ GetConfigBool(true, kUseBackgroundThreadForSubResources);
+ if (background_worker_thread_enabled_) {
+ base::Thread::Options options;
+ options.message_loop_type = MessageLoop::TYPE_UI;
+ background_thread_->StartWithOptions(options);
+ }
}
UrlmonUrlRequestManager::~UrlmonUrlRequestManager() {
StopAll();
+ if (background_worker_thread_enabled_)
+ background_thread_->Stop();
}
void UrlmonUrlRequestManager::AddPrivacyDataForUrl(
@@ -1277,3 +1407,19 @@ void UrlmonUrlRequestManager::AddPrivacyDataForUrl(
0);
}
}
+
+UrlmonUrlRequestManager::ResourceFetcherThread::ResourceFetcherThread(
+ const char* name) : base::Thread(name) {
+}
+
+UrlmonUrlRequestManager::ResourceFetcherThread::~ResourceFetcherThread() {
+}
+
+void UrlmonUrlRequestManager::ResourceFetcherThread::Init() {
+ CoInitialize(NULL);
+}
+
+void UrlmonUrlRequestManager::ResourceFetcherThread::CleanUp() {
+ CoUninitialize();
+}
+
diff --git a/chrome_frame/urlmon_url_request.h b/chrome_frame/urlmon_url_request.h
index 496c33d..8967d9f 100644
--- a/chrome_frame/urlmon_url_request.h
+++ b/chrome_frame/urlmon_url_request.h
@@ -22,6 +22,16 @@ class UrlmonUrlRequestManager
: public PluginUrlRequestManager,
public PluginUrlRequestDelegate {
public:
+ // Sub resources on the pages in chrome frame are fetched on this thread.
+ class ResourceFetcherThread : public base::Thread {
+ public:
+ explicit ResourceFetcherThread(const char* name);
+ virtual ~ResourceFetcherThread();
+
+ virtual void Init();
+ virtual void CleanUp();
+ };
+
// Contains the privacy information for all requests issued by this instance.
struct PrivacyInfo {
public:
@@ -74,7 +84,10 @@ class UrlmonUrlRequestManager
private:
friend class MessageLoop;
friend struct RunnableMethodTraits<UrlmonUrlRequestManager>;
+
+ // This method is needed to support PostTask on this object.
static bool ImplementsThreadSafeReferenceCounting() { return true; }
+
void AddRef() {}
void Release() {}
@@ -109,14 +122,39 @@ class UrlmonUrlRequestManager
void BindTerminated(IMoniker* moniker, IBindCtx* bind_ctx,
IStream* post_data, const char* request_headers);
+ // Helper function to initiate a download request in the host.
+ void DownloadRequestInHostHelper(UrlmonUrlRequest* request);
+
// Map for (request_id <-> UrlmonUrlRequest)
typedef std::map<int, scoped_refptr<UrlmonUrlRequest> > RequestMap;
RequestMap request_map_;
- scoped_refptr<UrlmonUrlRequest> LookupRequest(int request_id);
+ RequestMap background_request_map_;
+
+ // The caller is responsible for acquiring any locks needed to access the
+ // request map.
+ scoped_refptr<UrlmonUrlRequest> LookupRequest(int request_id,
+ RequestMap* request_map);
+ // The background_request_map_ is referenced from multiple threads. Lock to
+ // synchronize access.
+ base::Lock background_resource_map_lock_;
+
+ // Helper function to stop all requests in the request map.
+ void StopAllRequestsHelper(RequestMap* request_map,
+ base::Lock* request_map_lock);
+ // Helper function for initiating a new IE request.
+ void StartRequestHelper(int request_id,
+ const AutomationURLRequest& request_info,
+ RequestMap* request_map,
+ base::Lock* request_map_lock);
+
scoped_refptr<UrlmonUrlRequest> pending_request_;
+ scoped_ptr<ResourceFetcherThread> background_thread_;
bool stopping_;
- int calling_delegate_; // re-entrancy protection (debug only check)
+
+ // Controls whether we download subresources on the page in a background
+ // worker thread.
+ bool background_worker_thread_enabled_;
PrivacyInfo privacy_info_;
// The window to be used to fire notifications on.
diff --git a/chrome_frame/urlmon_url_request_private.h b/chrome_frame/urlmon_url_request_private.h
index f378d8f..b4075b5 100644
--- a/chrome_frame/urlmon_url_request_private.h
+++ b/chrome_frame/urlmon_url_request_private.h
@@ -58,6 +58,10 @@ class UrlmonUrlRequest
// to identify request objects in the log.
std::string me() const;
+ static bool ImplementsThreadSafeReferenceCounting() {
+ return true;
+ }
+
protected:
UrlmonUrlRequest();
~UrlmonUrlRequest();
diff --git a/chrome_frame/utils.cc b/chrome_frame/utils.cc
index 283de44..82436f3 100644
--- a/chrome_frame/utils.cc
+++ b/chrome_frame/utils.cc
@@ -83,6 +83,11 @@ const wchar_t kChromeFrameAccessibleMode[] = L"ChromeFrameAccessibleMode";
// DLL pinning, such as the perf tests.
const wchar_t kChromeFrameUnpinnedMode[] = L"kChromeFrameUnpinnedMode";
+// Controls whether we download subresources, etc on the chrome frame page in
+// the background worker thread. Defaults to true.
+const wchar_t kUseBackgroundThreadForSubResources[]
+ = L"BackgroundHTTPWorkerThread";
+
// {1AF32B6C-A3BA-48B9-B24E-8AA9C41F6ECD}
static const IID IID_IWebBrowserPriv2IE7 = { 0x1AF32B6C, 0xA3BA, 0x48B9,
{ 0xB2, 0x4E, 0x8A, 0xA9, 0xC4, 0x1F, 0x6E, 0xCD } };
diff --git a/chrome_frame/utils.h b/chrome_frame/utils.h
index 6d6a5d6..95feac6 100644
--- a/chrome_frame/utils.h
+++ b/chrome_frame/utils.h
@@ -43,6 +43,7 @@ extern const wchar_t kRenderInHostUrlList[];
extern const wchar_t kEnableGCFRendererByDefault[];
extern const wchar_t kIexploreProfileName[];
extern const wchar_t kRundllProfileName[];
+extern const wchar_t kUseBackgroundThreadForSubResources[];
// This function is very similar to the AtlRegisterTypeLib function except
// that it takes a parameter that specifies whether to register the typelib