Index: chrome_frame/protocol_sink_wrap.cc |
=================================================================== |
--- chrome_frame/protocol_sink_wrap.cc (revision 53833) |
+++ chrome_frame/protocol_sink_wrap.cc (working copy) |
@@ -13,6 +13,7 @@ |
#include "base/singleton.h" |
#include "base/string_util.h" |
+#include "chrome_frame/bho.h" |
#include "chrome_frame/bind_context_info.h" |
#include "chrome_frame/function_stub.h" |
#include "chrome_frame/utils.h" |
@@ -30,6 +31,8 @@ |
static const int kInternetProtocolStartIndex = 3; |
static const int kInternetProtocolReadIndex = 9; |
static const int kInternetProtocolStartExIndex = 13; |
+static const int kInternetProtocolLockRequestIndex = 11; |
+static const int kInternetProtocolUnlockRequestIndex = 12; |
// IInternetProtocol/Ex patches. |
@@ -55,10 +58,18 @@ |
ULONG size, |
ULONG* size_read); |
+STDMETHODIMP Hook_LockRequest(InternetProtocol_LockRequest_Fn orig_req, |
+ IInternetProtocol* protocol, DWORD dwOptions); |
+ |
+STDMETHODIMP Hook_UnlockRequest(InternetProtocol_UnlockRequest_Fn orig_req, |
+ IInternetProtocol* protocol); |
+ |
///////////////////////////////////////////////////////////////////////////// |
BEGIN_VTABLE_PATCHES(CTransaction) |
VTABLE_PATCH_ENTRY(kInternetProtocolStartIndex, Hook_Start) |
VTABLE_PATCH_ENTRY(kInternetProtocolReadIndex, Hook_Read) |
+ VTABLE_PATCH_ENTRY(kInternetProtocolLockRequestIndex, Hook_LockRequest) |
+ VTABLE_PATCH_ENTRY(kInternetProtocolUnlockRequestIndex, Hook_UnlockRequest) |
END_VTABLE_PATCHES() |
BEGIN_VTABLE_PATCHES(CTransaction2) |
@@ -502,7 +513,6 @@ |
DCHECK_EQ(CHROME, renderer_type_); |
ScopedComPtr<IWinInetHttpInfo> info; |
info.QueryFrom(delegate); |
- DCHECK(info); |
if (info) { |
char buffer[4096] = {0}; |
DWORD len = sizeof(buffer); |
@@ -512,6 +522,8 @@ |
buffer, &len, &flags, 0); |
if (hr == S_OK && len > 0) |
referrer_.assign(buffer); |
+ } else { |
+ DLOG(WARNING) << "Failed to QI for IWinInetHttpInfo"; |
} |
} |
@@ -525,6 +537,38 @@ |
return instance; |
} |
+// This function looks for the url pattern indicating that this request needs |
+// to be forced into chrome frame. |
+// This hack is required because window.open requests from Chrome don't have |
+// the URL up front. The URL comes in much later when the renderer initiates a |
+// top level navigation for the url passed into window.open. |
+// The new page must be rendered in ChromeFrame to preserve the opener |
+// relationship with its parent even if the new page does not have the chrome |
+// meta tag. |
+bool HandleAttachToExistingExternalTab(LPCWSTR url, |
+ IInternetProtocol* protocol, |
+ IInternetProtocolSink* prot_sink, |
+ IBindCtx* bind_ctx) { |
+ if (MatchPatternWide(url, kChromeFrameAttachTabPattern)) { |
+ scoped_refptr<ProtData> prot_data = ProtData::DataFromProtocol(protocol); |
+ if (!prot_data) { |
+ // Pass NULL as the read function which indicates that always return EOF |
+ // without calling the underlying protocol. |
+ prot_data = new ProtData(protocol, NULL, url); |
+ PutProtData(bind_ctx, prot_data); |
+ } |
+ |
+ prot_sink->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, kChromeMimeType); |
+ |
+ int data_flags = BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION; |
+ prot_sink->ReportData(data_flags, 0, 0); |
+ |
+ prot_sink->ReportResult(S_OK, 0, NULL); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
// IInternetProtocol/Ex hooks. |
STDMETHODIMP Hook_Start(InternetProtocol_Start_Fn orig_start, |
IInternetProtocol* protocol, LPCWSTR url, IInternetProtocolSink* prot_sink, |
@@ -542,6 +586,10 @@ |
return orig_start(protocol, url, prot_sink, bind_info, flags, reserved); |
} |
+ if (HandleAttachToExistingExternalTab(url, protocol, prot_sink, bind_ctx)) { |
+ return S_OK; |
+ } |
+ |
if (IsCFRequest(bind_ctx)) { |
return orig_start(protocol, url, prot_sink, bind_info, flags, reserved); |
} |
@@ -589,6 +637,10 @@ |
return orig_start_ex(protocol, uri, prot_sink, bind_info, flags, reserved); |
} |
+ if (HandleAttachToExistingExternalTab(url, protocol, prot_sink, bind_ctx)) { |
+ return S_OK; |
+ } |
+ |
if (IsCFRequest(bind_ctx)) { |
return orig_start_ex(protocol, uri, prot_sink, bind_info, flags, reserved); |
} |
@@ -620,15 +672,51 @@ |
STDMETHODIMP Hook_Read(InternetProtocol_Read_Fn orig_read, |
IInternetProtocol* protocol, void* buffer, ULONG size, ULONG* size_read) { |
DCHECK(orig_read); |
+ HRESULT hr = E_FAIL; |
+ |
scoped_refptr<ProtData> prot_data = ProtData::DataFromProtocol(protocol); |
if (!prot_data) { |
- return orig_read(protocol, buffer, size, size_read); |
+ hr = orig_read(protocol, buffer, size, size_read); |
+ return hr; |
} |
- HRESULT hr = prot_data->Read(buffer, size, size_read); |
+ if (prot_data->is_attach_external_tab_request()) { |
+ // return EOF always. |
+ if (size_read) |
+ *size_read = 0; |
+ return S_FALSE; |
+ } |
+ |
+ hr = prot_data->Read(buffer, size, size_read); |
return hr; |
} |
+STDMETHODIMP Hook_LockRequest(InternetProtocol_LockRequest_Fn orig_req, |
+ IInternetProtocol* protocol, DWORD options) { |
+ DCHECK(orig_req); |
+ |
+ scoped_refptr<ProtData> prot_data = ProtData::DataFromProtocol(protocol); |
+ if (prot_data && prot_data->is_attach_external_tab_request()) { |
+ prot_data->AddRef(); |
+ return S_OK; |
+ } |
+ |
+ return orig_req(protocol, options); |
+} |
+ |
+STDMETHODIMP Hook_UnlockRequest(InternetProtocol_UnlockRequest_Fn orig_req, |
+ IInternetProtocol* protocol) { |
+ DCHECK(orig_req); |
+ |
+ scoped_refptr<ProtData> prot_data = ProtData::DataFromProtocol(protocol); |
+ if (prot_data && prot_data->is_attach_external_tab_request()) { |
+ prot_data->Release(); |
+ return S_OK; |
+ } |
+ |
+ return orig_req(protocol); |
+} |
+ |
// Patching / Hooking code. |
class FakeProtocol : public CComObjectRootEx<CComSingleThreadModel>, |
public IInternetProtocol { |