summaryrefslogtreecommitdiffstats
path: root/chrome_frame
diff options
context:
space:
mode:
authorrobertshield@chromium.org <robertshield@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-03 00:21:50 +0000
committerrobertshield@chromium.org <robertshield@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-03 00:21:50 +0000
commitb55aaa67d96309c6dd983d8cf8cfaad723174567 (patch)
treed287c31b6659954ee9e3b3820737fc331e9219d0 /chrome_frame
parentda1620f743c03a11705e8aa21cabcdac93523056 (diff)
downloadchromium_src-b55aaa67d96309c6dd983d8cf8cfaad723174567.zip
chromium_src-b55aaa67d96309c6dd983d8cf8cfaad723174567.tar.gz
chromium_src-b55aaa67d96309c6dd983d8cf8cfaad723174567.tar.bz2
Adding support for Chrome Frame to be loaded via the presence of an X-UA-Compatible HTTP header (in addition to the meta tag support).
Also pins the CF module into the process such that it won't get unloaded. Doing this to work around how we can get unloaded without unpatching properly. BUG=22802 TEST=Navigate to a web site whose server sends the X-UA-Compatible: chrome=1 HTTP header and ensure that the page is loaded in CF. Review URL: http://codereview.chromium.org/465009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@33629 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame')
-rw-r--r--chrome_frame/bho.cc22
-rw-r--r--chrome_frame/http_negotiate.cc101
-rw-r--r--chrome_frame/http_negotiate.h27
-rw-r--r--chrome_frame/urlmon_url_request.cc23
-rw-r--r--chrome_frame/utils.cc25
-rw-r--r--chrome_frame/utils.h5
6 files changed, 180 insertions, 23 deletions
diff --git a/chrome_frame/bho.cc b/chrome_frame/bho.cc
index 9fff456..33396a6 100644
--- a/chrome_frame/bho.cc
+++ b/chrome_frame/bho.cc
@@ -7,7 +7,9 @@
#include <shlguid.h>
#include <shobjidl.h>
+#include "base/file_path.h"
#include "base/logging.h"
+#include "base/path_service.h"
#include "base/registry.h"
#include "base/scoped_bstr_win.h"
#include "base/scoped_comptr_win.h"
@@ -247,12 +249,32 @@ Bho* Bho::GetCurrentThreadBhoInstance() {
return bho_current_thread_instance_.Pointer()->Get();
}
+namespace {
+// Utility function that prevents the current module from ever being unloaded.
+void PinModule() {
+ FilePath module_path;
+ if (PathService::Get(base::FILE_MODULE, &module_path)) {
+ HMODULE unused;
+ if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN,
+ module_path.value().c_str(), &unused)) {
+ NOTREACHED() << "Failed to pin module " << module_path.value().c_str();
+ }
+ } else {
+ NOTREACHED() << "Could not get module path.";
+ }
+}
+} // namespace
+
bool PatchHelper::InitializeAndPatchProtocolsIfNeeded() {
bool ret = false;
_pAtlModule->m_csStaticDataInitAndTypeInfo.Lock();
if (state_ == UNKNOWN) {
+ // If we're going to start patching things, we'd better make sure that we
+ // stick around for ever more:
+ PinModule();
+
HttpNegotiatePatch::Initialize();
bool patch_protocol = GetConfigBool(true, kPatchProtocols);
diff --git a/chrome_frame/http_negotiate.cc b/chrome_frame/http_negotiate.cc
index efffeccc..1ea79e2 100644
--- a/chrome_frame/http_negotiate.cc
+++ b/chrome_frame/http_negotiate.cc
@@ -16,6 +16,16 @@
#include "chrome_frame/utils.h"
#include "chrome_frame/vtable_patch_manager.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_util.h"
+
+const wchar_t kChromeMimeType[] = L"application/chromepage";
+const char kUACompatibleHttpHeader[] = "x-ua-compatible";
+
+// From the latest urlmon.h. TODO(robertshield): Remove this once we update
+// our SDK version.
+static const int BINDSTATUS_SERVER_MIMETYPEAVAILABLE = 54;
+
static const int kHttpNegotiateBeginningTransactionIndex = 3;
static const int kHttpNegotiateOnResponseTransactionIndex = 4;
@@ -26,6 +36,21 @@ BEGIN_VTABLE_PATCHES(IHttpNegotiate)
HttpNegotiatePatch::OnResponse)
END_VTABLE_PATCHES()
+static const int kBindStatusCallbackStartBindingIndex = 3;
+
+BEGIN_VTABLE_PATCHES(IBindStatusCallback)
+ VTABLE_PATCH_ENTRY(kBindStatusCallbackStartBindingIndex,
+ HttpNegotiatePatch::StartBinding)
+END_VTABLE_PATCHES()
+
+static const int kInternetProtocolSinkReportProgressIndex = 4;
+
+BEGIN_VTABLE_PATCHES(IInternetProtocolSink)
+ VTABLE_PATCH_ENTRY(kInternetProtocolSinkReportProgressIndex,
+ HttpNegotiatePatch::ReportProgress)
+END_VTABLE_PATCHES()
+
+
HttpNegotiatePatch::HttpNegotiatePatch() {
}
@@ -85,6 +110,18 @@ HRESULT HttpNegotiatePatch::PatchHttpNegotiate(IUnknown* to_patch) {
<< StringPrintf("IHttpNegotiate not supported 0x%08X", hr);
}
+ ScopedComPtr<IBindStatusCallback> bscb;
+ hr = bscb.QueryFrom(to_patch);
+
+ if (bscb) {
+ hr = vtable_patch::PatchInterfaceMethods(bscb,
+ IBindStatusCallback_PatchInfo);
+ DLOG_IF(ERROR, FAILED(hr))
+ << StringPrintf("BindStatusCallback patch failed 0x%08X", hr);
+ } else {
+ DLOG(WARNING) << StringPrintf("IBindStatusCallback not supported 0x%08X",
+ hr);
+ }
return hr;
}
@@ -162,3 +199,67 @@ HRESULT HttpNegotiatePatch::OnResponse(IHttpNegotiate_OnResponse_Fn original,
additional_request_headers);
return hr;
}
+
+// static
+HRESULT HttpNegotiatePatch::StartBinding(
+ IBindStatusCallback_StartBinding_Fn original,
+ IBindStatusCallback* me, DWORD reserved, IBinding* binding) {
+ ScopedComPtr<IBinding> local_binding(binding);
+ ScopedComPtr<IInternetProtocolSink> protocol_sink;
+
+ HRESULT hr = protocol_sink.QueryFrom(local_binding);
+ if (FAILED(hr) || !protocol_sink) {
+ DLOG(WARNING) << "Failed to get IInternetProtocolSink from IBinding.";
+ } else {
+ if (!IS_PATCHED(IInternetProtocolSink)) {
+ hr = vtable_patch::PatchInterfaceMethods(protocol_sink,
+ IInternetProtocolSink_PatchInfo);
+ }
+
+ DLOG_IF(WARNING, FAILED(hr))
+ << "Failed to patch IInternetProtocolSink from IBinding.";
+ }
+
+ hr = original(me, reserved, binding);
+ return hr;
+}
+
+// static
+HRESULT HttpNegotiatePatch::ReportProgress(
+ IInternetProtocolSink_ReportProgress_Fn original, IInternetProtocolSink* me,
+ ULONG status_code, LPCWSTR status_text) {
+ if (status_code == BINDSTATUS_MIMETYPEAVAILABLE ||
+ status_code == BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE ||
+ status_code == BINDSTATUS_SERVER_MIMETYPEAVAILABLE) {
+ // Check to see if we need to alter the mime type that gets reported
+ // by inspecting the raw header information:
+ ScopedComPtr<IWinInetHttpInfo> win_inet_http_info;
+ HRESULT hr = win_inet_http_info.QueryFrom(me);
+
+ if (FAILED(hr) || !win_inet_http_info) {
+ NOTREACHED() << "Could not get at an IWinInetHttpInfo in "
+ << "IInternetProtocolSink::ReportProgress.";
+ } else {
+ // We have headers: check to see if the server is requesting CF via
+ // the X-UA-Compatible: chrome=1 HTTP header.
+ std::string headers(GetRawHttpHeaders(win_inet_http_info));
+ if (net::HttpUtil::HasHeader(headers, kUACompatibleHttpHeader)) {
+ net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(),
+ "\r\n");
+ while (it.GetNext()) {
+ if (LowerCaseEqualsASCII(it.name_begin(), it.name_end(),
+ kUACompatibleHttpHeader)) {
+ std::string ua_value(StringToLowerASCII(it.values()));
+ if (ua_value.find("chrome=1") != std::string::npos) {
+ status_text = kChromeMimeType;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ HRESULT hr = original(me, status_code, status_text);
+ return hr;
+} \ No newline at end of file
diff --git a/chrome_frame/http_negotiate.h b/chrome_frame/http_negotiate.h
index 4a22d9c..3146539 100644
--- a/chrome_frame/http_negotiate.h
+++ b/chrome_frame/http_negotiate.h
@@ -17,8 +17,24 @@ typedef HRESULT (STDMETHODCALLTYPE* IHttpNegotiate_OnResponse_Fn)(
IHttpNegotiate* me, DWORD response_code, LPCWSTR response_header,
LPCWSTR request_header, LPWSTR* additional_request_headers);
+// Typedefs for IBindStatusCallback methods.
+typedef HRESULT (STDMETHODCALLTYPE* IBindStatusCallback_StartBinding_Fn)(
+ IBindStatusCallback* me, DWORD reserved, IBinding *binding);
+
+// Typedefs for IInternetProtocolSink methods.
+typedef HRESULT (STDMETHODCALLTYPE* IInternetProtocolSink_ReportProgress_Fn)(
+ IInternetProtocolSink* me, ULONG status_code, LPCWSTR status_text);
+
// Patches methods of urlmon's IHttpNegotiate implementation for the purposes
// of adding to the http user agent header.
+
+// Also patches one of the IBindStatusCallback implementations in urlmon to pick
+// up an IBinding during the StartBinding call. The IBinding implementor then
+// gets a patch applied to its IInternetProtocolSink's ReportProgress method.
+// The patched is there so that the reporting of the MIME type to the IBinding
+// implementor can be changed if an X-Chrome-Frame HTTP header is present
+// in the response headers. If anyone can suggest a more straightforward way of
+// doing this, I would be eternally grateful.
class HttpNegotiatePatch {
// class is not to be instantiated atm.
HttpNegotiatePatch();
@@ -28,15 +44,24 @@ class HttpNegotiatePatch {
static bool Initialize();
static void Uninitialize();
+ // IHttpNegotiate patch methods
static STDMETHODIMP BeginningTransaction(
IHttpNegotiate_BeginningTransaction_Fn original, IHttpNegotiate* me,
LPCWSTR url, LPCWSTR headers, DWORD reserved, LPWSTR* additional_headers);
-
static STDMETHODIMP OnResponse(
IHttpNegotiate_OnResponse_Fn original, IHttpNegotiate* me,
DWORD response_code, LPCWSTR response_header, LPCWSTR request_header,
LPWSTR* additional_request_headers);
+ // IBindStatusCallback patch methods
+ static STDMETHODIMP StartBinding(IBindStatusCallback_StartBinding_Fn original,
+ IBindStatusCallback* me, DWORD reserved, IBinding *binding);
+
+ // IInternetProtocolSink patch methods
+ static STDMETHODIMP ReportProgress(
+ IInternetProtocolSink_ReportProgress_Fn original,
+ IInternetProtocolSink* me, ULONG status_code, LPCWSTR status_text);
+
protected:
static HRESULT PatchHttpNegotiate(IUnknown* to_patch);
diff --git a/chrome_frame/urlmon_url_request.cc b/chrome_frame/urlmon_url_request.cc
index b2588ab..66aacd6 100644
--- a/chrome_frame/urlmon_url_request.cc
+++ b/chrome_frame/urlmon_url_request.cc
@@ -773,28 +773,7 @@ std::string UrlmonUrlRequest::GetHttpHeaders() const {
return std::string();
}
- scoped_ptr<char> buffer;
- DWORD size = 0;
- DWORD flags = 0;
- DWORD reserved = 0;
- HRESULT hr = info->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF, NULL, &size,
- &flags, &reserved);
- if (!size) {
- DLOG(WARNING) << "Failed to query HTTP headers size. Error 0x%x" << hr;
- return std::string();
- }
-
- buffer.reset(new char[size]);
- memset(buffer.get(), 0, size);
-
- hr = info->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF, buffer.get(),
- &size, &flags, &reserved);
- if (FAILED(hr)) {
- DLOG(WARNING) << "Failed to query HTTP headers. Error 0x%x" << hr;
- return std::string();
- }
-
- return buffer.get();
+ return GetRawHttpHeaders(info);
}
void UrlmonUrlRequest::ReleaseBindings() {
diff --git a/chrome_frame/utils.cc b/chrome_frame/utils.cc
index 61bf7df..10bf92a 100644
--- a/chrome_frame/utils.cc
+++ b/chrome_frame/utils.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include <shlobj.h>
+#include <wininet.h>
#include "chrome_frame/html_utils.h"
#include "chrome_frame/utils.h"
@@ -610,3 +611,27 @@ bool IsValidUrlScheme(const std::wstring& url, bool is_privileged) {
return false;
}
+
+std::string GetRawHttpHeaders(IWinInetHttpInfo* info) {
+ DCHECK(info);
+
+ std::string buffer;
+
+ DWORD size = 0;
+ DWORD flags = 0;
+ DWORD reserved = 0;
+ HRESULT hr = info->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF, NULL, &size,
+ &flags, &reserved);
+ if (!size) {
+ DLOG(WARNING) << "Failed to query HTTP headers size. Error: " << hr;
+ } else {
+ buffer.resize(size + 1);
+ hr = info->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF, &buffer[0],
+ &size, &flags, &reserved);
+ if (FAILED(hr)) {
+ DLOG(WARNING) << "Failed to query HTTP headers. Error: " << hr;
+ }
+ }
+
+ return buffer;
+}
diff --git a/chrome_frame/utils.h b/chrome_frame/utils.h
index 717ee4f..351fba1 100644
--- a/chrome_frame/utils.h
+++ b/chrome_frame/utils.h
@@ -7,6 +7,7 @@
#include <atlbase.h>
#include <string>
+#include <UrlMon.h>
#include "base/basictypes.h"
#include "base/logging.h"
@@ -206,6 +207,10 @@ HRESULT GetUrlFromMoniker(IMoniker* moniker, IBindCtx* bind_context,
// When is_privileged is true, chrome extension URLs will be considered valid.
bool IsValidUrlScheme(const std::wstring& url, bool is_privileged);
+// Returns the raw http headers for the current request given an
+// IWinInetHttpInfo pointer.
+std::string GetRawHttpHeaders(IWinInetHttpInfo* info);
+
// See COM_INTERFACE_BLIND_DELEGATE below for details.
template <class T>
STDMETHODIMP CheckOutgoingInterface(void* obj, REFIID iid, void** ret,