summaryrefslogtreecommitdiffstats
path: root/chrome_frame/urlmon_url_request.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome_frame/urlmon_url_request.cc')
-rw-r--r--chrome_frame/urlmon_url_request.cc219
1 files changed, 217 insertions, 2 deletions
diff --git a/chrome_frame/urlmon_url_request.cc b/chrome_frame/urlmon_url_request.cc
index 5970b63..b98ba53 100644
--- a/chrome_frame/urlmon_url_request.cc
+++ b/chrome_frame/urlmon_url_request.cc
@@ -5,6 +5,7 @@
#include "chrome_frame/urlmon_url_request.h"
#include <wininet.h>
+#include <urlmon.h>
#include "base/scoped_ptr.h"
#include "base/string_util.h"
@@ -22,6 +23,203 @@ 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
+// the UI thread and hence cannot be used as is on the worker thread which
+// handles URL requests. We unmarshal the IBindCtx interface and invoke
+// the corresponding method on the unmarshaled object. The object implementing
+// the IBindCtx interface also implements IMarshal. However it seems to have a
+// bug where in subsequent download requests for the same URL fail. We work
+// around this issue by using the standard marshaler instead.
+class WrappedBindContext : public IBindCtx,
+ public CComObjectRootEx<CComMultiThreadModel> {
+ public:
+ WrappedBindContext() {
+ DLOG(INFO) << "In " << __FUNCTION__;
+ }
+
+ ~WrappedBindContext() {
+ DLOG(INFO) << "In " << __FUNCTION__ << " : Destroying object: " << this;
+ }
+
+ BEGIN_COM_MAP(WrappedBindContext)
+ COM_INTERFACE_ENTRY(IBindCtx)
+ COM_INTERFACE_ENTRY_IID(IID_IAsyncBindCtx, WrappedBindContext)
+ COM_INTERFACE_ENTRY(IUnknown)
+ END_COM_MAP()
+
+ HRESULT Initialize(IBindCtx* context) {
+ DCHECK(context != NULL);
+ HRESULT hr = CoGetStandardMarshal(__uuidof(IBindCtx),
+ context,
+ MSHCTX_INPROC,
+ NULL,
+ MSHLFLAGS_NORMAL,
+ standard_marshal_.Receive());
+ if (FAILED(hr)) {
+ NOTREACHED() << __FUNCTION__
+ << ": CoGetStandardMarshal failed. Error:"
+ << hr;
+ return hr;
+ }
+
+ DCHECK(standard_marshal_.get() != NULL);
+ DCHECK(marshaled_stream_.get() == NULL);
+
+ CreateStreamOnHGlobal(NULL, TRUE, marshaled_stream_.Receive());
+ DCHECK(marshaled_stream_.get() != NULL);
+
+ hr = standard_marshal_->MarshalInterface(marshaled_stream_,
+ __uuidof(IBindCtx),
+ context,
+ MSHCTX_INPROC,
+ NULL,
+ MSHLFLAGS_NORMAL);
+ if (FAILED(hr)) {
+ NOTREACHED() << __FUNCTION__
+ << ": MarshalInterface failed. Error:"
+ << hr;
+ }
+ return hr;
+ }
+
+ STDMETHOD(RegisterObjectBound)(IUnknown* object) {
+ DLOG(INFO) << "In " << __FUNCTION__ << " for object: " << this;
+
+ ScopedComPtr<IBindCtx> bind_context;
+ HRESULT hr = GetMarshalledBindContext(bind_context.Receive());
+ if (bind_context.get()) {
+ hr = bind_context->RegisterObjectBound(object);
+ }
+ return hr;
+ }
+
+ STDMETHOD(RevokeObjectBound)(IUnknown* object) {
+ DLOG(INFO) << "In " << __FUNCTION__ << " for object: " << this;
+
+ ScopedComPtr<IBindCtx> bind_context;
+ HRESULT hr = GetMarshalledBindContext(bind_context.Receive());
+ if (bind_context.get()) {
+ hr = bind_context->RevokeObjectBound(object);
+ }
+ return hr;
+ }
+
+ STDMETHOD(ReleaseBoundObjects)() {
+ DLOG(INFO) << "In " << __FUNCTION__ << " for object: " << this;
+
+ ScopedComPtr<IBindCtx> bind_context;
+ HRESULT hr = GetMarshalledBindContext(bind_context.Receive());
+ if (bind_context.get()) {
+ hr = bind_context->ReleaseBoundObjects();
+ }
+ return hr;
+ }
+
+ STDMETHOD(SetBindOptions)(BIND_OPTS* bind_options) {
+ DLOG(INFO) << "In " << __FUNCTION__ << " for object: " << this;
+
+ ScopedComPtr<IBindCtx> bind_context;
+ HRESULT hr = GetMarshalledBindContext(bind_context.Receive());
+ if (bind_context.get()) {
+ hr = bind_context->SetBindOptions(bind_options);
+ }
+ return hr;
+ }
+
+ STDMETHOD(GetBindOptions)(BIND_OPTS* bind_options) {
+ DLOG(INFO) << "In " << __FUNCTION__ << " for object: " << this;
+
+ ScopedComPtr<IBindCtx> bind_context;
+ HRESULT hr = GetMarshalledBindContext(bind_context.Receive());
+ if (bind_context.get()) {
+ hr = bind_context->GetBindOptions(bind_options);
+ }
+ return hr;
+ }
+
+ STDMETHOD(GetRunningObjectTable)(IRunningObjectTable** table) {
+ DLOG(INFO) << "In " << __FUNCTION__ << " for object: " << this;
+
+ ScopedComPtr<IBindCtx> bind_context;
+ HRESULT hr = GetMarshalledBindContext(bind_context.Receive());
+ if (bind_context.get()) {
+ hr = bind_context->GetRunningObjectTable(table);
+ }
+ return hr;
+ }
+
+ STDMETHOD(RegisterObjectParam)(LPOLESTR key, IUnknown* object) {
+ DLOG(INFO) << "In " << __FUNCTION__ << " for object: " << this;
+
+ ScopedComPtr<IBindCtx> bind_context;
+ HRESULT hr = GetMarshalledBindContext(bind_context.Receive());
+ if (bind_context.get()) {
+ hr = bind_context->RegisterObjectParam(key, object);
+ }
+ return hr;
+ }
+
+ STDMETHOD(GetObjectParam)(LPOLESTR key, IUnknown** object) {
+ DLOG(INFO) << "In " << __FUNCTION__ << " for object: " << this;
+
+ ScopedComPtr<IBindCtx> bind_context;
+ HRESULT hr = GetMarshalledBindContext(bind_context.Receive());
+ if (bind_context.get()) {
+ hr = bind_context->GetObjectParam(key, object);
+ }
+ return hr;
+ }
+
+ STDMETHOD(EnumObjectParam)(IEnumString** enum_string) {
+ DLOG(INFO) << "In " << __FUNCTION__ << " for object: " << this;
+
+ ScopedComPtr<IBindCtx> bind_context;
+ HRESULT hr = GetMarshalledBindContext(bind_context.Receive());
+ if (bind_context.get()) {
+ hr = bind_context->EnumObjectParam(enum_string);
+ }
+ return hr;
+ }
+
+ STDMETHOD(RevokeObjectParam)(LPOLESTR key) {
+ DLOG(INFO) << "In " << __FUNCTION__ << " for object: " << this;
+
+ ScopedComPtr<IBindCtx> bind_context;
+ HRESULT hr = GetMarshalledBindContext(bind_context.Receive());
+ if (bind_context.get()) {
+ hr = bind_context->RevokeObjectParam(key);
+ }
+ return hr;
+ }
+
+ private:
+ HRESULT GetMarshalledBindContext(IBindCtx** bind_context) {
+ DCHECK(bind_context != NULL);
+ DCHECK(standard_marshal_.get() != NULL);
+
+ if (!marshalled_bind_context_.get()) {
+ LARGE_INTEGER offset = {0};
+ marshaled_stream_->Seek(offset, STREAM_SEEK_SET, NULL);
+ HRESULT hr = standard_marshal_->UnmarshalInterface(
+ marshaled_stream_, __uuidof(IBindCtx),
+ reinterpret_cast<void**>(marshalled_bind_context_.Receive()));
+ if (FAILED(hr)) {
+ NOTREACHED() << __FUNCTION__
+ << "UnmarshalInterface failed. Error:"
+ << hr;
+ return hr;
+ }
+ DCHECK(marshalled_bind_context_.get() != NULL);
+ }
+ return marshalled_bind_context_.QueryInterface(bind_context);
+ }
+
+ ScopedComPtr<IStream> marshaled_stream_;
+ ScopedComPtr<IBindCtx> marshalled_bind_context_;
+ ScopedComPtr<IMarshal> standard_marshal_;
+};
+
UrlmonUrlRequest::UrlmonUrlRequest()
: pending_read_size_(0),
status_(URLRequestStatus::FAILED, net::ERR_FAILED),
@@ -361,7 +559,7 @@ STDMETHODIMP UrlmonUrlRequest::OnDataAvailable(DWORD flags, DWORD size,
return S_OK;
}
-STDMETHODIMP UrlmonUrlRequest::OnObjectAvailable(REFIID iid, IUnknown *object) {
+STDMETHODIMP UrlmonUrlRequest::OnObjectAvailable(REFIID iid, IUnknown* object) {
// We are calling BindToStorage on the moniker we should always get called
// back on OnDataAvailable and should never get OnObjectAvailable
NOTREACHED();
@@ -614,8 +812,25 @@ HRESULT UrlmonUrlRequest::ConnectToExistingMoniker(IMoniker* moniker,
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;
- bind_context_ = context;
set_url(WideToUTF8(url));
return S_OK;
}