Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5330)

Unified Diff: chrome_frame/urlmon_url_request.cc

Issue 545093: Refactor host network (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome_frame/urlmon_url_request.h ('k') | chrome_frame/urlmon_url_request_private.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome_frame/urlmon_url_request.cc
===================================================================
--- chrome_frame/urlmon_url_request.cc (revision 37418)
+++ chrome_frame/urlmon_url_request.cc (working copy)
@@ -11,9 +11,9 @@
#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/extra_system_apis.h"
#include "chrome_frame/html_utils.h"
+#include "chrome_frame/urlmon_url_request_private.h"
#include "chrome_frame/urlmon_upload_data_stream.h"
#include "chrome_frame/utils.h"
#include "net/http/http_util.h"
@@ -21,7 +21,6 @@
static const LARGE_INTEGER kZero = {0};
static const ULARGE_INTEGER kUnsignedZero = {0};
-int UrlmonUrlRequest::instance_count_ = 0;
// This class wraps the IBindCtx interface which is passed in when our active
// document object is instantiated. The IBindCtx interface is created on
@@ -222,14 +221,25 @@
ScopedComPtr<IMarshal> standard_marshal_;
};
+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;
+}
+
+int UrlmonUrlRequest::instance_count_ = 0;
+
UrlmonUrlRequest::UrlmonUrlRequest()
: pending_read_size_(0),
- status_(URLRequestStatus::FAILED, net::ERR_FAILED),
- thread_(PlatformThread::CurrentId()),
- redirect_status_(0),
- parent_window_(NULL),
- worker_thread_(NULL),
- ignore_redirect_stop_binding_error_(false) {
+ thread_(NULL),
+ parent_window_(NULL) {
DLOG(INFO) << StringPrintf("Created request. Obj: %X", this)
<< " Count: " << ++instance_count_;
}
@@ -240,141 +250,100 @@
}
bool UrlmonUrlRequest::Start() {
- DCHECK_EQ(PlatformThread::CurrentId(), thread_);
-
- if (!worker_thread_ || !worker_thread_->message_loop()) {
- NOTREACHED() << __FUNCTION__ << " Urlmon request thread not initialized";
- return false;
+ thread_ = PlatformThread::CurrentId();
+ status_.Start();
+ HRESULT hr = StartAsyncDownload();
+ if (FAILED(hr)) {
+ status_.set_result(URLRequestStatus::FAILED, HresultToNetError(hr));
+ NotifyDelegateAndDie();
}
-
- Create(HWND_MESSAGE);
- if (!IsWindow()) {
- NOTREACHED() << "Failed to create urlmon message window: "
- << GetLastError();
- return false;
- }
-
- // Take a self reference to maintain COM lifetime. This will be released
- // in OnFinalMessage
- AddRef();
- request_handler()->AddRequest(this);
-
- worker_thread_->message_loop()->PostTask(
- FROM_HERE, NewRunnableMethod(this, &UrlmonUrlRequest::StartAsync));
-
return true;
}
void UrlmonUrlRequest::Stop() {
- DCHECK_EQ(PlatformThread::CurrentId(), thread_);
+ DCHECK_EQ(thread_, PlatformThread::CurrentId());
+ DCHECK((status_.get_state() != Status::DONE) == (binding_ != NULL));
+ Status::State state = status_.get_state();
+ switch (state) {
+ case Status::WORKING:
+ status_.Cancel();
+ binding_->Abort();
+ break;
- if (!worker_thread_ || !worker_thread_->message_loop()) {
- NOTREACHED() << __FUNCTION__ << " Urlmon request thread not initialized";
- return;
- }
+ case Status::ABORTING:
+ status_.Cancel();
+ break;
- // We can remove the request from the map safely here if it is still valid.
- // There is an additional reference on the UrlmonUrlRequest instance which
- // is released when the task scheduled by the EndRequest function executes.
- request_handler()->RemoveRequest(this);
-
- 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;
+ case Status::DONE:
+ status_.Cancel();
+ NotifyDelegateAndDie();
+ break;
}
}
-void UrlmonUrlRequest::StopAsync() {
- DCHECK(worker_thread_ != NULL);
-
- if (binding_) {
- binding_->Abort();
- } else {
- status_.set_status(URLRequestStatus::CANCELED);
- status_.set_os_error(net::ERR_FAILED);
- EndRequest();
- }
-}
-
-void UrlmonUrlRequest::OnFinalMessage(HWND window) {
- m_hWnd = NULL;
- // 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();
-}
-
bool UrlmonUrlRequest::Read(int bytes_to_read) {
- DCHECK_EQ(PlatformThread::CurrentId(), thread_);
-
- DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this);
-
- if (!worker_thread_ || !worker_thread_->message_loop()) {
- NOTREACHED() << __FUNCTION__ << " Urlmon request thread not initialized";
+ DCHECK_EQ(thread_, PlatformThread::CurrentId());
+ // Re-entrancy check. Thou shall not call Read() while processOnReadComplete!!
+ DCHECK_EQ(0, pending_read_size_);
+ if (pending_read_size_ != 0)
return false;
- }
- worker_thread_->message_loop()->PostTask(
- FROM_HERE, NewRunnableMethod(this, &UrlmonUrlRequest::ReadAsync,
- bytes_to_read));
- return true;
-}
-
-void UrlmonUrlRequest::TransferToHost(IUnknown* host) {
- DCHECK_EQ(PlatformThread::CurrentId(), thread_);
- DCHECK(host);
- DCHECK(moniker_);
- if (moniker_) {
- ScopedComPtr<IBindCtx> bind_context;
- CreateBindCtx(0, bind_context.Receive());
- DCHECK(bind_context);
- NavigateBrowserToMoniker(host, moniker_, NULL, bind_context, NULL);
- moniker_.Release();
+ DCHECK((status_.get_state() != Status::DONE) == (binding_ != NULL));
+ if (status_.get_state() == Status::ABORTING) {
+ 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)) {
+ if (delegate_ && 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;
+ url().c_str(), this, bytes_copied);
+ return true;
}
- // if the request is finished or there's nothing more to read
- // then end the request
- if (!status_.is_io_pending() || !binding_) {
- DLOG(INFO) << StringPrintf("URL: %s Obj: %X. Response finished. Status: %d",
- url().c_str(), this, status_.status());
- EndRequest();
- return;
+ if (status_.get_state() == Status::WORKING) {
+ DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
+ "- Read pending for: " << bytes_to_read;
+ pending_read_size_ = bytes_to_read;
+ } else {
+ DLOG(INFO) << StringPrintf("URL: %s Obj: %X. Response finished.",
+ url().c_str(), this);
+ NotifyDelegateAndDie();
}
- 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(
- DWORD reserved, IBinding *binding) {
+HRESULT UrlmonUrlRequest::ConnectToExistingMoniker(IMoniker* moniker,
+ IBindCtx* context,
+ const std::wstring& url) {
+ if (!moniker || url.empty()) {
+ NOTREACHED() << "Invalid arguments";
+ return E_INVALIDARG;
+ }
+
+ DCHECK(moniker_.get() == NULL);
+ DCHECK(bind_context_.get() == NULL);
+
+ bind_context_ = context;
+ moniker_ = moniker;
+ set_url(WideToUTF8(url));
+ return S_OK;
+}
+
+void UrlmonUrlRequest::StealMoniker(IMoniker** moniker) {
+ // Could be called in any thread. There should be no race
+ // since moniker_ is not released while we are in manager's request map.
+ *moniker = moniker_.Detach();
+}
+
+STDMETHODIMP UrlmonUrlRequest::OnStartBinding(DWORD reserved,
+ IBinding *binding) {
+ DCHECK_EQ(thread_, PlatformThread::CurrentId());
binding_ = binding;
return S_OK;
}
@@ -392,35 +361,16 @@
STDMETHODIMP UrlmonUrlRequest::OnProgress(ULONG progress, ULONG max_progress,
ULONG status_code, LPCWSTR status_text) {
- static const int kDefaultHttpRedirectCode = 302;
-
+ DCHECK_EQ(thread_, PlatformThread::CurrentId());
switch (status_code) {
case BINDSTATUS_REDIRECTING: {
+ DLOG(INFO) << "URL: " << url() << " redirected to " << status_text;
// Fetch the redirect status as they aren't all equal (307 in particular
// retains the HTTP request verb).
- // We assume that valid redirect codes are 301, 302, 303 and 307. If we
- // receive anything else we would abort the request which would
- // eventually result in the request getting cancelled in Chrome.
- int redirect_status = GetHttpResponseStatus();
- DCHECK(status_text != NULL);
- DLOG(INFO) << "URL: " << url() << " redirected to "
- << status_text;
- redirect_url_ = status_text;
- // At times we receive invalid redirect codes like 0, 200, etc. We
- // default to 302 in this case.
- if (!net::HttpResponseHeaders::IsRedirectResponseCode(redirect_status))
- redirect_status = kDefaultHttpRedirectCode;
- redirect_status_ = redirect_status;
- // Chrome should decide whether a redirect has to be followed. To achieve
- // this we send over a fake response to Chrome and abort the redirect.
- std::string headers = GetHttpHeaders();
- OnResponse(0, UTF8ToWide(headers).c_str(), NULL, NULL);
- ignore_redirect_stop_binding_error_ = true;
- DCHECK(binding_ != NULL);
- if (binding_) {
- binding_->Abort();
- binding_ = NULL;
- }
+ int http_code = GetHttpResponseStatus();
+ status_.SetRedirected(http_code, WideToUTF8(status_text));
+ // Abort. We will inform Chrome in OnStopBinding callback.
+ binding_->Abort();
return E_ABORT;
}
@@ -434,39 +384,51 @@
}
STDMETHODIMP UrlmonUrlRequest::OnStopBinding(HRESULT result, LPCWSTR error) {
- DCHECK(worker_thread_ != NULL);
- DCHECK_EQ(PlatformThread::CurrentId(), worker_thread_->thread_id());
-
+ DCHECK_EQ(thread_, PlatformThread::CurrentId());
DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
- " - Request stopped, Result: " << std::hex << result <<
- " Status: " << status_.status();
+ " - Request stopped, Result: " << std::hex << result;
+ DCHECK(status_.get_state() == Status::WORKING ||
+ status_.get_state() == Status::ABORTING);
+ Status::State state = status_.get_state();
- if (FAILED(result)) {
- status_.set_status(URLRequestStatus::FAILED);
- status_.set_os_error(HresultToNetError(result));
- EndRequest();
- } else {
- status_.set_status(URLRequestStatus::SUCCESS);
- status_.set_os_error(0);
- ReleaseBindings();
- // In most cases we receive the end request notification from Chrome.
- // However at times requests can complete without us receiving any
- // data. In this case we need to inform Chrome that this request has been
- // completed to prevent Chrome from waiting forever for data for this
- // request.
- if (pending_read_size_) {
- pending_read_size_ = 0;
- OnResponseEnd(status_);
+ // Mark we a are done.
+ status_.Done();
+
+ if (state == Status::WORKING) {
+ status_.set_result(result);
+
+ // The code below seems easy but it is not. :)
+ // we cannot have pending read and data_avail at the same time.
+ DCHECK(!(pending_read_size_ > 0 && cached_data_.is_valid()));
+
+ // We have some data, but Chrome has not yet read it. Wait until Chrome
+ // read the remaining of the data and then send the error/success code.
+ if (cached_data_.is_valid()) {
+ ReleaseBindings();
+ return S_OK;
}
+
+ NotifyDelegateAndDie();
+ return S_OK;
}
+ // Status::ABORTING
+ if (status_.was_redirected()) {
+ // Just release bindings here. Chrome will issue EndRequest(request_id)
+ // after processing headers we had provided.
+ std::string headers = GetHttpHeaders();
+ OnResponse(0, UTF8ToWide(headers).c_str(), NULL, NULL);
+ ReleaseBindings();
+ return S_OK;
+ }
+
+ // Stop invoked.
+ NotifyDelegateAndDie();
return S_OK;
}
STDMETHODIMP UrlmonUrlRequest::GetBindInfo(DWORD* bind_flags,
BINDINFO *bind_info) {
- 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;
@@ -485,9 +447,8 @@
upload_data = true;
} else {
NOTREACHED() << "Unknown HTTP method.";
- status_.set_status(URLRequestStatus::FAILED);
- status_.set_os_error(net::ERR_METHOD_NOT_SUPPORTED);
- EndRequest();
+ status_.set_result(URLRequestStatus::FAILED, net::ERR_METHOD_NOT_SUPPORTED);
+ NotifyDelegateAndDie();
return E_FAIL;
}
@@ -519,9 +480,6 @@
STDMETHODIMP UrlmonUrlRequest::OnDataAvailable(DWORD flags, DWORD size,
FORMATETC* formatetc,
STGMEDIUM* storage) {
- 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);
@@ -563,7 +521,6 @@
}
if (BSCF_LASTDATANOTIFICATION & flags) {
- status_.set_status(URLRequestStatus::SUCCESS);
DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
" - end of data.";
}
@@ -581,9 +538,7 @@
STDMETHODIMP UrlmonUrlRequest::BeginningTransaction(const wchar_t* url,
const wchar_t* current_headers, DWORD reserved,
wchar_t** additional_headers) {
- DCHECK(worker_thread_ != NULL);
- DCHECK_EQ(PlatformThread::CurrentId(), worker_thread_->thread_id());
-
+ DCHECK_EQ(thread_, PlatformThread::CurrentId());
if (!additional_headers) {
NOTREACHED();
return E_POINTER;
@@ -592,7 +547,7 @@
DLOG(INFO) << "URL: " << url << " Obj: " << std::hex << this <<
" - Request headers: \n" << current_headers;
- if (!binding_) {
+ if (status_.get_state() == Status::ABORTING) {
// At times the BINDSTATUS_REDIRECTING notification which is sent to the
// IBindStatusCallback interface does not have an accompanying HTTP
// redirect status code, i.e. the attempt to query the HTTP status code
@@ -602,7 +557,6 @@
// However urlmon still tries to establish a transaction with the
// redirected URL which confuses the web server.
// Fix is to abort the attempted transaction.
- DCHECK(ignore_redirect_stop_binding_error_);
DLOG(WARNING) << __FUNCTION__
<< ": Aborting connection to URL:"
<< url
@@ -649,13 +603,10 @@
STDMETHODIMP UrlmonUrlRequest::OnResponse(DWORD dwResponseCode,
const wchar_t* response_headers, const wchar_t* request_headers,
wchar_t** additional_headers) {
- DCHECK(worker_thread_ != NULL);
DLOG(INFO) << __FUNCTION__ << " " << url() << std::endl << " headers: " <<
std::endl << response_headers;
- DCHECK_EQ(PlatformThread::CurrentId(), worker_thread_->thread_id());
-
+ DCHECK_EQ(thread_, PlatformThread::CurrentId());
if (!binding_) {
- DCHECK(redirect_url_.empty() == false);
DLOG(WARNING) << __FUNCTION__
<< ": Ignoring as the binding was aborted due to a redirect";
return S_OK;
@@ -679,7 +630,7 @@
// NOTE(slightlyoff): We don't use net::HttpResponseHeaders here because
// of lingering ICU/base_noicu issues.
- if (frame_busting_enabled_) {
+ if (enable_frame_busting_) {
std::string http_headers = net::HttpUtil::AssembleRawHeaders(
raw_headers.c_str(), raw_headers.length());
if (http_utils::HasFrameBustingHeader(http_headers)) {
@@ -689,36 +640,44 @@
}
}
- std::wstring url_for_persistent_cookies =
- redirect_url_.empty() ? UTF8ToWide(url()) : redirect_url_;
+ std::string url_for_persistent_cookies;
std::string persistent_cookies;
- DWORD cookie_size = 0; // NOLINT
- // Note that there's really no way for us here to distinguish session cookies
- // from persistent cookies here. Session cookies should get filtered
- // out on the chrome side as to not be added again.
- InternetGetCookie(url_for_persistent_cookies.c_str(), NULL, NULL,
- &cookie_size);
- if (cookie_size) {
- scoped_array<wchar_t> cookies(new wchar_t[cookie_size + 1]);
- if (!InternetGetCookie(url_for_persistent_cookies.c_str(), NULL,
- cookies.get(), &cookie_size)) {
- NOTREACHED() << "InternetGetCookie failed. Error: " << GetLastError();
- } else {
- persistent_cookies = WideToUTF8(cookies.get());
+ if (status_.was_redirected())
+ url_for_persistent_cookies = status_.get_redirection().utf8_url;
+
+ if (url_for_persistent_cookies.empty())
+ url_for_persistent_cookies = url();
+
+ // Grab cookies for the specific Url from WININET.
+ {
+ DWORD cookie_size = 0; // NOLINT
+ std::wstring url = UTF8ToWide(url_for_persistent_cookies);
+
+ // Note that there's really no way for us here to distinguish session
+ // cookies from persistent cookies here. Session cookies should get
+ // filtered out on the chrome side as to not be added again.
+ InternetGetCookie(url.c_str(), NULL, NULL, &cookie_size);
+ if (cookie_size) {
+ scoped_array<wchar_t> cookies(new wchar_t[cookie_size + 1]);
+ if (!InternetGetCookie(url.c_str(), NULL, cookies.get(), &cookie_size)) {
+ NOTREACHED() << "InternetGetCookie failed. Error: " << GetLastError();
+ } else {
+ persistent_cookies = WideToUTF8(cookies.get());
+ }
}
}
- OnResponseStarted("",
- raw_headers.c_str(),
- 0,
- base::Time(),
+ // Inform the delegate.
+ delegate_->OnResponseStarted(id(),
+ "", // mime_type
+ raw_headers.c_str(), // headers
+ 0, // size
+ base::Time(), // last_modified
persistent_cookies,
- redirect_url_.empty() ? std::string() :
- WideToUTF8(redirect_url_),
- redirect_status_);
-
+ status_.get_redirection().utf8_url,
+ status_.get_redirection().http_code);
return S_OK;
}
@@ -818,41 +777,6 @@
return hr;
}
-HRESULT UrlmonUrlRequest::ConnectToExistingMoniker(IMoniker* moniker,
- IBindCtx* context,
- const std::wstring& url) {
- if (!moniker || url.empty()) {
- NOTREACHED() << "Invalid arguments";
- return E_INVALIDARG;
- }
-
- DCHECK(moniker_.get() == NULL);
- DCHECK(bind_context_.get() == NULL);
-
- CComObject<WrappedBindContext>* bind_context = NULL;
- HRESULT hr = CComObject<WrappedBindContext>::CreateInstance(&bind_context);
- if (FAILED(hr)) {
- NOTREACHED() << "Failed to instantiate wrapped bind context. Error:" << hr;
- return hr;
- }
-
- bind_context->AddRef();
- hr = bind_context->Initialize(context);
- DCHECK(SUCCEEDED(hr));
-
- hr = bind_context->QueryInterface(bind_context_.Receive());
- bind_context->Release();
-
- if (FAILED(hr)) {
- NOTREACHED() << "Failed to QI for IBindCtx on wrapper. Error:" << hr;
- return hr;
- }
-
- moniker_ = moniker;
- set_url(WideToUTF8(url));
- return S_OK;
-}
-
HRESULT UrlmonUrlRequest::StartAsyncDownload() {
HRESULT hr = E_FAIL;
if (moniker_.get() == NULL) {
@@ -874,6 +798,12 @@
ScopedComPtr<IStream> stream;
hr = moniker_->BindToStorage(bind_context_, NULL, __uuidof(IStream),
reinterpret_cast<void**>(stream.Receive()));
+ // Even if hr == S_OK, binding_ could be NULL if the entire request
+ // finish synchronously but then we still get all the callbacks etc.
+ if (hr == S_OK) {
+ DCHECK(binding_ != NULL || status_.get_state() == Status::DONE);
+ }
+
if (FAILED(hr)) {
// TODO(joshia): Look into. This currently fails for:
// http://user2:secret@localhost:1337/auth-basic?set-cookie-if-challenged
@@ -891,48 +821,17 @@
return hr;
}
-void UrlmonUrlRequest::EndRequest() {
+void UrlmonUrlRequest::NotifyDelegateAndDie() {
+ DCHECK_EQ(thread_, PlatformThread::CurrentId());
DLOG(INFO) << __FUNCTION__;
-
- // In case of a redirect notification we prevent urlmon from following the
- // redirect and rely on Chrome, in which case AutomationMsg_RequestEnd
- // IPC will be sent over by Chrome to end this request.
- if (!ignore_redirect_stop_binding_error_) {
- // Special case. If the last request was a redirect and the current OS
- // error value is E_ACCESSDENIED, that means an unsafe redirect was
- // attempted. In that case, correct the OS error value to be the more
- // specific ERR_UNSAFE_REDIRECT error value.
- if (!status_.is_success() && status_.os_error() == net::ERR_ACCESS_DENIED) {
- int status = GetHttpResponseStatus();
- if (status >= 300 && status < 400) {
- redirect_status_ = status; // store the latest redirect status value.
- status_.set_os_error(net::ERR_UNSAFE_REDIRECT);
- }
- }
- OnResponseEnd(status_);
- } else {
- ignore_redirect_stop_binding_error_ = false;
+ PluginUrlRequestDelegate* delegate = delegate_;
+ delegate_ = NULL;
+ ReleaseBindings();
+ if (delegate) {
+ delegate->OnResponseEnd(id(), status_.get_result());
}
-
- ReleaseBindings();
- // Remove the request mapping and release the outstanding reference to us in
- // the context of the UI thread.
- // We should not access any members of the UrlmonUrlRequest object after this
- // as the object would be deleted.
- PostTask(FROM_HERE,
- NewRunnableMethod(this, &UrlmonUrlRequest::EndRequestInternal));
}
-void UrlmonUrlRequest::EndRequestInternal() {
- // The request object could have been removed from the map in the
- // OnRequestEnd callback which executes on receiving the
- // AutomationMsg_RequestEnd IPC from Chrome.
- request_handler()->RemoveRequest(this);
- // The current instance could get destroyed in the context of DestroyWindow.
- // We should not access the object after this.
- DestroyWindow();
-}
-
int UrlmonUrlRequest::GetHttpResponseStatus() const {
if (binding_ == NULL) {
DLOG(WARNING) << "GetHttpResponseStatus - no binding_";
@@ -1096,3 +995,236 @@
}
return ret;
}
+
+
+bool UrlmonUrlRequestManager::IsThreadSafe() {
+ return true;
+}
+
+void UrlmonUrlRequestManager::UseMonikerForUrl(IMoniker* moniker,
+ IBindCtx* bind_ctx,
+ const std::wstring& url) {
+ DCHECK(NULL == moniker_for_url_.get());
+ moniker_for_url_.reset(new MonikerForUrl());
+ moniker_for_url_->moniker = moniker;
+ moniker_for_url_->url = url;
+
+ CComObject<WrappedBindContext>* ctx = NULL;
+ CComObject<WrappedBindContext>::CreateInstance(&ctx);
+ ctx->Initialize(bind_ctx);
+ ctx->QueryInterface(moniker_for_url_->bind_ctx.Receive());
+ DCHECK(moniker_for_url_->bind_ctx.get());
+}
+
+void UrlmonUrlRequestManager::StartRequest(int request_id,
+ const IPC::AutomationURLRequest& request_info) {
+ if (stopping_) {
+ return;
+ }
+
+ if (!worker_thread_.IsRunning())
+ worker_thread_.Start();
+
+ MonikerForUrl* use_moniker = NULL;
+ if (moniker_for_url_.get()) {
+ if (GURL(moniker_for_url_->url) == GURL(request_info.url)) {
+ use_moniker = moniker_for_url_.release();
+ }
+ }
+
+ worker_thread_.message_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &UrlmonUrlRequestManager::StartRequestWorker,
+ request_id, request_info, use_moniker));
+}
+
+void UrlmonUrlRequestManager::StartRequestWorker(int request_id,
+ const IPC::AutomationURLRequest& request_info,
+ MonikerForUrl* use_moniker) {
+ DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
+ scoped_ptr<MonikerForUrl> moniker_for_url(use_moniker);
+
+ if (stopping_)
+ return;
+
+ DCHECK(LookupRequest(request_id).get() == NULL);
+
+ CComObject<UrlmonUrlRequest>* new_request = NULL;
+ CComObject<UrlmonUrlRequest>::CreateInstance(&new_request);
+
+ new_request->Initialize(static_cast<PluginUrlRequestDelegate*>(this),
+ request_id,
+ request_info.url,
+ request_info.method,
+ request_info.referrer,
+ request_info.extra_request_headers,
+ request_info.upload_data,
+ enable_frame_busting_);
+
+ // Shall we use an existing moniker?
+ if (moniker_for_url.get()) {
+ new_request->ConnectToExistingMoniker(moniker_for_url->moniker,
+ moniker_for_url->bind_ctx,
+ moniker_for_url->url);
+ }
+
+ 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) {
+ if (stopping_)
+ return;
+
+ worker_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &UrlmonUrlRequestManager::ReadRequestWorker, request_id, bytes_to_read));
+}
+
+void UrlmonUrlRequestManager::ReadRequestWorker(int request_id,
+ int bytes_to_read) {
+ DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
+ scoped_refptr<UrlmonUrlRequest> request = LookupRequest(request_id);
+ // if zero, it may just have had network error.
+ if (request) {
+ request->Read(bytes_to_read);
+ }
+}
+
+void UrlmonUrlRequestManager::EndRequest(int request_id) {
+ if (stopping_)
+ return;
+
+ worker_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &UrlmonUrlRequestManager::EndRequestWorker, request_id));
+}
+
+void UrlmonUrlRequestManager::EndRequestWorker(int request_id) {
+ DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
+ scoped_refptr<UrlmonUrlRequest> request = LookupRequest(request_id);
+ if (request) {
+ request->Stop();
+ }
+}
+
+void UrlmonUrlRequestManager::StopAll() {
+ if (stopping_)
+ return;
+
+ stopping_ = true;
+
+ if (!worker_thread_.IsRunning())
+ return;
+
+ worker_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &UrlmonUrlRequestManager::StopAllWorker));
+
+ // 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_.Stop();
+ DCHECK_EQ(0, UrlmonUrlRequest::instance_count_);
+}
+
+void UrlmonUrlRequestManager::StopAllWorker() {
+ DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
+ DCHECK_EQ(true, stopping_);
+
+ 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.
+ for (RequestMap::iterator it = request_map_.begin();
+ it != request_map_.end(); ++it) {
+ DCHECK(it->second != NULL);
+ request_list.push_back(it->second);
+ }
+
+ for (std::vector<scoped_refptr<UrlmonUrlRequest> >::size_type index = 0;
+ index < request_list.size(); ++index) {
+ request_list[index]->Stop();
+ }
+}
+
+void UrlmonUrlRequestManager::OnResponseStarted(int request_id,
+ const char* mime_type, const char* headers, int size,
+ base::Time last_modified, const std::string& peristent_cookies,
+ const std::string& redirect_url, int redirect_status) {
+ DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
+ DCHECK(LookupRequest(request_id).get() != NULL);
+ delegate_->OnResponseStarted(request_id, mime_type, headers, size,
+ last_modified, peristent_cookies, redirect_url, redirect_status);
+}
+
+void UrlmonUrlRequestManager::OnReadComplete(int request_id, const void* buffer,
+ int len) {
+ DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
+ DCHECK(LookupRequest(request_id).get() != NULL);
+ delegate_->OnReadComplete(request_id, buffer, len);
+}
+
+void UrlmonUrlRequestManager::OnResponseEnd(int request_id,
+ const URLRequestStatus& status) {
+ DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
+ 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);
+}
+
+scoped_refptr<UrlmonUrlRequest> UrlmonUrlRequestManager::LookupRequest(
+ int request_id) {
+ RequestMap::iterator it = request_map_.find(request_id);
+ if (request_map_.end() != it)
+ return it->second;
+ return NULL;
+}
+
+UrlmonUrlRequestManager::UrlmonUrlRequestManager()
+ : stopping_(false), worker_thread_("UrlMon fetch thread"),
+ map_empty_(true, true) {
+}
+
+UrlmonUrlRequestManager::~UrlmonUrlRequestManager() {
+ StopAll();
+}
+
+// Called from UI thread.
+void UrlmonUrlRequestManager::StealMonikerFromRequest(int request_id,
+ IMoniker** moniker) {
+ if (stopping_)
+ return;
+
+ base::WaitableEvent done(true, false);
+ worker_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &UrlmonUrlRequestManager::StealMonikerFromRequestWorker,
+ request_id, moniker, &done));
+
+ // Wait until moniker is grabbed from a request in the worker thread.
+ done.Wait();
+}
+
+void UrlmonUrlRequestManager::StealMonikerFromRequestWorker(int request_id,
+ IMoniker** moniker, base::WaitableEvent* done) {
+ if (!stopping_) {
+ scoped_refptr<UrlmonUrlRequest> request = LookupRequest(request_id);
+ if (request) {
+ request->StealMoniker(moniker);
+ request->Stop();
+ }
+ }
+
+ done->Signal();
+}
« no previous file with comments | « chrome_frame/urlmon_url_request.h ('k') | chrome_frame/urlmon_url_request_private.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698