summaryrefslogtreecommitdiffstats
path: root/chrome_frame
diff options
context:
space:
mode:
authorananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-24 01:29:20 +0000
committerananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-24 01:29:20 +0000
commit5778de6e6bfbc0439f49a245a75efa44e4f9a771 (patch)
tree7596aff0328ee022a23a9a0e84c28f94ee40ea30 /chrome_frame
parentb5be3f53d7af0037dbc634beb550752de56ad840 (diff)
downloadchromium_src-5778de6e6bfbc0439f49a245a75efa44e4f9a771.zip
chromium_src-5778de6e6bfbc0439f49a245a75efa44e4f9a771.tar.gz
chromium_src-5778de6e6bfbc0439f49a245a75efa44e4f9a771.tar.bz2
Currently the host network stack in IE which uses Urlmon interfaces to initiate
and complete URL downloads requested by ChromeFrame, executes in the UI thread of IE. While this works fine in most cases for large data sizes, the IE UI thread ends up being busy pulling the data in our IBindStatusCallback::OnDataAvailable implementation. As a result the browser hangs until all data is pulled out. The fix is to handle Urlmon requests on a separate thread. This fixes http://code.google.com/p/chromium/issues/detail?id=24007 Changes to plugin_url_request.cc/.h are to set the LF property on these files. Bug=24007 Review URL: http://codereview.chromium.org/292035 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29986 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame')
-rw-r--r--chrome_frame/chrome_frame_activex_base.h55
-rw-r--r--chrome_frame/chrome_frame_automation.cc2
-rw-r--r--chrome_frame/chrome_frame_automation.h36
-rw-r--r--chrome_frame/chrome_frame_delegate.h45
-rw-r--r--chrome_frame/plugin_url_request.h3
-rw-r--r--chrome_frame/urlmon_url_request.cc110
-rw-r--r--chrome_frame/urlmon_url_request.h31
7 files changed, 210 insertions, 72 deletions
diff --git a/chrome_frame/chrome_frame_activex_base.h b/chrome_frame/chrome_frame_activex_base.h
index 651ecbf..bbd88dc 100644
--- a/chrome_frame/chrome_frame_activex_base.h
+++ b/chrome_frame/chrome_frame_activex_base.h
@@ -150,13 +150,19 @@ class ATL_NO_VTABLE ChromeFrameActivexBase :
public IPropertyNotifySinkCP<T>,
public CComCoClass<T, &class_id>,
public CComControl<T>,
- public ChromeFramePlugin<T> {
+ public ChromeFramePlugin<T>,
+ public TaskMarshallerThroughWindowsMessages<
+ ChromeFrameActivexBase<T, class_id> > {
protected:
typedef std::set<ScopedComPtr<IDispatch> > EventHandlers;
+ typedef TaskMarshallerThroughWindowsMessages<
+ ChromeFrameActivexBase<T, class_id> > TaskMarshaller;
+ typedef ChromeFrameActivexBase<T, class_id> Base;
public:
ChromeFrameActivexBase()
- : ready_state_(READYSTATE_UNINITIALIZED) {
+ : ready_state_(READYSTATE_UNINITIALIZED),
+ worker_thread_("ChromeFrameWorker_Thread") {
m_bWindowOnly = TRUE;
}
@@ -197,6 +203,7 @@ BEGIN_MSG_MAP(ChromeFrameActivexBase)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
CHAIN_MSG_MAP(ChromeFramePlugin<T>)
CHAIN_MSG_MAP(CComControl<T>)
+ CHAIN_MSG_MAP(TaskMarshaller)
DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP()
@@ -231,6 +238,12 @@ END_MSG_MAP()
IE_8,
IE_8 + 1);
}
+
+ base::Thread::Options options;
+ options.message_loop_type = MessageLoop::TYPE_UI;
+ worker_thread_.StartWithOptions(options);
+ worker_thread_.message_loop()->PostTask(
+ FROM_HERE, NewRunnableMethod(this, &Base::OnWorkerStart));
return S_OK;
}
@@ -302,10 +315,21 @@ END_MSG_MAP()
// of this template should implement this method based on how
// it "feels" from a security perspective. If it's hosted in another
// scriptable document, return true, else false.
- virtual bool is_frame_busting_enabled() const {
+ bool is_frame_busting_enabled() const {
return true;
}
+ // Needed to support PostTask.
+ static bool ImplementsThreadSafeReferenceCounting() {
+ return true;
+ }
+
+ virtual void OnFinalMessage(HWND) {
+ worker_thread_.message_loop()->PostTask(
+ FROM_HERE, NewRunnableMethod(this, &Base::OnWorkerStop));
+ worker_thread_.Stop();
+ }
+
protected:
virtual void OnTabbedOut(int tab_handle, bool reverse) {
DCHECK(m_bInPlaceActive);
@@ -419,12 +443,13 @@ END_MSG_MAP()
DCHECK(request.get() != NULL);
- if (request->Initialize(automation_client_.get(), tab_handle, request_id,
- request_info.url, request_info.method,
- request_info.referrer,
- request_info.extra_request_headers,
- request_info.upload_data.get(),
- static_cast<T*>(this)->is_frame_busting_enabled())) {
+ if (request->Initialize(
+ automation_client_.get(), tab_handle, request_id, request_info.url,
+ request_info.method, request_info.referrer,
+ request_info.extra_request_headers, request_info.upload_data.get(),
+ static_cast<T*>(this)->is_frame_busting_enabled())) {
+ request->set_worker_thread(&worker_thread_);
+ request->set_task_marshaller(this);
// If Start is successful, it will add a self reference.
request->Start();
request->set_parent_window(m_hWnd);
@@ -941,6 +966,16 @@ END_MSG_MAP()
}
protected:
+ // The following functions are called to initialize and uninitialize the
+ // worker thread.
+ void OnWorkerStart() {
+ CoInitialize(NULL);
+ }
+
+ void OnWorkerStop() {
+ CoUninitialize();
+ }
+
ScopedBstr url_;
ScopedComPtr<IOleDocumentSite> doc_site_;
@@ -963,6 +998,8 @@ END_MSG_MAP()
// The UrlmonUrlRequest instance instantiated for downloading the base URL.
scoped_refptr<CComObject<UrlmonUrlRequest> > base_url_request_;
+
+ base::Thread worker_thread_;
};
#endif // CHROME_FRAME_CHROME_FRAME_ACTIVEX_BASE_H_
diff --git a/chrome_frame/chrome_frame_automation.cc b/chrome_frame/chrome_frame_automation.cc
index 2d22bbd..d84cbd3 100644
--- a/chrome_frame/chrome_frame_automation.cc
+++ b/chrome_frame/chrome_frame_automation.cc
@@ -1000,8 +1000,8 @@ void ChromeFrameAutomationClient::RemoveRequest(
PluginUrlRequest* request = LookupRequest(request_id);
if (request) {
if (abort) {
+ // The request object will get removed asynchronously.
request->Stop();
- DCHECK(request_map_.end() == request_map_.find(request_id));
} else {
request_map_.erase(request_id);
}
diff --git a/chrome_frame/chrome_frame_automation.h b/chrome_frame/chrome_frame_automation.h
index 6eca88d..f2120e2 100644
--- a/chrome_frame/chrome_frame_automation.h
+++ b/chrome_frame/chrome_frame_automation.h
@@ -144,35 +144,6 @@ class ProxyFactory {
int uma_send_interval_;
};
-// T is expected to be something CWindowImpl derived, or at least to have
-// PostMessage(UINT, WPARAM) method. Do not forget to CHAIN_MSG_MAP
-template <class T> class TaskMarshallerThroughWindowsMessages {
- public:
- void PostTask(const tracked_objects::Location& from_here, Task* task) {
- task->SetBirthPlace(from_here);
- T* this_ptr = static_cast<T*>(this);
- if (this_ptr->IsWindow()) {
- this_ptr->PostMessage(MSG_EXECUTE_TASK, reinterpret_cast<WPARAM>(task));
- } else {
- DLOG(INFO) << "Dropping MSG_EXECUTE_TASK message for destroyed window.";
- }
- }
-
- BEGIN_MSG_MAP(PostMessageMarshaller)
- MESSAGE_HANDLER(MSG_EXECUTE_TASK, ExecuteTask)
- END_MSG_MAP()
-
- private:
- enum { MSG_EXECUTE_TASK = WM_APP + 6 };
- inline LRESULT ExecuteTask(UINT, WPARAM wparam, LPARAM,
- BOOL& handled) { // NOLINT
- Task* task = reinterpret_cast<Task*>(wparam);
- task->Run();
- delete task;
- return 0;
- }
-};
-
// Handles all automation requests initiated from the chrome frame objects.
// These include the chrome tab/chrome frame activex/chrome frame npapi
// plugin objects.
@@ -296,6 +267,13 @@ class ChromeFrameAutomationClient
void SetPageFontSize(enum AutomationPageFontSize);
+ // Dummy reference counting functions to enable us to use the
+ // TaskMarshallerThroughWindowsMessages functionality. At this point we don't
+ // need to ensure that any tasks executed on us grab a reference to ensure
+ // that the instance remains valid.
+ void AddRef() {}
+ void Release() {}
+
protected:
// ChromeFrameAutomationProxy::LaunchDelegate implementation.
virtual void LaunchComplete(ChromeFrameAutomationProxy* proxy,
diff --git a/chrome_frame/chrome_frame_delegate.h b/chrome_frame/chrome_frame_delegate.h
index e11f099..bbdc99e 100644
--- a/chrome_frame/chrome_frame_delegate.h
+++ b/chrome_frame/chrome_frame_delegate.h
@@ -5,6 +5,9 @@
#ifndef CHROME_FRAME_CHROME_FRAME_DELEGATE_H_
#define CHROME_FRAME_CHROME_FRAME_DELEGATE_H_
+#include <atlbase.h>
+#include <atlwin.h>
+
#include "chrome/test/automation/automation_messages.h"
#include "ipc/ipc_message.h"
@@ -12,7 +15,6 @@
// implementations.
class ChromeFrameDelegate {
public:
-
typedef HWND WindowType;
virtual WindowType GetWindow() const = 0;
@@ -103,4 +105,45 @@ class ChromeFrameDelegateImpl : public ChromeFrameDelegate {
virtual void OnGoToHistoryEntryOffset(int tab_handle, int offset) {}
};
+// This interface enables tasks to be marshalled to desired threads.
+class TaskMarshaller {
+ public:
+ virtual void PostTask(const tracked_objects::Location& from_here,
+ Task* task) = 0;
+};
+
+// T is expected to be something CWindowImpl derived, or at least to have
+// PostMessage(UINT, WPARAM) method. Do not forget to CHAIN_MSG_MAP
+template <class T> class TaskMarshallerThroughWindowsMessages
+ : public TaskMarshaller {
+ public:
+ virtual void PostTask(const tracked_objects::Location& from_here,
+ Task* task) {
+ task->SetBirthPlace(from_here);
+ T* this_ptr = static_cast<T*>(this);
+ if (this_ptr->IsWindow()) {
+ this_ptr->AddRef();
+ this_ptr->PostMessage(MSG_EXECUTE_TASK, reinterpret_cast<WPARAM>(task));
+ } else {
+ DLOG(INFO) << "Dropping MSG_EXECUTE_TASK message for destroyed window.";
+ }
+ }
+
+ BEGIN_MSG_MAP(PostMessageMarshaller)
+ MESSAGE_HANDLER(MSG_EXECUTE_TASK, ExecuteTask)
+ END_MSG_MAP()
+
+ private:
+ enum { MSG_EXECUTE_TASK = WM_APP + 6 };
+ inline LRESULT ExecuteTask(UINT, WPARAM wparam, LPARAM,
+ BOOL& handled) { // NOLINT
+ Task* task = reinterpret_cast<Task*>(wparam);
+ task->Run();
+ delete task;
+ T* this_ptr = static_cast<T*>(this);
+ this_ptr->Release();
+ return 0;
+ }
+};
+
#endif // CHROME_FRAME_CHROME_FRAME_DELEGATE_H_
diff --git a/chrome_frame/plugin_url_request.h b/chrome_frame/plugin_url_request.h
index fb28c77..8c38b92 100644
--- a/chrome_frame/plugin_url_request.h
+++ b/chrome_frame/plugin_url_request.h
@@ -13,6 +13,7 @@
#include "net/base/upload_data.h"
#include "net/url_request/url_request_status.h"
#include "base/ref_counted.h"
+#include "chrome_frame/chrome_frame_delegate.h"
class PluginUrlRequest;
@@ -52,7 +53,7 @@ class PluginUrlRequest : public UrlRequestReference {
// These cookies are sent when we receive a response for every URL request
// initiated by Chrome. Ideally we should only send cookies for the top level
// URL and any subframes. However we don't receive information from Chrome
- // about the context for a URL, i.e. whether it is a subframe, etc.
+ // about the context for a URL, i.e. whether it is a subframe, etc.
// Additionally cookies for a URL should be sent once for the page. This
// is not done now as it is difficult to track URLs, specifically if they
// are redirected, etc.
diff --git a/chrome_frame/urlmon_url_request.cc b/chrome_frame/urlmon_url_request.cc
index 4d91607..d64cc62 100644
--- a/chrome_frame/urlmon_url_request.cc
+++ b/chrome_frame/urlmon_url_request.cc
@@ -9,6 +9,8 @@
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/logging.h"
+#include "base/message_loop.h"
+#include "chrome_frame/chrome_frame_activex_base.h"
#include "chrome_frame/urlmon_upload_data_stream.h"
#include "chrome_frame/utils.h"
#include "net/http/http_util.h"
@@ -23,10 +25,11 @@ UrlmonUrlRequest::UrlmonUrlRequest()
: pending_read_size_(0),
status_(URLRequestStatus::FAILED, net::ERR_FAILED),
thread_(PlatformThread::CurrentId()),
- is_request_started_(false),
post_data_len_(0),
redirect_status_(0),
- parent_window_(NULL) {
+ parent_window_(NULL),
+ worker_thread_(NULL),
+ task_marshaller_(NULL) {
DLOG(INFO) << StringPrintf("Created request. Obj: %X", this)
<< " Count: " << ++instance_count_;
}
@@ -39,22 +42,16 @@ UrlmonUrlRequest::~UrlmonUrlRequest() {
bool UrlmonUrlRequest::Start() {
DCHECK_EQ(PlatformThread::CurrentId(), thread_);
- status_.set_status(URLRequestStatus::IO_PENDING);
- HRESULT hr = StartAsyncDownload();
- if (FAILED(hr)) {
- // Do not call EndRequest() here since it will attempt to free references
- // that have not been established.
- status_.set_os_error(HresultToNetError(hr));
- status_.set_status(URLRequestStatus::FAILED);
- DLOG(ERROR) << "StartAsyncDownload failed";
- OnResponseEnd(status_);
+ if (!worker_thread_) {
+ NOTREACHED() << __FUNCTION__ << " Urlmon request thread not initialized";
return false;
}
+ worker_thread_->message_loop()->PostTask(
+ FROM_HERE, NewRunnableMethod(this, &UrlmonUrlRequest::StartAsync));
+
// Take a self reference to maintain COM lifetime. This will be released
- // in EndRequest. Set a flag indicating that we have an additional
- // reference here
- is_request_started_ = true;
+ // in EndRequest
AddRef();
request_handler()->AddRequest(this);
return true;
@@ -63,6 +60,34 @@ bool UrlmonUrlRequest::Start() {
void UrlmonUrlRequest::Stop() {
DCHECK_EQ(PlatformThread::CurrentId(), thread_);
+ if (!worker_thread_) {
+ NOTREACHED() << __FUNCTION__ << " Urlmon request thread not initialized";
+ return;
+ }
+
+ worker_thread_->message_loop()->PostTask(
+ FROM_HERE, NewRunnableMethod(this, &UrlmonUrlRequest::StopAsync));
+}
+
+void UrlmonUrlRequest::StartAsync() {
+ DCHECK(worker_thread_ != NULL);
+
+ status_.set_status(URLRequestStatus::IO_PENDING);
+ HRESULT hr = StartAsyncDownload();
+ if (FAILED(hr)) {
+ // Do not call EndRequest() here since it will attempt to free references
+ // that have not been established.
+ status_.set_os_error(HresultToNetError(hr));
+ status_.set_status(URLRequestStatus::FAILED);
+ DLOG(ERROR) << "StartAsyncDownload failed";
+ EndRequest();
+ return;
+ }
+}
+
+void UrlmonUrlRequest::StopAsync() {
+ DCHECK(worker_thread_ != NULL);
+
if (binding_) {
binding_->Abort();
} else {
@@ -77,15 +102,28 @@ bool UrlmonUrlRequest::Read(int bytes_to_read) {
DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this);
+ if (!worker_thread_) {
+ NOTREACHED() << __FUNCTION__ << " Urlmon request thread not initialized";
+ return false;
+ }
+
+ worker_thread_->message_loop()->PostTask(
+ FROM_HERE, NewRunnableMethod(this, &UrlmonUrlRequest::ReadAsync,
+ bytes_to_read));
+ return true;
+}
+
+void UrlmonUrlRequest::ReadAsync(int bytes_to_read) {
// Send cached data if available.
CComObjectStackEx<SendStream> send_stream;
send_stream.Initialize(this);
+
size_t bytes_copied = 0;
if (cached_data_.is_valid() && cached_data_.Read(&send_stream, bytes_to_read,
&bytes_copied)) {
DLOG(INFO) << StringPrintf("URL: %s Obj: %X - bytes read from cache: %d",
url().c_str(), this, bytes_copied);
- return true;
+ return;
}
// if the request is finished or there's nothing more to read
@@ -94,13 +132,12 @@ bool UrlmonUrlRequest::Read(int bytes_to_read) {
DLOG(INFO) << StringPrintf("URL: %s Obj: %X. Response finished. Status: %d",
url().c_str(), this, status_.status());
EndRequest();
- return true;
+ return;
}
pending_read_size_ = bytes_to_read;
DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
"- Read pending for: " << bytes_to_read;
- return true;
}
STDMETHODIMP UrlmonUrlRequest::OnStartBinding(
@@ -143,7 +180,8 @@ STDMETHODIMP UrlmonUrlRequest::OnProgress(ULONG progress, ULONG max_progress,
}
STDMETHODIMP UrlmonUrlRequest::OnStopBinding(HRESULT result, LPCWSTR error) {
- DCHECK_EQ(PlatformThread::CurrentId(), thread_);
+ DCHECK(worker_thread_ != NULL);
+ DCHECK_EQ(PlatformThread::CurrentId(), worker_thread_->thread_id());
DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
" - Request stopped, Result: " << std::hex << result <<
@@ -167,7 +205,8 @@ STDMETHODIMP UrlmonUrlRequest::OnStopBinding(HRESULT result, LPCWSTR error) {
STDMETHODIMP UrlmonUrlRequest::GetBindInfo(DWORD* bind_flags,
BINDINFO *bind_info) {
- DCHECK_EQ(PlatformThread::CurrentId(), thread_);
+ DCHECK(worker_thread_ != NULL);
+ DCHECK_EQ(PlatformThread::CurrentId(), worker_thread_->thread_id());
if ((bind_info == NULL) || (bind_info->cbSize == 0) || (bind_flags == NULL))
return E_INVALIDARG;
@@ -224,7 +263,9 @@ STDMETHODIMP UrlmonUrlRequest::GetBindInfo(DWORD* bind_flags,
STDMETHODIMP UrlmonUrlRequest::OnDataAvailable(DWORD flags, DWORD size,
FORMATETC* formatetc,
STGMEDIUM* storage) {
- DCHECK_EQ(PlatformThread::CurrentId(), thread_);
+ DCHECK(worker_thread_ != NULL);
+ DCHECK_EQ(PlatformThread::CurrentId(), worker_thread_->thread_id());
+
DLOG(INFO) << StringPrintf("URL: %s Obj: %X - Bytes available: %d",
url().c_str(), this, size);
@@ -285,7 +326,9 @@ STDMETHODIMP UrlmonUrlRequest::OnObjectAvailable(REFIID iid, IUnknown *object) {
STDMETHODIMP UrlmonUrlRequest::BeginningTransaction(const wchar_t* url,
const wchar_t* current_headers, DWORD reserved,
wchar_t** additional_headers) {
- DCHECK_EQ(PlatformThread::CurrentId(), thread_);
+ DCHECK(worker_thread_ != NULL);
+ DCHECK_EQ(PlatformThread::CurrentId(), worker_thread_->thread_id());
+
if (!additional_headers) {
NOTREACHED();
return E_POINTER;
@@ -333,7 +376,8 @@ STDMETHODIMP UrlmonUrlRequest::BeginningTransaction(const wchar_t* url,
STDMETHODIMP UrlmonUrlRequest::OnResponse(DWORD dwResponseCode,
const wchar_t* response_headers, const wchar_t* request_headers,
wchar_t** additional_headers) {
- DCHECK_EQ(PlatformThread::CurrentId(), thread_);
+ DCHECK(worker_thread_ != NULL);
+ DCHECK_EQ(PlatformThread::CurrentId(), worker_thread_->thread_id());
std::string raw_headers = WideToUTF8(response_headers);
@@ -552,15 +596,22 @@ void UrlmonUrlRequest::EndRequest() {
status_.set_os_error(net::ERR_UNSAFE_REDIRECT);
}
}
- request_handler()->RemoveRequest(this);
+
OnResponseEnd(status_);
- // If the request was started then we must have an additional reference on the
- // request.
- if (is_request_started_) {
- is_request_started_ = false;
- Release();
- }
+ DCHECK(task_marshaller_ != NULL);
+
+ // Remove the request mapping and release the outstanding reference to us in
+ // the context of the UI thread.
+ task_marshaller_->PostTask(
+ FROM_HERE, NewRunnableMethod(this, &UrlmonUrlRequest::EndRequestInternal));
+}
+
+void UrlmonUrlRequest::EndRequestInternal() {
+ request_handler()->RemoveRequest(this);
+ // Release the outstanding reference in the context of the UI thread to
+ // ensure that our instance gets deleted in the same thread which created it.
+ Release();
}
int UrlmonUrlRequest::GetHttpResponseStatus() const {
@@ -677,6 +728,7 @@ bool UrlmonUrlRequest::Cache::Append(IStream* source,
while (SUCCEEDED(hr)) {
DWORD chunk_read = 0; // NOLINT
hr = source->Read(read_buffer_, sizeof(read_buffer_), &chunk_read);
+
if (!chunk_read)
break;
diff --git a/chrome_frame/urlmon_url_request.h b/chrome_frame/urlmon_url_request.h
index 114ee6b..3c64243f 100644
--- a/chrome_frame/urlmon_url_request.h
+++ b/chrome_frame/urlmon_url_request.h
@@ -13,8 +13,10 @@
#include "base/lock.h"
#include "base/platform_thread.h"
+#include "base/thread.h"
#include "base/scoped_comptr_win.h"
#include "chrome_frame/plugin_url_request.h"
+#include "chrome_frame/chrome_frame_delegate.h"
#include "net/base/net_errors.h"
#include "net/base/upload_data.h"
@@ -87,8 +89,32 @@ END_SERVICE_MAP()
parent_window_ = parent_window;
}
+ // Needed to support PostTask.
+ static bool ImplementsThreadSafeReferenceCounting() {
+ return true;
+ }
+
+ // URL requests are handled on this thread.
+ void set_worker_thread(base::Thread* worker_thread) {
+ worker_thread_ = worker_thread;
+ }
+
+ void set_task_marshaller(TaskMarshaller* task_marshaller) {
+ task_marshaller_ = task_marshaller;
+ }
+
protected:
+ // The following functions issue and handle Urlmon requests on the dedicated
+ // Urlmon thread.
+ void StartAsync();
+ void StopAsync();
+ void ReadAsync(int bytes_to_read);
+
static const size_t kCopyChunkSize = 32 * 1024;
+ // URL requests are handled on this thread.
+ base::Thread* worker_thread_;
+
+ TaskMarshaller* task_marshaller_;
// A fake stream class to make it easier to copy received data using
// IStream::CopyTo instead of allocating temporary buffers and keeping
@@ -203,7 +229,9 @@ END_SERVICE_MAP()
HRESULT StartAsyncDownload();
void EndRequest();
-
+ // Executes in the context of the UI thread and releases the outstanding
+ // reference to us. It also deletes the request mapping for this instance.
+ void EndRequestInternal();
int GetHttpResponseStatus() const;
static net::Error HresultToNetError(HRESULT hr);
@@ -221,7 +249,6 @@ END_SERVICE_MAP()
uint64 post_data_len_;
PlatformThreadId thread_;
- bool is_request_started_;
static int instance_count_;
HWND parent_window_;
DISALLOW_COPY_AND_ASSIGN(UrlmonUrlRequest);