summaryrefslogtreecommitdiffstats
path: root/chrome_frame
diff options
context:
space:
mode:
authortommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-02 01:22:12 +0000
committertommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-02 01:22:12 +0000
commit04f66a08aa84731dc466738b58d3143df44b5394 (patch)
tree75756b61cdfebdb025f1a6555ebe5905156f8151 /chrome_frame
parentd6d7a21f69f77d6789b48eea43ea2fc8cf44cf2f (diff)
downloadchromium_src-04f66a08aa84731dc466738b58d3143df44b5394.zip
chromium_src-04f66a08aa84731dc466738b58d3143df44b5394.tar.gz
chromium_src-04f66a08aa84731dc466738b58d3143df44b5394.tar.bz2
Not using an intermediate cache between urlmon and chrome reads.
Instead we hang on to stream objects from urlmon and read from them when chrome asks for data. TEST=Run all tests verify that sites like wave and vimeo work correctly etc. BUG=none Review URL: http://codereview.chromium.org/1718025 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@46188 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame')
-rw-r--r--chrome_frame/test/url_request_test.cc57
-rw-r--r--chrome_frame/urlmon_url_request.cc369
-rw-r--r--chrome_frame/urlmon_url_request_private.h66
3 files changed, 163 insertions, 329 deletions
diff --git a/chrome_frame/test/url_request_test.cc b/chrome_frame/test/url_request_test.cc
index 35f0f81..106f717b 100644
--- a/chrome_frame/test/url_request_test.cc
+++ b/chrome_frame/test/url_request_test.cc
@@ -31,63 +31,6 @@ static void AppendToStream(IStream* s, void* buffer, ULONG cb) {
ASSERT_HRESULT_SUCCEEDED(s->Seek(current_pos, STREAM_SEEK_SET, NULL));
}
-TEST(UrlmonUrlRequestCache, ReadWrite) {
- UrlmonUrlRequest::Cache cache;
- ScopedComPtr<IStream> stream;
- ASSERT_HRESULT_SUCCEEDED(::CreateStreamOnHGlobal(0, TRUE, stream.Receive()));
- cache.Append(stream);
- ASSERT_EQ(0, cache.size());
- size_t bytes_read;
- const size_t BUF_SIZE = UrlmonUrlRequest::Cache::BUF_SIZE;
- scoped_array<uint8> buffer(new uint8[BUF_SIZE * 2]);
-
- AppendToStream(stream, "hello", 5u);
- ASSERT_TRUE(cache.Append(stream));
- ASSERT_HRESULT_SUCCEEDED(cache.Read(buffer.get(), 2u, &bytes_read));
- ASSERT_EQ(2, bytes_read);
- ASSERT_EQ('h', buffer[0]);
- ASSERT_EQ('e', buffer[1]);
-
- AppendToStream(stream, "world\0", 6u);
- ASSERT_TRUE(cache.Append(stream));
- ASSERT_HRESULT_SUCCEEDED(cache.Read(buffer.get(), 1u, &bytes_read));
- ASSERT_EQ(1, bytes_read);
- ASSERT_EQ('l', buffer[0]);
- ASSERT_HRESULT_SUCCEEDED(cache.Read(buffer.get(), 100u, &bytes_read));
- ASSERT_EQ(8, bytes_read);
- ASSERT_STREQ("loworld", (const char*)buffer.get());
-
- memset(buffer.get(), '1', BUF_SIZE / 2);
- AppendToStream(stream, buffer.get(), BUF_SIZE / 2);
- cache.Append(stream);
- memset(buffer.get(), '2', BUF_SIZE);
- AppendToStream(stream, buffer.get(), BUF_SIZE);
- memset(buffer.get(), '3', BUF_SIZE * 3 / 4);
- AppendToStream(stream, buffer.get(), BUF_SIZE * 3 / 4);
- cache.Append(stream);
-
- cache.Read(buffer.get(), BUF_SIZE / 2, &bytes_read);
- ASSERT_EQ(BUF_SIZE / 2, bytes_read);
- ASSERT_EQ('1', buffer[0]);
- ASSERT_EQ('1', buffer[BUF_SIZE / 4]);
- ASSERT_EQ('1', buffer[BUF_SIZE /2 - 1]);
-
- cache.Read(buffer.get(), BUF_SIZE, &bytes_read);
- ASSERT_EQ(BUF_SIZE, bytes_read);
- ASSERT_EQ('2', buffer[0]);
- ASSERT_EQ('2', buffer[BUF_SIZE /2]);
- ASSERT_EQ('2', buffer[BUF_SIZE - 1]);
-
- cache.Read(buffer.get(), BUF_SIZE * 3 / 4, &bytes_read);
- ASSERT_EQ(BUF_SIZE * 3 / 4, bytes_read);
- ASSERT_EQ('3', buffer[0]);
- ASSERT_EQ('3', buffer[BUF_SIZE / 2]);
- ASSERT_EQ('3', buffer[BUF_SIZE * 3 / 4 - 1]);
- cache.Read(buffer.get(), 11, &bytes_read);
- ASSERT_EQ(0, bytes_read);
-}
-
-
class MockUrlDelegate : public PluginUrlRequestDelegate {
public:
MOCK_METHOD7(OnResponseStarted, void(int request_id, const char* mime_type,
diff --git a/chrome_frame/urlmon_url_request.cc b/chrome_frame/urlmon_url_request.cc
index 961b7da..5bfbbbf 100644
--- a/chrome_frame/urlmon_url_request.cc
+++ b/chrome_frame/urlmon_url_request.cc
@@ -21,6 +21,28 @@
#include "net/http/http_util.h"
#include "net/http/http_response_headers.h"
+namespace {
+
+// Reads data from a stream into a string.
+HRESULT ReadStream(IStream* stream, size_t size, std::string* data) {
+ DCHECK(stream);
+ DCHECK(data);
+
+ DWORD read = 0;
+ HRESULT hr = stream->Read(WriteInto(data, size + 1), size, &read);
+ DCHECK(hr == S_OK || hr == S_FALSE || hr == E_PENDING);
+ if (read) {
+ data->erase(read);
+ DCHECK_EQ(read, data->length());
+ } else {
+ data->clear();
+ }
+
+ return hr;
+}
+
+} // end namespace
+
UrlmonUrlRequest::UrlmonUrlRequest()
: pending_read_size_(0),
headers_received_(false),
@@ -29,14 +51,20 @@ UrlmonUrlRequest::UrlmonUrlRequest()
parent_window_(NULL),
privileged_mode_(false),
pending_(false) {
- DLOG(INFO) << StringPrintf("Created request. Obj: %X", this);
+ DLOG(INFO) << __FUNCTION__ << me();
}
UrlmonUrlRequest::~UrlmonUrlRequest() {
- DLOG(INFO) << StringPrintf("Deleted request. Obj: %X", this);
+ DLOG(INFO) << __FUNCTION__ << me();
+}
+
+std::string UrlmonUrlRequest::me() const {
+ return StringPrintf(" id: %i Obj: %X ", id(), this);
}
bool UrlmonUrlRequest::Start() {
+ DLOG(INFO) << __FUNCTION__ << me() << url();
+ DCHECK(thread_ == 0 || thread_ == PlatformThread::CurrentId());
thread_ = PlatformThread::CurrentId();
status_.Start();
// The UrlmonUrlRequest instance can get destroyed in the context of
@@ -85,6 +113,8 @@ bool UrlmonUrlRequest::Read(int bytes_to_read) {
DCHECK_EQ(thread_, PlatformThread::CurrentId());
DCHECK_GE(bytes_to_read, 0);
DCHECK_EQ(0, calling_delegate_);
+ DLOG(INFO) << __FUNCTION__ << me();
+
// Re-entrancy check. Thou shall not call Read() while process OnReadComplete!
DCHECK_EQ(0, pending_read_size_);
if (pending_read_size_ != 0)
@@ -95,21 +125,18 @@ bool UrlmonUrlRequest::Read(int bytes_to_read) {
return true;
}
- // Send cached data if available.
- 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);
+ // Send data if available.
+ size_t bytes_copied = 0;
+ if ((bytes_copied = SendDataToDelegate(bytes_to_read))) {
+ DLOG(INFO) << __FUNCTION__ << me() << " bytes read: " << bytes_copied;
return true;
}
if (status_.get_state() == Status::WORKING) {
- DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
- "- Read pending for: " << bytes_to_read;
+ DLOG(INFO) << __FUNCTION__ << me() << " pending: " << bytes_to_read;
pending_read_size_ = bytes_to_read;
} else {
- DLOG(INFO) << StringPrintf("URL: %s Obj: %X. Response finished.",
- url().c_str(), this);
+ DLOG(INFO) << __FUNCTION__ << me() << " Response finished.";
NotifyDelegateAndDie();
}
@@ -122,19 +149,21 @@ HRESULT UrlmonUrlRequest::InitPending(const GURL& url, IMoniker* moniker,
bool privileged_mode,
HWND notification_window,
IStream* cache) {
+ DLOG(INFO) << __FUNCTION__ << me() << url.spec();
DCHECK(bind_context_ == NULL);
DCHECK(moniker_ == NULL);
+ DCHECK(cache_ == NULL);
+ DCHECK(thread_ == 0 || thread_ == PlatformThread::CurrentId());
+ thread_ = PlatformThread::CurrentId();
bind_context_ = bind_context;
moniker_ = moniker;
- url_ = url;
enable_frame_busting_ = enable_frame_busting;
privileged_mode_ = privileged_mode;
parent_window_ = notification_window;
+ cache_ = cache;
+ set_url(url.spec());
set_pending(true);
- if (cache)
- cached_data_.Append(cache);
-
// Request has already started and data is fetched. We will get the
// GetBindInfo call as per contract but the return values are
// ignored. So just set "get" as a method to make our GetBindInfo
@@ -145,8 +174,7 @@ HRESULT UrlmonUrlRequest::InitPending(const GURL& url, IMoniker* moniker,
void UrlmonUrlRequest::TerminateBind(TerminateBindCallback* callback) {
DCHECK_EQ(thread_, PlatformThread::CurrentId());
- DLOG(INFO) << __FUNCTION__ << " id: " << id();
-
+ DLOG(INFO) << __FUNCTION__ << me();
if (status_.get_state() == Status::DONE) {
// Binding is stopped. Note result could be an error.
callback->Run(moniker_, bind_context_);
@@ -161,26 +189,52 @@ void UrlmonUrlRequest::TerminateBind(TerminateBindCallback* callback) {
}
size_t UrlmonUrlRequest::SendDataToDelegate(size_t bytes_to_read) {
+ DCHECK_EQ(thread_, PlatformThread::CurrentId());
+ DCHECK(id() != -1);
+ DCHECK_GT(bytes_to_read, 0U);
size_t bytes_copied = 0;
if (delegate_) {
- // We can optimize a bit by setting this string as a class member
- // and avoid frequent memory reallocations.
- std::string data;
-
- size_t bytes = std::min(static_cast<size_t>(bytes_to_read),
- cached_data_.size());
- cached_data_.Read(WriteInto(&data, 1 + bytes), bytes, &bytes_copied);
- DCHECK_EQ(bytes, data.length());
- ++calling_delegate_;
- delegate_->OnReadComplete(id(), data);
- --calling_delegate_;
+ std::string read_data;
+ if (cache_) {
+ HRESULT hr = ReadStream(cache_, bytes_to_read, &read_data);
+ if (hr == S_FALSE || read_data.length() < bytes_to_read) {
+ DLOG(INFO) << __FUNCTION__ << me() << "all cached data read";
+ cache_.Release();
+ }
+ }
+
+ if (read_data.empty() && pending_data_) {
+ size_t pending_data_read_save = pending_read_size_;
+ pending_read_size_ = 0;
+
+ // AddRef the stream while we call Read to avoid a potential issue
+ // where we can get a call to OnDataAvailable while inside Read and
+ // in our OnDataAvailable call, we can release the stream object
+ // while still using it.
+ ScopedComPtr<IStream> pending(pending_data_);
+ HRESULT hr = ReadStream(pending, bytes_to_read, &read_data);
+ if (read_data.empty()) {
+ pending_read_size_ = pending_data_read_save;
+ }
+ }
+
+ bytes_copied = read_data.length();
+
+ if (bytes_copied) {
+ ++calling_delegate_;
+ DCHECK(id() != -1);
+ delegate_->OnReadComplete(id(), read_data);
+ --calling_delegate_;
+ }
+ } else {
+ DLOG(ERROR) << __FUNCTION__ << me() << "no delegate";
}
return bytes_copied;
}
STDMETHODIMP UrlmonUrlRequest::OnStartBinding(DWORD reserved,
- IBinding *binding) {
+ IBinding* binding) {
DCHECK_EQ(thread_, PlatformThread::CurrentId());
binding_ = binding;
if (pending_) {
@@ -224,7 +278,8 @@ STDMETHODIMP UrlmonUrlRequest::OnProgress(ULONG progress, ULONG max_progress,
DCHECK(info);
GURL previously_redirected(info ? info->url() : std::wstring());
if (GURL(status_text) != previously_redirected) {
- DLOG(INFO) << "URL: " << url() << " redirected to " << status_text;
+ DLOG(INFO) << __FUNCTION__ << me() << "redirect from " << url()
+ << " to " << status_text;
// Fetch the redirect status as they aren't all equal (307 in particular
// retains the HTTP request verb).
int http_code = GetHttpResponseStatusFromBinding(binding_);
@@ -265,8 +320,8 @@ STDMETHODIMP UrlmonUrlRequest::OnProgress(ULONG progress, ULONG max_progress,
break;
default:
- DLOG(INFO) << " Obj: " << std::hex << this << " OnProgress(" << url()
- << StringPrintf(L") code: %i status: %ls", status_code, status_text);
+ DLOG(INFO) << __FUNCTION__ << me()
+ << StringPrintf(L"code: %i status: %ls", status_code, status_text);
break;
}
@@ -275,8 +330,8 @@ STDMETHODIMP UrlmonUrlRequest::OnProgress(ULONG progress, ULONG max_progress,
STDMETHODIMP UrlmonUrlRequest::OnStopBinding(HRESULT result, LPCWSTR error) {
DCHECK_EQ(thread_, PlatformThread::CurrentId());
- DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
- " - Request stopped, Result: " << std::hex << result;
+ DLOG(INFO) << __FUNCTION__ << me() <<
+ "- Request stopped, Result: " << std::hex << result;
DCHECK(status_.get_state() == Status::WORKING ||
status_.get_state() == Status::ABORTING);
@@ -311,17 +366,16 @@ STDMETHODIMP UrlmonUrlRequest::OnStopBinding(HRESULT result, LPCWSTR error) {
// The code below seems easy but it is not. :)
// The network policy in Chrome network is that error code/end_of_stream
// should be returned only as a result of read (or start) request.
- // Here is the possible cases:
+ // Here are the possible cases:
// cached_data|pending_read
- // FALSE |FALSE => EndRequest if no headers, otherwise wait for Read
- // FALSE |TRUE => EndRequest.
- // TRUE |FALSE => Wait for Read.
- // TRUE |TRUE => Something went wrong!!
+ // FALSE |FALSE => EndRequest if no headers, otherwise wait for Read.
+ // FALSE |TRUE => EndRequest.
+ // TRUE |FALSE => Wait for Read.
+ // TRUE |TRUE => Something went wrong!!
- // we cannot have pending read and data_avail at the same time.
- DCHECK(!(pending_read_size_ > 0 && cached_data_.is_valid()));
+ DCHECK(!(pending_read_size_ > 0 && pending_data_));
- if (cached_data_.is_valid()) {
+ if (pending_data_) {
ReleaseBindings();
return S_OK;
}
@@ -395,12 +449,11 @@ STDMETHODIMP UrlmonUrlRequest::GetBindInfo(DWORD* bind_flags,
if (get_upload_data(&bind_info->stgmedData.pstm) == S_OK) {
bind_info->stgmedData.tymed = TYMED_ISTREAM;
- DLOG(INFO) << " Obj: " << std::hex << this << " " << method()
+ DLOG(INFO) << __FUNCTION__ << me() << method()
<< " request with " << Int64ToString(post_data_len())
- << " bytes";
+ << " bytes. url=" << url();
} else {
- DLOG(INFO) << " Obj: " << std::hex << this
- << "POST request with no data!";
+ DLOG(INFO) << __FUNCTION__ << me() << "POST request with no data!";
}
}
@@ -410,8 +463,8 @@ STDMETHODIMP UrlmonUrlRequest::GetBindInfo(DWORD* bind_flags,
STDMETHODIMP UrlmonUrlRequest::OnDataAvailable(DWORD flags, DWORD size,
FORMATETC* formatetc,
STGMEDIUM* storage) {
- DLOG(INFO) << StringPrintf("URL: %s Obj: %X - Bytes available: %d",
- url().c_str(), this, size);
+ DCHECK_EQ(thread_, PlatformThread::CurrentId());
+ DLOG(INFO) << __FUNCTION__ << me() << "bytes available: " << size;
if (terminate_requested())
return INET_E_TERMINATED_BIND;
@@ -427,30 +480,17 @@ STDMETHODIMP UrlmonUrlRequest::OnDataAvailable(DWORD flags, DWORD size,
return E_UNEXPECTED;
}
- HRESULT hr = S_OK;
- // Always read data into cache. We have to read all the data here at this
- // 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 cached = cached_data_.size();
- cached_data_.Append(read_stream);
- DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
- " - Bytes read into cache: " << cached_data_.size() - cached;
-
- if (pending_read_size_ && cached_data_.is_valid()) {
+ pending_data_ = read_stream;
+
+ if (pending_read_size_) {
size_t bytes_copied = SendDataToDelegate(pending_read_size_);
- DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
- " - size read: " << bytes_copied;
- pending_read_size_ = 0;
+ DLOG(INFO) << __FUNCTION__ << me() << "size read: " << bytes_copied;
} else {
- DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
- " - waiting for remote read";
+ DLOG(INFO) << __FUNCTION__ << me() << "- waiting for remote read";
}
if (BSCF_LASTDATANOTIFICATION & flags) {
- DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
- " - end of data.";
-
+ DLOG(INFO) << __FUNCTION__ << me() << "end of data.";
// Always return INET_E_TERMINATED_BIND to allow bind context reuse
// if DownloadToHost is suddenly requested.
return INET_E_TERMINATED_BIND;
@@ -475,8 +515,7 @@ STDMETHODIMP UrlmonUrlRequest::BeginningTransaction(const wchar_t* url,
return E_POINTER;
}
- DLOG(INFO) << "URL: " << url << " Obj: " << std::hex << this <<
- " - Request headers: \n" << current_headers;
+ DLOG(INFO) << __FUNCTION__ << me() << "headers: \n" << current_headers;
if (status_.get_state() == Status::ABORTING) {
// At times the BINDSTATUS_REDIRECTING notification which is sent to the
@@ -488,7 +527,7 @@ STDMETHODIMP UrlmonUrlRequest::BeginningTransaction(const wchar_t* url,
// However urlmon still tries to establish a transaction with the
// redirected URL which confuses the web server.
// Fix is to abort the attempted transaction.
- DLOG(WARNING) << __FUNCTION__
+ DLOG(WARNING) << __FUNCTION__ << me()
<< ": Aborting connection to URL:"
<< url
<< " as the binding has been aborted";
@@ -534,11 +573,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) {
- DLOG(INFO) << __FUNCTION__ << " " << url() << std::endl << " headers: " <<
- std::endl << response_headers;
- DLOG(INFO) << __FUNCTION__
- << StringPrintf(" this=0x%08X, tid=%i", this, ::GetCurrentThreadId());
DCHECK_EQ(thread_, PlatformThread::CurrentId());
+ DLOG(INFO) << __FUNCTION__ << me() << "headers: \n" << response_headers;
std::string raw_headers = WideToUTF8(response_headers);
@@ -568,10 +604,11 @@ STDMETHODIMP UrlmonUrlRequest::OnResponse(DWORD dwResponseCode,
}
}
- DLOG(INFO) << "Calling OnResponseStarted";
+ DLOG(INFO) << __FUNCTION__ << me() << "Calling OnResponseStarted";
// Inform the delegate.
headers_received_ = true;
+ DCHECK(id() != -1);
delegate_->OnResponseStarted(id(),
"", // mime_type
raw_headers.c_str(), // headers
@@ -592,7 +629,7 @@ STDMETHODIMP UrlmonUrlRequest::GetWindow(const GUID& guid_reason,
wchar_t guid[40] = {0};
::StringFromGUID2(guid_reason, guid, arraysize(guid));
- DLOG(INFO) << " Obj: " << std::hex << this << " GetWindow: " <<
+ DLOG(INFO) << __FUNCTION__ << me() << "GetWindow: " <<
(guid_reason == IID_IAuthenticate ? L" - IAuthenticate" :
(guid_reason == IID_IHttpSecurity ? L"IHttpSecurity" :
(guid_reason == IID_IWindowForBindingUI ? L"IWindowForBindingUI" :
@@ -648,7 +685,7 @@ STDMETHODIMP UrlmonUrlRequest::OnSecurityProblem(DWORD problem) {
// decided to go with the easier option of implementing the IHttpSecurity
// interface and replicating the checks performed by Urlmon. This
// causes Urlmon to display a dialog box on the same lines as IE6.
- DLOG(INFO) << __FUNCTION__ << " Security problem : " << problem;
+ DLOG(INFO) << __FUNCTION__ << me() << "Security problem : " << problem;
// On IE6 the default IBindStatusCallback interface does not implement the
// IHttpSecurity interface and thus causes IE to put up a certificate error
@@ -681,8 +718,7 @@ STDMETHODIMP UrlmonUrlRequest::OnSecurityProblem(DWORD problem) {
}
HRESULT UrlmonUrlRequest::StartAsyncDownload() {
- DLOG(INFO) << __FUNCTION__
- << StringPrintf(" this=0x%08X, tid=%i", this, ::GetCurrentThreadId());
+ DLOG(INFO) << __FUNCTION__ << me() << url();
HRESULT hr = E_FAIL;
DCHECK((moniker_ && bind_context_) || (!moniker_ && !bind_context_));
@@ -732,22 +768,24 @@ HRESULT UrlmonUrlRequest::StartAsyncDownload() {
// TODO(joshia): Look into. This currently fails for:
// http://user2:secret@localhost:1337/auth-basic?set-cookie-if-challenged
// when running the UrlRequest unit tests.
- DLOG(ERROR) <<
- StringPrintf("IUrlMoniker::BindToStorage failed. Error: 0x%08X.", hr)
- << std::endl << url();
- DCHECK(hr == MK_E_SYNTAX);
+ DLOG(ERROR) << __FUNCTION__ << me() <<
+ StringPrintf("IUrlMoniker::BindToStorage failed 0x%08X.", hr);
+ // In most cases we'll get a MK_E_SYNTAX error here but if we abort
+ // the navigation ourselves such as in the case of seeing something
+ // else than ALLOWALL in X-Frame-Options.
}
}
- DLOG_IF(ERROR, FAILED(hr))
- << StringPrintf(L"StartAsyncDownload failed: 0x%08X", hr);
+ DLOG_IF(ERROR, FAILED(hr)) << me() <<
+ StringPrintf(L"StartAsyncDownload failed: 0x%08X", hr);
return hr;
}
void UrlmonUrlRequest::NotifyDelegateAndDie() {
DCHECK_EQ(thread_, PlatformThread::CurrentId());
- DLOG(INFO) << __FUNCTION__;
+ DLOG(INFO) << __FUNCTION__ << me();
+
PluginUrlRequestDelegate* delegate = delegate_;
delegate_ = NULL;
ReleaseBindings();
@@ -755,6 +793,8 @@ void UrlmonUrlRequest::NotifyDelegateAndDie() {
if (delegate) {
URLRequestStatus result = status_.get_result();
delegate->OnResponseEnd(id(), result);
+ } else {
+ DLOG(WARNING) << __FUNCTION__ << me() << "no delegate";
}
}
@@ -768,133 +808,6 @@ void UrlmonUrlRequest::ReleaseBindings() {
}
}
-//
-// UrlmonUrlRequest::Cache implementation.
-//
-
-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;
- }
-}
-
-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__;
- *bytes_copied = 0;
- while (bytes) {
- GetReadBuffer(&src, &src_size);
- if (src_size == 0)
- break;
-
- size_t bytes_to_copy = std::min(src_size, bytes);
- memcpy(dest, src, bytes_to_copy);
-
- BytesRead(bytes_to_copy);
- dest = reinterpret_cast<uint8*>(dest) + bytes_to_copy;
- bytes -= bytes_to_copy;
- *bytes_copied += bytes_to_copy;
- }
-
- return true;
-}
-
-
-void UrlmonUrlRequest::Cache::GetWriteBuffer(void** dest, size_t* bytes_avail) {
- if (cache_.size() == 0 || write_offset_ == BUF_SIZE) {
-
- 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_;
-}
-
-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) {
- if (!source) {
- NOTREACHED();
- return false;
- }
-
- HRESULT hr = S_OK;
- while (SUCCEEDED(hr)) {
- void* dest = 0;
- size_t bytes = 0;
- DWORD chunk_read = 0; // NOLINT
- GetWriteBuffer(&dest, &bytes);
- hr = source->Read(dest, bytes, &chunk_read);
- BytesWritten(chunk_read);
-
- if (hr == S_OK && chunk_read == 0) {
- // implied EOF
- break;
- }
-
- if (hr == S_FALSE) {
- // EOF
- break;
- }
- }
-
- return SUCCEEDED(hr);
-}
-
net::Error UrlmonUrlRequest::HresultToNetError(HRESULT hr) {
// Useful reference:
// http://msdn.microsoft.com/en-us/library/ms775145(VS.85).aspx
@@ -984,22 +897,24 @@ void UrlmonUrlRequestManager::SetInfoForUrl(const std::wstring& url,
void UrlmonUrlRequestManager::StartRequest(int request_id,
const IPC::AutomationURLRequest& request_info) {
- DLOG(INFO) << __FUNCTION__;
+ DLOG(INFO) << __FUNCTION__ << " id: " << request_id;
DCHECK_EQ(0, calling_delegate_);
if (stopping_)
return;
- DCHECK(LookupRequest(request_id).get() == NULL);
+ DCHECK(request_map_.find(request_id) == request_map_.end());
DCHECK(GURL(request_info.url).is_valid());
scoped_refptr<UrlmonUrlRequest> new_request;
bool is_started = false;
if (pending_request_) {
- DCHECK(pending_request_->IsForUrl(GURL(request_info.url)));
+ DCHECK_EQ(pending_request_->url(), request_info.url);
new_request.swap(pending_request_);
new_request->set_pending(false);
is_started = true;
+ DLOG(INFO) << __FUNCTION__ << new_request->me()
+ << "assigned id " << request_id;
} else {
CComObject<UrlmonUrlRequest>* created_request = NULL;
CComObject<UrlmonUrlRequest>::CreateInstance(&created_request);
@@ -1025,6 +940,7 @@ void UrlmonUrlRequestManager::StartRequest(int request_id,
} else {
// Request is already underway, call OnResponse so that the
// other side can start reading.
+ DCHECK(!new_request->response_headers().empty());
new_request->OnResponse(
0, UTF8ToWide(new_request->response_headers()).c_str(), NULL, NULL);
}
@@ -1048,6 +964,8 @@ void UrlmonUrlRequestManager::DownloadRequestInHost(int request_id) {
UrlmonUrlRequest::TerminateBindCallback* callback = NewCallback(this,
&UrlmonUrlRequestManager::BindTerminated);
request->TerminateBind(callback);
+ } else {
+ NOTREACHED();
}
} else {
NOTREACHED()
@@ -1139,6 +1057,8 @@ void UrlmonUrlRequestManager::EndRequest(int request_id) {
if (request) {
request_map_.erase(request_id);
request->Stop();
+ } else {
+ NOTREACHED();
}
}
@@ -1148,6 +1068,10 @@ void UrlmonUrlRequestManager::StopAll() {
return;
stopping_ = true;
+
+ DLOG(INFO) << __FUNCTION__ << " stopping " <<
+ request_map_.size() << " requests";
+
for (RequestMap::iterator it = request_map_.begin();
it != request_map_.end(); ++it) {
DCHECK(it->second != NULL);
@@ -1161,8 +1085,9 @@ void UrlmonUrlRequestManager::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) {
+ DCHECK_NE(request_id, -1);
DLOG(INFO) << __FUNCTION__;
- DCHECK(LookupRequest(request_id).get() != NULL);
+ DCHECK(LookupRequest(request_id) != NULL);
++calling_delegate_;
delegate_->OnResponseStarted(request_id, mime_type, headers, size,
last_modified, redirect_url, redirect_status);
@@ -1171,15 +1096,18 @@ void UrlmonUrlRequestManager::OnResponseStarted(int request_id,
void UrlmonUrlRequestManager::OnReadComplete(int request_id,
const std::string& data) {
- DLOG(INFO) << __FUNCTION__;
- DCHECK(LookupRequest(request_id).get() != NULL);
+ DCHECK_NE(request_id, -1);
+ DLOG(INFO) << __FUNCTION__ << " id: " << request_id;
+ DCHECK(LookupRequest(request_id) != NULL);
++calling_delegate_;
delegate_->OnReadComplete(request_id, data);
--calling_delegate_;
+ DLOG(INFO) << __FUNCTION__ << " done id: " << request_id;
}
void UrlmonUrlRequestManager::OnResponseEnd(int request_id,
const URLRequestStatus& status) {
+ DCHECK_NE(request_id, -1);
DLOG(INFO) << __FUNCTION__;
DCHECK(status.status() != URLRequestStatus::CANCELED);
RequestMap::size_type n = request_map_.erase(request_id);
@@ -1191,6 +1119,7 @@ void UrlmonUrlRequestManager::OnResponseEnd(int request_id,
void UrlmonUrlRequestManager::OnCookiesRetrieved(bool success, const GURL& url,
const std::string& cookie_string, int cookie_id) {
+ DCHECK(url.is_valid());
delegate_->OnCookiesRetrieved(success, url, cookie_string, cookie_id);
}
@@ -1199,6 +1128,7 @@ scoped_refptr<UrlmonUrlRequest> UrlmonUrlRequestManager::LookupRequest(
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;
}
@@ -1214,6 +1144,7 @@ UrlmonUrlRequestManager::~UrlmonUrlRequestManager() {
void UrlmonUrlRequestManager::AddPrivacyDataForUrl(
const std::string& url, const std::string& policy_ref,
int32 flags) {
+ DCHECK(!url.empty());
AutoLock lock(privacy_info_lock_);
bool fire_privacy_event = false;
diff --git a/chrome_frame/urlmon_url_request_private.h b/chrome_frame/urlmon_url_request_private.h
index f8c3561..f116998 100644
--- a/chrome_frame/urlmon_url_request_private.h
+++ b/chrome_frame/urlmon_url_request_private.h
@@ -8,7 +8,6 @@
#include <atlbase.h>
#include <atlcom.h>
#include <string>
-#include <deque>
#include "net/base/net_errors.h"
#include "net/http/http_response_headers.h"
@@ -52,9 +51,9 @@ class UrlmonUrlRequest
privileged_mode_ = privileged_mode;
}
- bool IsForUrl(const GURL& other) const {
- return url_ == other;
- }
+ // Returns a string in the form " id: %i Obj: %X URL: %s" which is useful
+ // to identify request objects in the log.
+ std::string me() const;
protected:
UrlmonUrlRequest();
@@ -73,25 +72,24 @@ class UrlmonUrlRequest
SERVICE_ENTRY(IID_IHttpNegotiate);
END_SERVICE_MAP()
-
// IBindStatusCallback implementation
STDMETHOD(OnStartBinding)(DWORD reserved, IBinding* binding);
STDMETHOD(GetPriority)(LONG* priority);
STDMETHOD(OnLowResource)(DWORD reserved);
STDMETHOD(OnProgress)(ULONG progress, ULONG max_progress,
- ULONG status_code, LPCWSTR status_text);
+ ULONG status_code, LPCWSTR status_text);
STDMETHOD(OnStopBinding)(HRESULT result, LPCWSTR error);
STDMETHOD(GetBindInfo)(DWORD* bind_flags, BINDINFO* bind_info);
STDMETHOD(OnDataAvailable)(DWORD flags, DWORD size, FORMATETC* formatetc,
- STGMEDIUM* storage);
+ STGMEDIUM* storage);
STDMETHOD(OnObjectAvailable)(REFIID iid, IUnknown* object);
// IHttpNegotiate implementation
STDMETHOD(BeginningTransaction)(const wchar_t* url,
- const wchar_t* current_headers, DWORD reserved,
- wchar_t** additional_headers);
+ const wchar_t* current_headers, DWORD reserved,
+ wchar_t** additional_headers);
STDMETHOD(OnResponse)(DWORD dwResponseCode, const wchar_t* response_headers,
- const wchar_t* request_headers, wchar_t** additional_headers);
+ const wchar_t* request_headers, wchar_t** additional_headers);
// IWindowForBindingUI implementation. This interface is used typically to
// query the window handle which URLMON uses as the parent of error dialogs.
@@ -100,7 +98,7 @@ class UrlmonUrlRequest
// IAuthenticate implementation. Used to return the parent window for the
// dialog displayed by IE for authenticating with a proxy.
STDMETHOD(Authenticate)(HWND* parent_window, LPWSTR* user_name,
- LPWSTR* password);
+ LPWSTR* password);
// IHttpSecurity implementation.
STDMETHOD(OnSecurityProblem)(DWORD problem);
@@ -124,52 +122,13 @@ class UrlmonUrlRequest
protected:
void ReleaseBindings();
- // Manage data caching. Note: this class supports cache
- // size less than 2GB
- FRIEND_TEST(UrlmonUrlRequestCache, ReadWrite);
- class Cache {
- public:
- Cache() : size_(0), read_offset_(0), write_offset_(0) {
- }
-
- ~Cache();
-
- // 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 {
- return size_;
- }
-
- // Returns true if the cache has valid data.
- bool is_valid() const {
- return size() != 0;
- }
-
- private:
- FRIEND_TEST(UrlmonUrlRequestCache, ReadWrite);
- 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();
void NotifyDelegateAndDie();
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
@@ -268,8 +227,9 @@ class UrlmonUrlRequest
ScopedComPtr<IBinding> binding_;
ScopedComPtr<IMoniker> moniker_;
ScopedComPtr<IBindCtx> bind_context_;
- GURL url_;
- Cache cached_data_;
+ ScopedComPtr<IStream> cache_;
+ ScopedComPtr<IStream> pending_data_;
+
size_t pending_read_size_;
PlatformThreadId thread_;
HWND parent_window_;