summaryrefslogtreecommitdiffstats
path: root/chrome_frame
diff options
context:
space:
mode:
Diffstat (limited to 'chrome_frame')
-rw-r--r--chrome_frame/chrome_active_document.cc4
-rw-r--r--chrome_frame/chrome_frame_activex_base.h5
-rw-r--r--chrome_frame/chrome_frame_automation.cc3
-rw-r--r--chrome_frame/chrome_frame_automation.h2
-rw-r--r--chrome_frame/npapi_url_request.cc13
-rw-r--r--chrome_frame/npapi_url_request.h4
-rw-r--r--chrome_frame/plugin_url_request.h61
-rw-r--r--chrome_frame/test/automation_client_mock.h2
-rw-r--r--chrome_frame/test/url_request_test.cc43
-rw-r--r--chrome_frame/urlmon_url_request.cc414
-rw-r--r--chrome_frame/urlmon_url_request.h73
-rw-r--r--chrome_frame/urlmon_url_request_private.h114
12 files changed, 303 insertions, 435 deletions
diff --git a/chrome_frame/chrome_active_document.cc b/chrome_frame/chrome_active_document.cc
index 80ccd23..cec1b46 100644
--- a/chrome_frame/chrome_active_document.cc
+++ b/chrome_frame/chrome_active_document.cc
@@ -266,8 +266,8 @@ STDMETHODIMP ChromeActiveDocument::Load(BOOL fully_avalable,
return E_INVALIDARG;
}
- if (!is_chrome_protocol && data) {
- url_fetcher_.UseRequestDataForUrl(data, url);
+ if (!is_chrome_protocol) {
+ url_fetcher_.SetInfoForUrl(url, moniker_name, bind_context);
}
THREAD_SAFE_UMA_HISTOGRAM_CUSTOM_COUNTS("ChromeFrame.FullTabLaunchType",
diff --git a/chrome_frame/chrome_frame_activex_base.h b/chrome_frame/chrome_frame_activex_base.h
index bb516af..d43c4ea 100644
--- a/chrome_frame/chrome_frame_activex_base.h
+++ b/chrome_frame/chrome_frame_activex_base.h
@@ -426,14 +426,13 @@ END_MSG_MAP()
BOOL& handled) {
ScopedComPtr<IMoniker> moniker(reinterpret_cast<IMoniker*>(lparam));
DCHECK(moniker);
+ ScopedComPtr<IBindCtx> bind_context(reinterpret_cast<IBindCtx*>(wparam));
+
// TODO(tommi): It looks like we might have to switch the request object
// into a pass-through request object and serve up any thus far received
// content and headers to IE in order to prevent what can currently happen
// which is reissuing requests and turning POST into GET.
if (moniker) {
- ScopedComPtr<IBindCtx> bind_context;
- ::CreateBindCtx(0, bind_context.Receive());
- DCHECK(bind_context);
NavigateBrowserToMoniker(doc_site_, moniker, NULL, bind_context, NULL);
}
diff --git a/chrome_frame/chrome_frame_automation.cc b/chrome_frame/chrome_frame_automation.cc
index eed34e5..aa88def 100644
--- a/chrome_frame/chrome_frame_automation.cc
+++ b/chrome_frame/chrome_frame_automation.cc
@@ -1298,8 +1298,7 @@ void ChromeFrameAutomationClient::OnResponseStarted(int request_id,
}
void ChromeFrameAutomationClient::OnReadComplete(int request_id,
- const void* buffer, int len) {
- std::string data(reinterpret_cast<const char*>(buffer), len);
+ const std::string& data) {
automation_server_->Send(new AutomationMsg_RequestData(0, tab_->handle(),
request_id, data));
}
diff --git a/chrome_frame/chrome_frame_automation.h b/chrome_frame/chrome_frame_automation.h
index c995883..2387a12 100644
--- a/chrome_frame/chrome_frame_automation.h
+++ b/chrome_frame/chrome_frame_automation.h
@@ -357,7 +357,7 @@ class ChromeFrameAutomationClient
virtual void OnResponseStarted(int request_id, const char* mime_type,
const char* headers, int size, base::Time last_modified,
const std::string& redirect_url, int redirect_status);
- virtual void OnReadComplete(int request_id, const void* buffer, int len);
+ virtual void OnReadComplete(int request_id, const std::string& data);
virtual void OnResponseEnd(int request_id, const URLRequestStatus& status);
virtual bool SendIPCMessage(IPC::Message* msg);
diff --git a/chrome_frame/npapi_url_request.cc b/chrome_frame/npapi_url_request.cc
index f928327..5306fb9 100644
--- a/chrome_frame/npapi_url_request.cc
+++ b/chrome_frame/npapi_url_request.cc
@@ -166,7 +166,8 @@ int NPAPIUrlRequest::OnWriteReady() {
int NPAPIUrlRequest::OnWrite(void* buffer, int len) {
pending_read_size_ = 0;
- delegate_->OnReadComplete(id(), buffer, len);
+ std::string data(reinterpret_cast<char*>(buffer), len);
+ delegate_->OnReadComplete(id(), data);
return len;
}
@@ -198,13 +199,13 @@ bool NPAPIUrlRequestManager::IsThreadSafe() {
}
void NPAPIUrlRequestManager::StartRequest(int request_id,
- const ThreadSafeAutomationUrlRequest& request_info) {
+ const IPC::AutomationURLRequest& request_info) {
scoped_refptr<NPAPIUrlRequest> new_request(new NPAPIUrlRequest(instance_));
DCHECK(new_request);
if (new_request->Initialize(this, request_id, request_info.url,
request_info.method, request_info.referrer,
request_info.extra_request_headers,
- request_info.upload_data.get()->get_data(),
+ request_info.upload_data,
enable_frame_busting_)) {
// Add to map.
DCHECK(request_map_.find(request_id) == request_map_.end());
@@ -256,9 +257,9 @@ void NPAPIUrlRequestManager::OnResponseStarted(int request_id,
last_modified, redirect_url, redirect_status);
}
-void NPAPIUrlRequestManager::OnReadComplete(int request_id, const void* buffer,
- int len) {
- delegate_->OnReadComplete(request_id, buffer, len);
+void NPAPIUrlRequestManager::OnReadComplete(int request_id,
+ const std::string& data) {
+ delegate_->OnReadComplete(request_id, data);
}
void NPAPIUrlRequestManager::OnResponseEnd(int request_id,
diff --git a/chrome_frame/npapi_url_request.h b/chrome_frame/npapi_url_request.h
index 64817eb..a059176 100644
--- a/chrome_frame/npapi_url_request.h
+++ b/chrome_frame/npapi_url_request.h
@@ -36,7 +36,7 @@ class NPAPIUrlRequestManager : public PluginUrlRequestManager,
// PluginUrlRequestManager implementation. Called from AutomationClient.
virtual bool IsThreadSafe();
virtual void StartRequest(int request_id,
- const ThreadSafeAutomationUrlRequest& request_info);
+ const IPC::AutomationURLRequest& request_info);
virtual void ReadRequest(int request_id, int bytes_to_read);
virtual void EndRequest(int request_id);
virtual void DownloadRequestInHost(int request_id) {
@@ -54,7 +54,7 @@ class NPAPIUrlRequestManager : public PluginUrlRequestManager,
virtual void OnResponseStarted(int request_id, const char* mime_type,
const char* headers, int size, base::Time last_modified,
const std::string& redirect_url, int redirect_status);
- virtual void OnReadComplete(int request_id, const void* buffer, int len);
+ virtual void OnReadComplete(int request_id, const std::string& data);
virtual void OnResponseEnd(int request_id, const URLRequestStatus& status);
static inline NPAPIUrlRequest* RequestFromNotifyData(void* notify_data) {
diff --git a/chrome_frame/plugin_url_request.h b/chrome_frame/plugin_url_request.h
index dbec76f..aea4fa8 100644
--- a/chrome_frame/plugin_url_request.h
+++ b/chrome_frame/plugin_url_request.h
@@ -21,67 +21,12 @@ class PluginUrlRequest;
class PluginUrlRequestDelegate;
class PluginUrlRequestManager;
-// A thread-safe ref-counted wrapper for the non-thread-safe ref-counted
-// net::UploadData. I'm trying to avoid making net::UploadData thread-safe
-// as it is a widely used data structure whose performance characteristics
-// I do not wish to change.
-class UploadDataThreadSafe
- : public base::RefCountedThreadSafe<UploadDataThreadSafe> {
- public:
- explicit UploadDataThreadSafe(net::UploadData* upload_data) {
- DCHECK(upload_data == NULL || upload_data->HasOneRef());
- upload_data_ = upload_data;
- }
-
- net::UploadData* get_data() {
- DCHECK(upload_data_.get() == NULL || upload_data_->HasOneRef());
- return upload_data_.get();
- }
-
- private:
- scoped_refptr<net::UploadData> upload_data_;
-};
-
-// A class that can be used in place of an IPC::AutomationUrlRequest but can be
-// safely passed across threads. Note that this takes ownership of the
-// net::UploadData instance and that the instance must have a ref_count of
-// exactly 1 when this is called.
-class ThreadSafeAutomationUrlRequest {
- public:
- // Note that the constructor mutates the "const" ipc_request parameter.
- explicit ThreadSafeAutomationUrlRequest(
- const IPC::AutomationURLRequest& ipc_request)
- : url(ipc_request.url), method(ipc_request.method),
- referrer(ipc_request.referrer),
- extra_request_headers(ipc_request.extra_request_headers) {
- // Make sure that we have exactly one reference when taking ownership.
- net::UploadData* temp_data = const_cast<IPC::AutomationURLRequest&>(
- ipc_request).upload_data.release();
- DCHECK(temp_data == NULL || temp_data->HasOneRef());
-
- upload_data = new UploadDataThreadSafe(temp_data);
-
- if (temp_data) {
- temp_data->Release();
- }
- // Make sure that we have exactly one reference after taking ownership.
- DCHECK(temp_data == NULL || temp_data->HasOneRef());
- }
-
- std::string url;
- std::string method;
- std::string referrer;
- std::string extra_request_headers;
- scoped_refptr<UploadDataThreadSafe> upload_data;
-};
-
-
class DECLSPEC_NOVTABLE PluginUrlRequestDelegate { // NOLINT
public:
virtual void OnResponseStarted(int request_id, const char* mime_type,
const char* headers, int size, base::Time last_modified,
const std::string& redirect_url, int redirect_status) = 0;
- virtual void OnReadComplete(int request_id, const void* buffer, int len) = 0;
+ virtual void OnReadComplete(int request_id, const std::string& data) = 0;
virtual void OnResponseEnd(int request_id,
const URLRequestStatus& status) = 0;
virtual void AddPrivacyDataForUrl(const std::string& url,
@@ -116,7 +61,7 @@ class DECLSPEC_NOVTABLE PluginUrlRequestManager { // NOLINT
// derived classes.
void StartUrlRequest(int tab, int request_id,
const IPC::AutomationURLRequest& request_info) {
- StartRequest(request_id, ThreadSafeAutomationUrlRequest(request_info));
+ StartRequest(request_id, request_info);
}
void ReadUrlRequest(int tab, int request_id, int bytes_to_read) {
@@ -151,7 +96,7 @@ class DECLSPEC_NOVTABLE PluginUrlRequestManager { // NOLINT
private:
virtual void StartRequest(int request_id,
- const ThreadSafeAutomationUrlRequest& request_info) = 0;
+ const IPC::AutomationURLRequest& request_info) = 0;
virtual void ReadRequest(int request_id, int bytes_to_read) = 0;
virtual void EndRequest(int request_id) = 0;
virtual void DownloadRequestInHost(int request_id) = 0;
diff --git a/chrome_frame/test/automation_client_mock.h b/chrome_frame/test/automation_client_mock.h
index 54f9d5e..d08d62d3 100644
--- a/chrome_frame/test/automation_client_mock.h
+++ b/chrome_frame/test/automation_client_mock.h
@@ -72,7 +72,7 @@ struct MockCFDelegate : public ChromeFrameDelegateImpl {
}
void ReplyData(int request_id, const std::string* data) {
- request_delegate_->OnReadComplete(request_id, data->c_str(), data->size());
+ request_delegate_->OnReadComplete(request_id, *data);
}
void Reply(const URLRequestStatus& status, int request_id) {
diff --git a/chrome_frame/test/url_request_test.cc b/chrome_frame/test/url_request_test.cc
index 971f239c..efdebc2 100644
--- a/chrome_frame/test/url_request_test.cc
+++ b/chrome_frame/test/url_request_test.cc
@@ -21,8 +21,7 @@ class MockUrlDelegate : public PluginUrlRequestDelegate {
MOCK_METHOD7(OnResponseStarted, void(int request_id, const char* mime_type,
const char* headers, int size, base::Time last_modified,
const std::string& redirect_url, int redirect_status));
- MOCK_METHOD3(OnReadComplete, void(int request_id, const void* buffer,
- int len));
+ MOCK_METHOD2(OnReadComplete, void(int request_id, const std::string& data));
MOCK_METHOD2(OnResponseEnd, void(int request_id,
const URLRequestStatus& status));
@@ -35,11 +34,11 @@ class MockUrlDelegate : public PluginUrlRequestDelegate {
void PostponeReadRequest(chrome_frame_test::TimedMsgLoop* loop,
UrlmonUrlRequest* request, int bytes_to_read) {
loop->PostDelayedTask(FROM_HERE, NewRunnableMethod(this,
- &MockUrlDelegate::Read, request, bytes_to_read), 0);
+ &MockUrlDelegate::RequestRead, request, bytes_to_read), 0);
}
private:
- void Read(UrlmonUrlRequest* request, int bytes_to_read) {
+ void RequestRead(UrlmonUrlRequest* request, int bytes_to_read) {
request->Read(bytes_to_read);
}
};
@@ -70,7 +69,8 @@ TEST(UrlmonUrlRequestTest, Simple1) {
&request, &UrlmonUrlRequest::Read, 512))));
- EXPECT_CALL(mock, OnReadComplete(1, testing::_, testing::Gt(0)))
+ EXPECT_CALL(mock, OnReadComplete(1, testing::Property(&std::string::size,
+ testing::Gt(0u))))
.Times(testing::AtLeast(1))
.WillRepeatedly(testing::InvokeWithoutArgs(CreateFunctor(&mock,
&MockUrlDelegate::PostponeReadRequest, &loop, &request, 64)));
@@ -113,7 +113,7 @@ TEST(UrlmonUrlRequestTest, Head) {
// For HEAD requests we don't expect content reads.
- EXPECT_CALL(mock, OnReadComplete(1, testing::_, testing::_)).Times(0);
+ EXPECT_CALL(mock, OnReadComplete(1, testing::_)).Times(0);
EXPECT_CALL(mock, OnResponseEnd(1, testing::_))
.Times(1)
@@ -193,6 +193,17 @@ TEST(UrlmonUrlRequestTest, ZeroLengthResponse) {
server.TearDown();
}
+ACTION_P4(ManagerRead, loop, mgr, request_id, bytes_to_read) {
+ loop->PostDelayedTask(FROM_HERE, NewRunnableMethod(mgr,
+ &UrlmonUrlRequestManager::ReadUrlRequest, 0, request_id,
+ bytes_to_read), 0);
+}
+ACTION_P3(ManagerEndRequest, loop, mgr, request_id) {
+ loop->PostDelayedTask(FROM_HERE, NewRunnableMethod(mgr,
+ &UrlmonUrlRequestManager::EndUrlRequest, 0, request_id,
+ URLRequestStatus()), 0);
+}
+
// Simplest test - retrieve file from local web server.
TEST(UrlmonUrlRequestManagerTest, Simple1) {
MockUrlDelegate mock;
@@ -207,13 +218,12 @@ TEST(UrlmonUrlRequestManagerTest, Simple1) {
EXPECT_CALL(mock, OnResponseStarted(1, testing::_, testing::_, testing::_,
testing::_, testing::_, testing::_))
.Times(1)
- .WillOnce(testing::InvokeWithoutArgs(CreateFunctor(mgr.get(),
- &PluginUrlRequestManager::ReadUrlRequest, 0, 1, 512)));
+ .WillOnce(ManagerRead(&loop, mgr.get(), 1, 512));
- EXPECT_CALL(mock, OnReadComplete(1, testing::_, testing::Gt(0)))
+ EXPECT_CALL(mock, OnReadComplete(1, testing::Property(&std::string::size,
+ testing::Gt(0u))))
.Times(testing::AtLeast(1))
- .WillRepeatedly(testing::InvokeWithoutArgs(CreateFunctor(mgr.get(),
- &PluginUrlRequestManager::ReadUrlRequest, 0, 1, 2)));
+ .WillRepeatedly(ManagerRead(&loop, mgr.get(), 1, 2));
EXPECT_CALL(mock, OnResponseEnd(1, testing::_))
.Times(1)
@@ -239,17 +249,14 @@ TEST(UrlmonUrlRequestManagerTest, Abort1) {
testing::_, testing::_, testing::_))
.Times(1)
.WillOnce(testing::DoAll(
- testing::InvokeWithoutArgs(CreateFunctor(mgr.get(),
- &PluginUrlRequestManager::EndUrlRequest, 0, 1, URLRequestStatus())),
- testing::InvokeWithoutArgs(CreateFunctor(mgr.get(),
- &PluginUrlRequestManager::ReadUrlRequest, 0, 1, 2))));
+ ManagerEndRequest(&loop, mgr.get(), 1),
+ QUIT_LOOP_SOON(loop, 3)));
- EXPECT_CALL(mock, OnReadComplete(1, testing::_, testing::Gt(0)))
+ EXPECT_CALL(mock, OnReadComplete(1, testing::_))
.Times(0);
EXPECT_CALL(mock, OnResponseEnd(1, testing::_))
- .Times(1)
- .WillOnce(QUIT_LOOP_SOON(loop, 2));
+ .Times(0);
mgr->StartUrlRequest(0, 1, r1);
loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds);
diff --git a/chrome_frame/urlmon_url_request.cc b/chrome_frame/urlmon_url_request.cc
index b0641a5..783fcf0 100644
--- a/chrome_frame/urlmon_url_request.cc
+++ b/chrome_frame/urlmon_url_request.cc
@@ -20,25 +20,10 @@
#include "net/http/http_util.h"
#include "net/http/http_response_headers.h"
-static const LARGE_INTEGER kZero = {0};
-static const ULARGE_INTEGER kUnsignedZero = {0};
-
-STDMETHODIMP UrlmonUrlRequest::SendStream::Write(const void * buffer,
- ULONG size,
- ULONG* size_written) {
- DCHECK(request_);
- int size_to_write = static_cast<int>(
- std::min(static_cast<ULONG>(MAXINT), size));
- request_->delegate_->OnReadComplete(request_->id(), buffer,
- size_to_write);
- if (size_written)
- *size_written = size_to_write;
- return S_OK;
-}
-
UrlmonUrlRequest::UrlmonUrlRequest()
: pending_read_size_(0),
headers_received_(false),
+ calling_delegate_(0),
thread_(NULL),
parent_window_(NULL),
privileged_mode_(false) {
@@ -59,7 +44,7 @@ bool UrlmonUrlRequest::Start() {
HRESULT hr = E_UNEXPECTED;
if (request_data_) {
DCHECK(bind_context_ == NULL);
- hr = CreateAsyncBindCtx(0, this, NULL, bind_context_.Receive());
+ hr = CreateAsyncBindCtxEx(NULL, 0, this, NULL, bind_context_.Receive(), 0);
DCHECK(SUCCEEDED(hr));
CComObject<SimpleBindingImpl>* binding = NULL;
CComObject<SimpleBindingImpl>::CreateInstance(&binding);
@@ -83,6 +68,7 @@ void UrlmonUrlRequest::Stop() {
DCHECK_EQ(thread_, PlatformThread::CurrentId());
DCHECK((status_.get_state() != Status::DONE) == (binding_ != NULL));
Status::State state = status_.get_state();
+ delegate_ = NULL;
switch (state) {
case Status::WORKING:
status_.Cancel();
@@ -104,7 +90,9 @@ void UrlmonUrlRequest::Stop() {
bool UrlmonUrlRequest::Read(int bytes_to_read) {
DCHECK_EQ(thread_, PlatformThread::CurrentId());
- // Re-entrancy check. Thou shall not call Read() while processOnReadComplete!!
+ DCHECK_GE(bytes_to_read, 0);
+ DCHECK_EQ(0, calling_delegate_);
+ // Re-entrancy check. Thou shall not call Read() while process OnReadComplete!
DCHECK_EQ(0, pending_read_size_);
if (pending_read_size_ != 0)
return false;
@@ -115,12 +103,8 @@ bool UrlmonUrlRequest::Read(int bytes_to_read) {
}
// Send cached data if available.
- CComObjectStackEx<SendStream> send_stream;
- send_stream.Initialize(this);
-
- size_t bytes_copied = 0;
- if (delegate_ && cached_data_.is_valid() &&
- cached_data_.Read(&send_stream, bytes_to_read, &bytes_copied)) {
+ if (delegate_ && cached_data_.is_valid()) {
+ size_t bytes_copied = SendDataToDelegate(bytes_to_read);
DLOG(INFO) << StringPrintf("URL: %s Obj: %X - bytes read from cache: %d",
url().c_str(), this, bytes_copied);
return true;
@@ -139,17 +123,35 @@ bool UrlmonUrlRequest::Read(int bytes_to_read) {
return true;
}
-HRESULT UrlmonUrlRequest::SetRequestData(RequestData* data) {
- request_data_ = data;
+HRESULT UrlmonUrlRequest::UseBindCtx(IMoniker* moniker, LPBC bc) {
+ DCHECK(bind_context_ == NULL);
+ DCHECK(moniker_ == NULL);
+ bind_context_ = bc;
+ moniker_ = moniker;
return S_OK;
}
-void UrlmonUrlRequest::StealMoniker(IMoniker** moniker) {
+void UrlmonUrlRequest::StealMoniker(IMoniker** moniker, IBindCtx** bctx) {
// Could be called in any thread. There should be no race
// since moniker_ is not released while we are in manager's request map.
DLOG(INFO) << __FUNCTION__ << " id: " << id();
DLOG_IF(WARNING, moniker == NULL) << __FUNCTION__ << " no moniker";
*moniker = moniker_.Detach();
+ *bctx = bind_context_.Detach();
+}
+
+size_t UrlmonUrlRequest::SendDataToDelegate(size_t bytes_to_read) {
+ // We can optimize a bit by setting this string as a class member
+ // and avoid frequent memory reallocations.
+ std::string data;
+ size_t bytes_copied;
+
+ size_t bytes = std::min(size_t(bytes_to_read), cached_data_.size());
+ cached_data_.Read(WriteInto(&data, 1 + bytes), bytes, &bytes_copied);
+ ++calling_delegate_;
+ delegate_->OnReadComplete(id(), data);
+ --calling_delegate_;
+ return bytes_copied;
}
STDMETHODIMP UrlmonUrlRequest::OnStartBinding(DWORD reserved,
@@ -239,6 +241,10 @@ STDMETHODIMP UrlmonUrlRequest::OnStopBinding(HRESULT result, LPCWSTR error) {
// Mark we a are done.
status_.Done();
+ // We always return INET_E_TERMINATED_BIND from OnDataAvailable
+ if (result == INET_E_TERMINATED_BIND)
+ result = S_OK;
+
if (state == Status::WORKING) {
status_.set_result(result);
@@ -330,8 +336,7 @@ STDMETHODIMP UrlmonUrlRequest::GetBindInfo(DWORD* bind_flags,
if (upload_data) {
// Bypass caching proxies on POSTs and PUTs and avoid writing responses to
// these requests to the browser's cache
- *bind_flags |= BINDF_GETNEWESTVERSION | BINDF_NOWRITECACHE |
- BINDF_PRAGMA_NO_CACHE;
+ *bind_flags |= BINDF_GETNEWESTVERSION | BINDF_PRAGMA_NO_CACHE;
// Initialize the STGMEDIUM.
memset(&bind_info->stgmedData, 0, sizeof(STGMEDIUM));
@@ -378,17 +383,15 @@ STDMETHODIMP UrlmonUrlRequest::OnDataAvailable(DWORD flags, DWORD size,
// time or it won't be available later. Since the size of the data could
// be more than pending read size, it's not straightforward (or might even
// be impossible) to implement a true data pull model.
- size_t bytes_available = 0;
- cached_data_.Append(read_stream, &bytes_available);
+ size_t cached = cached_data_.size();
+ cached_data_.Append(read_stream);
DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
- " - Bytes read into cache: " << bytes_available;
+ " - Bytes read into cache: " << cached_data_.size() - cached;
if (pending_read_size_ && cached_data_.is_valid()) {
- CComObjectStackEx<SendStream> send_stream;
- send_stream.Initialize(this);
- cached_data_.Read(&send_stream, pending_read_size_, &pending_read_size_);
+ size_t bytes_copied = SendDataToDelegate(pending_read_size_);
DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
- " - size read: " << pending_read_size_;
+ " - size read: " << bytes_copied;
pending_read_size_ = 0;
} else {
DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
@@ -398,6 +401,10 @@ STDMETHODIMP UrlmonUrlRequest::OnDataAvailable(DWORD flags, DWORD size,
if (BSCF_LASTDATANOTIFICATION & flags) {
DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
" - end of data.";
+
+ // Always return INET_E_TERMINATED_BIND to allow bind context reuse
+ // if DownloadToHost is suddenly requested.
+ return INET_E_TERMINATED_BIND;
}
return S_OK;
@@ -629,20 +636,27 @@ HRESULT UrlmonUrlRequest::StartAsyncDownload() {
DLOG(INFO) << __FUNCTION__
<< StringPrintf(" this=0x%08X, tid=%i", this, ::GetCurrentThreadId());
HRESULT hr = E_FAIL;
- if (moniker_.get() == NULL) {
- DLOG(INFO) << "Creating a new moniker for " << url();
+ DCHECK((moniker_ && bind_context_) || (!moniker_ && !bind_context_));
+
+
+ if (!moniker_.get()) {
std::wstring wide_url = UTF8ToWide(url());
hr = CreateURLMonikerEx(NULL, wide_url.c_str(), moniker_.Receive(),
URL_MK_UNIFORM);
if (FAILED(hr)) {
NOTREACHED() << "CreateURLMonikerEx failed. Error: " << hr;
- } else {
- hr = CreateAsyncBindCtx(0, this, NULL, bind_context_.Receive());
- DCHECK(SUCCEEDED(hr)) << "CreateAsyncBindCtx failed. Error: " << hr;
+ return hr;
}
+ }
+
+ if (bind_context_.get() == NULL) {
+ hr = ::CreateAsyncBindCtxEx(NULL, 0, this, NULL,
+ bind_context_.Receive(), 0);
+ DCHECK(SUCCEEDED(hr)) << "CreateAsyncBindCtxEx failed. Error: " << hr;
} else {
- DCHECK(bind_context_.get() != NULL);
- hr = S_OK;
+ // Use existing bind context.
+ hr = ::RegisterBindStatusCallback(bind_context_, this, NULL, 0);
+ DCHECK(SUCCEEDED(hr)) << "RegisterBindStatusCallback failed. Error: " << hr;
}
if (SUCCEEDED(hr)) {
@@ -682,6 +696,7 @@ void UrlmonUrlRequest::NotifyDelegateAndDie() {
PluginUrlRequestDelegate* delegate = delegate_;
delegate_ = NULL;
ReleaseBindings();
+ bind_context_.Release();
if (delegate) {
URLRequestStatus result = status_.get_result();
delegate->OnResponseEnd(id(), result);
@@ -733,9 +748,11 @@ std::string UrlmonUrlRequest::GetHttpHeaders() const {
void UrlmonUrlRequest::ReleaseBindings() {
binding_.Release();
+ // Do not release bind_context here!
+ // We may get DownloadToHost request and therefore we want the bind_context
+ // to be available.
if (bind_context_) {
::RevokeBindStatusCallback(bind_context_, this);
- bind_context_.Release();
}
}
@@ -743,57 +760,123 @@ void UrlmonUrlRequest::ReleaseBindings() {
// UrlmonUrlRequest::Cache implementation.
//
-size_t UrlmonUrlRequest::Cache::Size() const {
- return cache_.size();
+UrlmonUrlRequest::Cache::~Cache() {
+ while (cache_.size()) {
+ uint8* t = cache_.front();
+ cache_.pop_front();
+ delete [] t;
+ }
+
+ while (pool_.size()) {
+ uint8* t = pool_.front();
+ pool_.pop_front();
+ delete [] t;
+ }
}
-bool UrlmonUrlRequest::Cache::Read(IStream* dest, size_t size,
+void UrlmonUrlRequest::Cache::GetReadBuffer(void** src, size_t* bytes_avail) {
+ DCHECK_LT(read_offset_, BUF_SIZE);
+ *src = NULL;
+ *bytes_avail = 0;
+ if (cache_.size()) {
+ if (cache_.size() == 1)
+ *bytes_avail = write_offset_ - read_offset_;
+ else
+ *bytes_avail = BUF_SIZE - read_offset_;
+
+ // Return non-NULL pointer only if there is some data
+ if (*bytes_avail)
+ *src = cache_.front() + read_offset_;
+ }
+}
+
+void UrlmonUrlRequest::Cache::BytesRead(size_t bytes) {
+ DCHECK_LT(read_offset_, BUF_SIZE);
+ DCHECK_LE(read_offset_ + bytes, BUF_SIZE);
+ DCHECK_LE(bytes, size_);
+
+ size_ -= bytes;
+ read_offset_ += bytes;
+ if (read_offset_ == BUF_SIZE) {
+ uint8* p = cache_.front();
+ cache_.pop_front();
+ // check if pool_ became too large
+ pool_.push_front(p);
+ read_offset_ = 0;
+ }
+}
+
+bool UrlmonUrlRequest::Cache::Read(void* dest, size_t bytes,
size_t* bytes_copied) {
+ void* src;
+ size_t src_size;
+
DLOG(INFO) << __FUNCTION__;
- if (!dest || !size || !is_valid()) {
- NOTREACHED();
- return false;
- }
+ *bytes_copied = 0;
+ while (bytes) {
+ GetReadBuffer(&src, &src_size);
+ if (src_size == 0)
+ break;
- // Copy the data to the destination stream and remove it from our cache.
- size_t size_written = 0;
- size_t bytes_to_write = (size <= Size() ? size : Size());
+ size_t bytes_to_copy = std::min(src_size, bytes);
+ memcpy(dest, src, bytes_to_copy);
- if (bytes_to_write) {
- dest->Write(&cache_[0], bytes_to_write,
- reinterpret_cast<unsigned long*>(&size_written)); // NOLINT
+ BytesRead(bytes_to_copy);
+ bytes -= bytes_to_copy;
+ *bytes_copied += bytes_to_copy;
}
- DCHECK(size_written == bytes_to_write);
- cache_.erase(cache_.begin(), cache_.begin() + size_written);
+ return true;
+}
+
+
+void UrlmonUrlRequest::Cache::GetWriteBuffer(void** dest, size_t* bytes_avail) {
+ if (cache_.size() == 0 || write_offset_ == BUF_SIZE) {
- if (bytes_copied)
- *bytes_copied = size_written;
+ if (pool_.size()) {
+ cache_.push_back(pool_.front());
+ pool_.pop_front();
+ } else {
+ cache_.push_back(new uint8[BUF_SIZE]);
+ }
+
+ write_offset_ = 0;
+ }
+
+ *dest = cache_.back() + write_offset_;
+ *bytes_avail = BUF_SIZE - write_offset_;
+}
- return (size_written != 0);
+void UrlmonUrlRequest::Cache::BytesWritten(size_t bytes) {
+ DCHECK_LE(write_offset_ + bytes, BUF_SIZE);
+ write_offset_ += bytes;
+ size_ += bytes;
}
-bool UrlmonUrlRequest::Cache::Append(IStream* source,
- size_t* bytes_copied) {
+bool UrlmonUrlRequest::Cache::Append(IStream* source) {
if (!source) {
NOTREACHED();
return false;
}
- char read_buffer[32 * 1024];
HRESULT hr = S_OK;
while (SUCCEEDED(hr)) {
+ void* dest = 0;
+ size_t bytes = 0;
DWORD chunk_read = 0; // NOLINT
- hr = source->Read(read_buffer, sizeof(read_buffer), &chunk_read);
+ GetWriteBuffer(&dest, &bytes);
+ hr = source->Read(dest, bytes, &chunk_read);
+ BytesWritten(chunk_read);
- if (!chunk_read)
+ if (hr == S_OK && chunk_read == 0) {
+ // implied EOF
break;
+ }
- std::copy(read_buffer, read_buffer + chunk_read,
- back_inserter(cache_));
-
- if (bytes_copied)
- *bytes_copied += chunk_read;
+ if (hr == S_FALSE) {
+ // EOF
+ break;
+ }
}
return SUCCEEDED(hr);
@@ -859,39 +942,18 @@ net::Error UrlmonUrlRequest::HresultToNetError(HRESULT hr) {
bool UrlmonUrlRequestManager::IsThreadSafe() {
- return true;
+ return false;
}
-void UrlmonUrlRequestManager::UseRequestDataForUrl(RequestData* data,
- const std::wstring& url) {
- DCHECK(data);
- DCHECK(request_data_for_url_.get() == NULL);
- request_data_for_url_.reset(new RequestDataForUrl(data, url));
+void UrlmonUrlRequestManager::SetInfoForUrl(const std::wstring& url,
+ IMoniker* moniker, LPBC bind_ctx) {
+ url_info_.Set(url, moniker, bind_ctx);
}
void UrlmonUrlRequestManager::StartRequest(int request_id,
- const ThreadSafeAutomationUrlRequest& request_info) {
+ const IPC::AutomationURLRequest& request_info) {
DLOG(INFO) << __FUNCTION__;
- RequestDataForUrl* use_request = NULL;
- if (request_data_for_url_.get()) {
- if (GURL(request_data_for_url_->url()) == GURL(request_info.url)) {
- use_request = request_data_for_url_.release();
- }
- }
-
- bool posted = ExecuteInWorkerThread(FROM_HERE, NewRunnableMethod(this,
- &UrlmonUrlRequestManager::StartRequestWorker,
- request_id, request_info, use_request));
- if (!posted) {
- delete use_request;
- }
-}
-
-void UrlmonUrlRequestManager::StartRequestWorker(int request_id,
- const ThreadSafeAutomationUrlRequest& request_info,
- RequestDataForUrl* use_request) {
- DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
- scoped_ptr<RequestDataForUrl> request_for_url(use_request);
+ DCHECK_EQ(0, calling_delegate_);
if (stopping_)
return;
@@ -907,32 +969,24 @@ void UrlmonUrlRequestManager::StartRequestWorker(int request_id,
request_info.method,
request_info.referrer,
request_info.extra_request_headers,
- request_info.upload_data->get_data(),
+ request_info.upload_data,
enable_frame_busting_);
new_request->set_parent_window(notification_window_);
new_request->set_privileged_mode(privileged_mode_);
// Shall we use previously fetched data?
- if (request_for_url.get()) {
- new_request->SetRequestData(request_for_url->request_data());
+ if (url_info_.IsForUrl(request_info.url)) {
+ new_request->UseBindCtx(url_info_.moniker_, url_info_.bind_ctx_);
+ url_info_.Clear();
}
- DCHECK(LookupRequest(request_id).get() == NULL);
request_map_[request_id] = new_request;
- map_empty_.Reset();
new_request->Start();
}
void UrlmonUrlRequestManager::ReadRequest(int request_id, int bytes_to_read) {
DLOG(INFO) << __FUNCTION__ << " id: " << request_id;
- ExecuteInWorkerThread(FROM_HERE, NewRunnableMethod(this,
- &UrlmonUrlRequestManager::ReadRequestWorker, request_id, bytes_to_read));
-}
-
-void UrlmonUrlRequestManager::ReadRequestWorker(int request_id,
- int bytes_to_read) {
- DLOG(INFO) << __FUNCTION__ << " id: " << request_id;
- DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
+ DCHECK_EQ(0, calling_delegate_);
scoped_refptr<UrlmonUrlRequest> request = LookupRequest(request_id);
// if zero, it may just have had network error.
if (request) {
@@ -940,25 +994,21 @@ void UrlmonUrlRequestManager::ReadRequestWorker(int request_id,
}
}
-void UrlmonUrlRequestManager::EndRequest(int request_id) {
- DLOG(INFO) << __FUNCTION__ << " id: " << request_id;
- ExecuteInWorkerThread(FROM_HERE, NewRunnableMethod(this,
- &UrlmonUrlRequestManager::EndRequestWorker, request_id));
-}
-
void UrlmonUrlRequestManager::DownloadRequestInHost(int request_id) {
DLOG(INFO) << __FUNCTION__ << " " << request_id;
if (IsWindow(notification_window_)) {
scoped_refptr<UrlmonUrlRequest> request(LookupRequest(request_id));
if (request) {
ScopedComPtr<IMoniker> moniker;
- request->StealMoniker(moniker.Receive());
+ ScopedComPtr<IBindCtx> bind_context;
+ request->StealMoniker(moniker.Receive(), bind_context.Receive());
DLOG_IF(ERROR, moniker == NULL) << __FUNCTION__ << " No moniker!";
if (moniker) {
// We use SendMessage and not PostMessage to make sure that if the
// notification window does not handle the message we won't leak
// the moniker.
- ::SendMessage(notification_window_, WM_DOWNLOAD_IN_HOST, 0,
+ ::SendMessage(notification_window_, WM_DOWNLOAD_IN_HOST,
+ reinterpret_cast<WPARAM>(bind_context.get()),
reinterpret_cast<LPARAM>(moniker.get()));
}
}
@@ -1045,67 +1095,29 @@ bool UrlmonUrlRequestManager::SetCookiesForUrl(int tab_handle,
return true;
}
-void UrlmonUrlRequestManager::EndRequestWorker(int request_id) {
+void UrlmonUrlRequestManager::EndRequest(int request_id) {
DLOG(INFO) << __FUNCTION__ << " id: " << request_id;
- DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
+ DCHECK_EQ(0, calling_delegate_);
scoped_refptr<UrlmonUrlRequest> request = LookupRequest(request_id);
if (request) {
+ request_map_.erase(request_id);
request->Stop();
}
}
void UrlmonUrlRequestManager::StopAll() {
DLOG(INFO) << __FUNCTION__;
- do {
- AutoLock lock(worker_thread_access_);
- if (stopping_)
- return;
-
- stopping_ = true;
-
- if (!worker_thread_.IsRunning())
- return;
-
- // ExecuteInWorkerThread will check for stopping_. Hence post directly
- // to the worker thread.
- worker_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
- &UrlmonUrlRequestManager::StopAllWorker));
- } while (0);
-
- // Note we may not call worker_thread_.Stop() here. The MessageLoop's quit
- // task will be serialized after request::Stop tasks, but requests may
- // not quit immediately. CoUninitialize has a modal message loop, but it
- // does not help in this case.
- // Normally we call binding->Abort() and expect OnStopBinding() callback
- // where we inform UrlmonUrlRequestManager that request is dead.
- // The problem is that while waiting for OnStopBinding(), Quit Task may be
- // picked up and executed, thus exiting the thread.
- map_empty_.Wait();
-
- worker_thread_access_.Acquire();
- worker_thread_.Stop();
- worker_thread_access_.Release();
-}
-
-void UrlmonUrlRequestManager::StopAllWorker() {
- DLOG(INFO) << __FUNCTION__;
- DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
- DCHECK_EQ(true, stopping_);
+ if (stopping_)
+ return;
- std::vector<scoped_refptr<UrlmonUrlRequest> > request_list;
- // We copy the pending requests into a temporary vector as the Stop
- // function in the request could also try to delete the request from
- // the request map and the iterator could end up being invalid.
+ stopping_ = true;
for (RequestMap::iterator it = request_map_.begin();
it != request_map_.end(); ++it) {
DCHECK(it->second != NULL);
- request_list.push_back(it->second);
+ it->second->Stop();
}
- for (std::vector<scoped_refptr<UrlmonUrlRequest> >::size_type index = 0;
- index < request_list.size(); ++index) {
- request_list[index]->Stop();
- }
+ request_map_.empty();
}
void UrlmonUrlRequestManager::OnResponseStarted(int request_id,
@@ -1113,33 +1125,31 @@ void UrlmonUrlRequestManager::OnResponseStarted(int request_id,
base::Time last_modified, const std::string& redirect_url,
int redirect_status) {
DLOG(INFO) << __FUNCTION__;
- DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
DCHECK(LookupRequest(request_id).get() != NULL);
+ ++calling_delegate_;
delegate_->OnResponseStarted(request_id, mime_type, headers, size,
last_modified, redirect_url, redirect_status);
+ --calling_delegate_;
}
-void UrlmonUrlRequestManager::OnReadComplete(int request_id, const void* buffer,
- int len) {
+void UrlmonUrlRequestManager::OnReadComplete(int request_id,
+ const std::string& data) {
DLOG(INFO) << __FUNCTION__;
- DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
DCHECK(LookupRequest(request_id).get() != NULL);
- delegate_->OnReadComplete(request_id, buffer, len);
+ ++calling_delegate_;
+ delegate_->OnReadComplete(request_id, data);
+ --calling_delegate_;
}
void UrlmonUrlRequestManager::OnResponseEnd(int request_id,
const URLRequestStatus& status) {
DLOG(INFO) << __FUNCTION__;
- DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
+ DCHECK(status.status() != URLRequestStatus::CANCELED);
RequestMap::size_type n = request_map_.erase(request_id);
DCHECK_EQ(1, n);
-
- if (request_map_.size() == 0)
- map_empty_.Signal();
-
- // Inform delegate unless the request has been explicitly cancelled.
- if (status.status() != URLRequestStatus::CANCELED)
- delegate_->OnResponseEnd(request_id, status);
+ ++calling_delegate_;
+ delegate_->OnResponseEnd(request_id, status);
+ --calling_delegate_;
}
scoped_refptr<UrlmonUrlRequest> UrlmonUrlRequestManager::LookupRequest(
@@ -1151,8 +1161,7 @@ scoped_refptr<UrlmonUrlRequest> UrlmonUrlRequestManager::LookupRequest(
}
UrlmonUrlRequestManager::UrlmonUrlRequestManager()
- : stopping_(false), worker_thread_("UrlMon fetch thread"),
- map_empty_(true, true), notification_window_(NULL),
+ : stopping_(false), calling_delegate_(0), notification_window_(NULL),
privileged_mode_(false) {
}
@@ -1160,46 +1169,27 @@ UrlmonUrlRequestManager::~UrlmonUrlRequestManager() {
StopAll();
}
-bool UrlmonUrlRequestManager::ExecuteInWorkerThread(
- const tracked_objects::Location& from_here, Task* task) {
- AutoLock lock(worker_thread_access_);
- if (stopping_) {
- delete task;
- return false;
- }
-
- if (!worker_thread_.IsRunning())
- worker_thread_.Start();
-
- worker_thread_.message_loop()->PostTask(from_here, task);
- return true;
-}
-
void UrlmonUrlRequestManager::AddPrivacyDataForUrl(
const std::string& url, const std::string& policy_ref,
int32 flags) {
bool fire_privacy_event = false;
- {
- AutoLock lock(privacy_info_lock_);
+ if (privacy_info_.privacy_records.size() == 0)
+ flags |= PRIVACY_URLISTOPLEVEL;
- if (privacy_info_.privacy_records.size() == 0)
- flags |= PRIVACY_URLISTOPLEVEL;
-
- if (!privacy_info_.privacy_impacted) {
- if (flags & (COOKIEACTION_ACCEPT | COOKIEACTION_REJECT |
- COOKIEACTION_DOWNGRADE)) {
- privacy_info_.privacy_impacted = true;
- fire_privacy_event = true;
- }
+ if (!privacy_info_.privacy_impacted) {
+ if (flags & (COOKIEACTION_ACCEPT | COOKIEACTION_REJECT |
+ COOKIEACTION_DOWNGRADE)) {
+ privacy_info_.privacy_impacted = true;
+ fire_privacy_event = true;
}
+ }
- PrivacyInfo::PrivacyEntry& privacy_entry =
- privacy_info_.privacy_records[UTF8ToWide(url)];
+ PrivacyInfo::PrivacyEntry& privacy_entry =
+ privacy_info_.privacy_records[UTF8ToWide(url)];
- privacy_entry.flags |= flags;
- privacy_entry.policy_ref = UTF8ToWide(policy_ref);
- }
+ privacy_entry.flags |= flags;
+ privacy_entry.policy_ref = UTF8ToWide(policy_ref);
if (fire_privacy_event && IsWindow(notification_window_)) {
PostMessage(notification_window_, WM_FIRE_PRIVACY_CHANGE_NOTIFICATION, 1,
diff --git a/chrome_frame/urlmon_url_request.h b/chrome_frame/urlmon_url_request.h
index 189f64b..7e45123 100644
--- a/chrome_frame/urlmon_url_request.h
+++ b/chrome_frame/urlmon_url_request.h
@@ -21,27 +21,6 @@
class UrlmonUrlRequest;
-class RequestDataForUrl {
- public:
- RequestDataForUrl(RequestData* data, const std::wstring& url)
- : request_data_(data), url_(url) {
- }
- ~RequestDataForUrl() {
- }
-
- const std::wstring& url() const {
- return url_;
- }
-
- RequestData* request_data() const {
- return request_data_;
- }
-
- protected:
- scoped_refptr<RequestData> request_data_;
- std::wstring url_;
-};
-
class UrlmonUrlRequestManager
: public PluginUrlRequestManager,
public PluginUrlRequestDelegate {
@@ -66,13 +45,13 @@ class UrlmonUrlRequestManager
UrlmonUrlRequestManager();
~UrlmonUrlRequestManager();
- // Use cached data when Chrome request this url.
+ // Use specific bind context when Chrome request this url.
// Used from ChromeActiveDocument's implementation of IPersistMoniker::Load().
- void UseRequestDataForUrl(RequestData* data, const std::wstring& url);
+ void SetInfoForUrl(const std::wstring& url,
+ IMoniker* moniker, LPBC bind_context);
// Returns a copy of the url privacy information for this instance.
PrivacyInfo privacy_info() {
- AutoLock lock(privacy_info_lock_);
return privacy_info_;
}
@@ -101,7 +80,7 @@ class UrlmonUrlRequestManager
// PluginUrlRequestManager implementation.
virtual bool IsThreadSafe();
virtual void StartRequest(int request_id,
- const ThreadSafeAutomationUrlRequest& request_info);
+ const IPC::AutomationURLRequest& request_info);
virtual void ReadRequest(int request_id, int bytes_to_read);
virtual void EndRequest(int request_id);
virtual void DownloadRequestInHost(int request_id);
@@ -118,33 +97,41 @@ class UrlmonUrlRequestManager
base::Time last_modified,
const std::string& redirect_url,
int redirect_status);
- virtual void OnReadComplete(int request_id, const void* buffer, int len);
+ virtual void OnReadComplete(int request_id, const std::string& data);
virtual void OnResponseEnd(int request_id, const URLRequestStatus& status);
- bool ExecuteInWorkerThread(const tracked_objects::Location& from_here,
- Task* task);
- // Methods executed in worker thread.
- void StartRequestWorker(int request_id,
- const ThreadSafeAutomationUrlRequest& request_info,
- RequestDataForUrl* use_request);
- void ReadRequestWorker(int request_id, int bytes_to_read);
- void EndRequestWorker(int request_id);
- void StopAllWorker();
-
// Map for (request_id <-> UrlmonUrlRequest)
typedef std::map<int, scoped_refptr<UrlmonUrlRequest> > RequestMap;
RequestMap request_map_;
scoped_refptr<UrlmonUrlRequest> LookupRequest(int request_id);
- scoped_ptr<RequestDataForUrl> request_data_for_url_;
- STAThread worker_thread_;
- base::WaitableEvent map_empty_;
+ struct UrlInfo {
+ void Clear() {
+ url_ = GURL::EmptyGURL();
+ bind_ctx_.Release();
+ moniker_.Release();
+ }
+
+ void Set(const std::wstring& url, IMoniker* moniker, LPBC bc) {
+ DCHECK(bind_ctx_.get() == NULL);
+ DCHECK(moniker_.get() == NULL);
+ url_ = GURL(url);
+ moniker_ = moniker;
+ bind_ctx_ = bc;
+ }
+
+ bool IsForUrl(const std::string& url) {
+ return GURL(url) == url_;
+ }
+
+ GURL url_;
+ ScopedComPtr<IBindCtx> bind_ctx_;
+ ScopedComPtr<IMoniker> moniker_;
+ } url_info_;
+
bool stopping_;
- Lock worker_thread_access_;
+ int calling_delegate_; // re-entrancy protection (debug only check)
- // This lock is used to synchronize access to the PrivacyInfo data structure
- // as it can be accessed from the ui thread and the worker thread.
- Lock privacy_info_lock_;
PrivacyInfo privacy_info_;
// The window to be used to fire notifications on.
HWND notification_window_;
diff --git a/chrome_frame/urlmon_url_request_private.h b/chrome_frame/urlmon_url_request_private.h
index 596c099c..5ae3da3 100644
--- a/chrome_frame/urlmon_url_request_private.h
+++ b/chrome_frame/urlmon_url_request_private.h
@@ -8,7 +8,7 @@
#include <atlbase.h>
#include <atlcom.h>
#include <string>
-#include <vector>
+#include <deque>
#include "net/base/net_errors.h"
#include "net/http/http_response_headers.h"
@@ -30,10 +30,10 @@ class UrlmonUrlRequest
virtual bool Read(int bytes_to_read);
// Special function needed by ActiveDocument::Load()
- HRESULT SetRequestData(RequestData* data);
+ HRESULT UseBindCtx(IMoniker* moniker, LPBC bc);
// Used from "DownloadRequestInHost".
- void StealMoniker(IMoniker** moniker);
+ void StealMoniker(IMoniker** moniker, IBindCtx** bctx);
// Parent Window for UrlMon error dialogs
void set_parent_window(HWND parent_window) {
@@ -98,104 +98,42 @@ class UrlmonUrlRequest
protected:
void ReleaseBindings();
- // A fake stream class to make it easier to copy received data using
- // IStream::CopyTo instead of allocating temporary buffers and keeping
- // track of data copied so far.
- class SendStream : public CComObjectRoot, public IStream {
- public:
- SendStream() {
- }
-
- BEGIN_COM_MAP(SendStream)
- COM_INTERFACE_ENTRY(IStream)
- COM_INTERFACE_ENTRY(ISequentialStream)
- END_COM_MAP()
-
- void Initialize(UrlmonUrlRequest* request) {
- request_ = request;
- }
-
- STDMETHOD(Write)(const void * buffer, ULONG size, ULONG* size_written);
- STDMETHOD(Read)(void* pv, ULONG cb, ULONG* read) {
- DCHECK(false) << __FUNCTION__;
- return E_NOTIMPL;
- }
-
- STDMETHOD(Seek)(LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER* new_pos) {
- DCHECK(false) << __FUNCTION__;
- return E_NOTIMPL;
- }
-
- STDMETHOD(SetSize)(ULARGE_INTEGER new_size) {
- DCHECK(false) << __FUNCTION__;
- return E_NOTIMPL;
- }
-
- STDMETHOD(CopyTo)(IStream* stream, ULARGE_INTEGER cb, ULARGE_INTEGER* read,
- ULARGE_INTEGER* written) {
- DCHECK(false) << __FUNCTION__;
- return E_NOTIMPL;
- }
-
- STDMETHOD(Commit)(DWORD flags) {
- DCHECK(false) << __FUNCTION__;
- return E_NOTIMPL;
- }
-
- STDMETHOD(Revert)() {
- DCHECK(false) << __FUNCTION__;
- return E_NOTIMPL;
- }
-
- STDMETHOD(LockRegion)(ULARGE_INTEGER offset, ULARGE_INTEGER cb,
- DWORD type) {
- DCHECK(false) << __FUNCTION__;
- return E_NOTIMPL;
- }
-
- STDMETHOD(UnlockRegion)(ULARGE_INTEGER offset, ULARGE_INTEGER cb,
- DWORD type) {
- DCHECK(false) << __FUNCTION__;
- return E_NOTIMPL;
- }
-
- STDMETHOD(Stat)(STATSTG *pstatstg, DWORD grfStatFlag) {
- return E_NOTIMPL;
- }
-
- STDMETHOD(Clone)(IStream** stream) {
- DCHECK(false) << __FUNCTION__;
- return E_NOTIMPL;
- }
-
- protected:
- scoped_refptr<UrlmonUrlRequest> request_;
- DISALLOW_COPY_AND_ASSIGN(SendStream);
- };
-
// Manage data caching. Note: this class supports cache
// size less than 2GB
class Cache {
public:
- Cache() {
+ Cache() : size_(0), read_offset_(0), write_offset_(0) {
}
- // Adds data to the end of the cache.
- bool Append(IStream* source, size_t* bytes_copied);
+ ~Cache();
- // Reads from the cache.
- bool Read(IStream* dest, size_t size, size_t* bytes_copied);
+ // Adds data to the end of the cache.
+ bool Append(IStream* source);
+ // Copies up to |bytes| bytes from the cache to |dest| buffer.
+ bool Read(void* dest, size_t bytes, size_t* bytes_copied);
// Returns the size of the cache.
- size_t Size() const;
+ size_t size() const {
+ return size_;
+ }
// Returns true if the cache has valid data.
bool is_valid() const {
- return Size() != 0;
+ return size() != 0;
}
- protected:
- std::vector<byte> cache_;
+ private:
+ void GetWriteBuffer(void** dest, size_t* bytes_avail);
+ void BytesWritten(size_t bytes);
+ void GetReadBuffer(void** src, size_t* bytes_avail);
+ void BytesRead(size_t bytes);
+
+ static const size_t BUF_SIZE = 0x8000; // 32k
+ std::deque<uint8*> cache_;
+ size_t size_;
+ size_t read_offset_;
+ size_t write_offset_;
+ std::deque<uint8*> pool_;
};
HRESULT StartAsyncDownload();
@@ -205,6 +143,7 @@ class UrlmonUrlRequest
static net::Error HresultToNetError(HRESULT hr);
private:
+ size_t SendDataToDelegate(size_t bytes);
// This class simplifies tracking the progress of operation. We have 3 main
// states: DONE, WORKING and ABORTING.
// When in [DONE] or [ABORTING] state, there is additional information
@@ -309,6 +248,7 @@ class UrlmonUrlRequest
PlatformThreadId thread_;
HWND parent_window_;
bool headers_received_;
+ int calling_delegate_; // re-entrancy protection.
// Set to true if the ChromeFrame instance is running in privileged mode.
bool privileged_mode_;
DISALLOW_COPY_AND_ASSIGN(UrlmonUrlRequest);