summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome_frame/bho.cc5
-rw-r--r--chrome_frame/chrome_frame_automation.cc9
-rw-r--r--chrome_frame/chrome_tab.cc36
-rw-r--r--chrome_frame/http_negotiate.cc129
-rw-r--r--chrome_frame/http_negotiate.h47
-rw-r--r--chrome_frame/test/http_negotiate_unittest.cc106
-rw-r--r--chrome_frame/test/navigation_test.cc82
-rw-r--r--chrome_frame/utils.cc7
-rw-r--r--chrome_frame/utils.h3
9 files changed, 116 insertions, 308 deletions
diff --git a/chrome_frame/bho.cc b/chrome_frame/bho.cc
index 35623b3..7fbc473 100644
--- a/chrome_frame/bho.cc
+++ b/chrome_frame/bho.cc
@@ -319,7 +319,6 @@ bool PatchHelper::InitializeAndPatchProtocolsIfNeeded() {
if (state_ == UNKNOWN) {
g_trans_hooks.InstallHooks();
- HttpNegotiatePatch::Initialize();
state_ = PATCH_PROTOCOL;
ret = true;
}
@@ -343,10 +342,6 @@ void PatchHelper::UnpatchIfNeeded() {
} else if (state_ == PATCH_IBROWSER) {
vtable_patch::UnpatchInterfaceMethods(IBrowserService_PatchInfo);
MonikerPatch::Uninitialize();
- HttpNegotiatePatch::Uninitialize();
- } else {
- HttpNegotiatePatch::Uninitialize();
}
-
state_ = UNKNOWN;
}
diff --git a/chrome_frame/chrome_frame_automation.cc b/chrome_frame/chrome_frame_automation.cc
index e0cab31..b25b89d 100644
--- a/chrome_frame/chrome_frame_automation.cc
+++ b/chrome_frame/chrome_frame_automation.cc
@@ -46,15 +46,6 @@ static const wchar_t kUmaSendIntervalValue[] = L"UmaSendInterval";
// threads.
Lock g_ChromeFrameHistogramLock;
-namespace {
-std::wstring GetCurrentModuleVersion() {
- scoped_ptr<FileVersionInfo> module_version_info(
- FileVersionInfo::CreateFileVersionInfoForCurrentModule());
- DCHECK(module_version_info.get() != NULL);
- return module_version_info->file_version();
-}
-}
-
class ChromeFrameAutomationProxyImpl::TabProxyNotificationMessageFilter
: public IPC::ChannelProxy::MessageFilter {
public:
diff --git a/chrome_frame/chrome_tab.cc b/chrome_frame/chrome_tab.cc
index f3f4bd1..79c846d 100644
--- a/chrome_frame/chrome_tab.cc
+++ b/chrome_frame/chrome_tab.cc
@@ -417,6 +417,35 @@ STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) {
return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
}
+const wchar_t kPostPlatformUAKey[] =
+ L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\"
+ L"User Agent\\Post Platform";
+const wchar_t kChromeFramePrefix[] = L"chromeframe/";
+
+// To delete the user agent, set value to NULL.
+// The is_system parameter indicates whether this is a per machine or a per
+// user installation.
+HRESULT SetChromeFrameUA(bool is_system, const wchar_t* value) {
+ HRESULT hr = E_FAIL;
+ HKEY parent_hive = is_system ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+
+ RegKey ua_key;
+ if (ua_key.Create(parent_hive, kPostPlatformUAKey, KEY_WRITE)) {
+ std::wstring chrome_frame_ua_value_name = kChromeFramePrefix;
+ chrome_frame_ua_value_name += GetCurrentModuleVersion();
+ if (value) {
+ ua_key.WriteValue(chrome_frame_ua_value_name.c_str(), value);
+ } else {
+ ua_key.DeleteValue(chrome_frame_ua_value_name.c_str());
+ }
+ hr = S_OK;
+ } else {
+ DLOG(ERROR) << __FUNCTION__ << ": " << kPostPlatformUAKey;
+ hr = E_UNEXPECTED;
+ }
+ return hr;
+}
+
enum RegistrationFlags {
ACTIVEX = 0x0001,
ACTIVEDOC = 0x0002,
@@ -500,6 +529,13 @@ STDAPI CustomRegistration(UINT reg_flags, BOOL reg, bool is_system) {
hr = _AtlModule.UpdateRegistryAppId(reg);
}
+ if (hr == S_OK) {
+ if (reg) {
+ hr = SetChromeFrameUA(is_system, L"1");
+ } else {
+ hr = SetChromeFrameUA(is_system, NULL);
+ }
+ }
return hr;
}
diff --git a/chrome_frame/http_negotiate.cc b/chrome_frame/http_negotiate.cc
index b593f28..85701c3 100644
--- a/chrome_frame/http_negotiate.cc
+++ b/chrome_frame/http_negotiate.cc
@@ -32,56 +32,6 @@ const char kLowerCaseUserAgent[] = "user-agent";
// TODO(robertshield): Remove this once we update our SDK version.
const int LOCAL_BINDSTATUS_SERVER_MIMETYPEAVAILABLE = 54;
-static const int kHttpNegotiateBeginningTransactionIndex = 3;
-
-BEGIN_VTABLE_PATCHES(IHttpNegotiate)
- VTABLE_PATCH_ENTRY(kHttpNegotiateBeginningTransactionIndex,
- HttpNegotiatePatch::BeginningTransaction)
-END_VTABLE_PATCHES()
-
-namespace {
-
-class SimpleBindStatusCallback : public CComObjectRootEx<CComSingleThreadModel>,
- public IBindStatusCallback {
- public:
- BEGIN_COM_MAP(SimpleBindStatusCallback)
- COM_INTERFACE_ENTRY(IBindStatusCallback)
- END_COM_MAP()
-
- // IBindStatusCallback implementation
- STDMETHOD(OnStartBinding)(DWORD reserved, IBinding* binding) {
- return E_NOTIMPL;
- }
-
- STDMETHOD(GetPriority)(LONG* priority) {
- return E_NOTIMPL;
- }
- STDMETHOD(OnLowResource)(DWORD reserved) {
- return E_NOTIMPL;
- }
-
- STDMETHOD(OnProgress)(ULONG progress, ULONG max_progress,
- ULONG status_code, LPCWSTR status_text) {
- return E_NOTIMPL;
- }
- STDMETHOD(OnStopBinding)(HRESULT result, LPCWSTR error) {
- return E_NOTIMPL;
- }
-
- STDMETHOD(GetBindInfo)(DWORD* bind_flags, BINDINFO* bind_info) {
- return E_NOTIMPL;
- }
-
- STDMETHOD(OnDataAvailable)(DWORD flags, DWORD size, FORMATETC* formatetc,
- STGMEDIUM* storage) {
- return E_NOTIMPL;
- }
- STDMETHOD(OnObjectAvailable)(REFIID iid, IUnknown* object) {
- return E_NOTIMPL;
- }
-};
-} // end namespace
-
std::string AppendCFUserAgentString(LPCWSTR headers,
LPCWSTR additional_headers) {
using net::HttpUtil;
@@ -157,82 +107,3 @@ std::string ReplaceOrAddUserAgent(LPCWSTR headers,
return new_headers;
}
-HttpNegotiatePatch::HttpNegotiatePatch() {
-}
-
-HttpNegotiatePatch::~HttpNegotiatePatch() {
-}
-
-// static
-bool HttpNegotiatePatch::Initialize() {
- if (IS_PATCHED(IHttpNegotiate)) {
- DLOG(WARNING) << __FUNCTION__ << " called more than once.";
- return true;
- }
- // Use our SimpleBindStatusCallback class as we need a temporary object that
- // implements IBindStatusCallback.
- CComObjectStackEx<SimpleBindStatusCallback> request;
- ScopedComPtr<IBindCtx> bind_ctx;
- HRESULT hr = CreateAsyncBindCtx(0, &request, NULL, bind_ctx.Receive());
- DCHECK(SUCCEEDED(hr)) << "CreateAsyncBindCtx";
- if (bind_ctx) {
- ScopedComPtr<IUnknown> bscb_holder;
- bind_ctx->GetObjectParam(L"_BSCB_Holder_", bscb_holder.Receive());
- if (bscb_holder) {
- hr = PatchHttpNegotiate(bscb_holder);
- } else {
- NOTREACHED() << "Failed to get _BSCB_Holder_";
- hr = E_UNEXPECTED;
- }
- bind_ctx.Release();
- }
-
- return SUCCEEDED(hr);
-}
-
-// static
-void HttpNegotiatePatch::Uninitialize() {
- vtable_patch::UnpatchInterfaceMethods(IHttpNegotiate_PatchInfo);
-}
-
-// static
-HRESULT HttpNegotiatePatch::PatchHttpNegotiate(IUnknown* to_patch) {
- DCHECK(to_patch);
- DCHECK_IS_NOT_PATCHED(IHttpNegotiate);
-
- ScopedComPtr<IHttpNegotiate> http;
- HRESULT hr = http.QueryFrom(to_patch);
- if (FAILED(hr)) {
- hr = DoQueryService(IID_IHttpNegotiate, to_patch, http.Receive());
- }
-
- if (http) {
- hr = vtable_patch::PatchInterfaceMethods(http, IHttpNegotiate_PatchInfo);
- DLOG_IF(ERROR, FAILED(hr))
- << base::StringPrintf("HttpNegotiate patch failed 0x%08X", hr);
- } else {
- DLOG(WARNING)
- << base::StringPrintf("IHttpNegotiate not supported 0x%08X", hr);
- }
- return hr;
-}
-
-// static
-HRESULT HttpNegotiatePatch::BeginningTransaction(
- IHttpNegotiate_BeginningTransaction_Fn original, IHttpNegotiate* me,
- LPCWSTR url, LPCWSTR headers, DWORD reserved, LPWSTR* additional_headers) {
- DVLOG(1) << __FUNCTION__ << " " << url << " headers:\n" << headers;
-
- HRESULT hr = original(me, url, headers, reserved, additional_headers);
-
- if (FAILED(hr)) {
- DLOG(WARNING) << __FUNCTION__ << " Delegate returned an error";
- return hr;
- }
- std::string updated(AppendCFUserAgentString(headers, *additional_headers));
- *additional_headers = reinterpret_cast<wchar_t*>(::CoTaskMemRealloc(
- *additional_headers, (updated.length() + 1) * sizeof(wchar_t)));
- lstrcpyW(*additional_headers, ASCIIToWide(updated).c_str());
- return S_OK;
-}
-
diff --git a/chrome_frame/http_negotiate.h b/chrome_frame/http_negotiate.h
index eb17c7f..151ad23 100644
--- a/chrome_frame/http_negotiate.h
+++ b/chrome_frame/http_negotiate.h
@@ -12,53 +12,6 @@
#include "base/basictypes.h"
#include "base/scoped_comptr_win.h"
-// Typedefs for IHttpNegotiate methods.
-typedef HRESULT (STDMETHODCALLTYPE* IHttpNegotiate_BeginningTransaction_Fn)(
- IHttpNegotiate* me, LPCWSTR url, LPCWSTR headers, DWORD reserved,
- LPWSTR* additional_headers);
-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();
- ~HttpNegotiatePatch();
-
- public:
- 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);
-
- protected:
- static HRESULT PatchHttpNegotiate(IUnknown* to_patch);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(HttpNegotiatePatch);
-};
-
// From the latest urlmon.h. Symbol name prepended with LOCAL_ to
// avoid conflict (and therefore build errors) for those building with
// a newer Windows SDK.
diff --git a/chrome_frame/test/http_negotiate_unittest.cc b/chrome_frame/test/http_negotiate_unittest.cc
index c56034b..857197e 100644
--- a/chrome_frame/test/http_negotiate_unittest.cc
+++ b/chrome_frame/test/http_negotiate_unittest.cc
@@ -16,112 +16,6 @@
#include "gtest/gtest.h"
#include "gmock/gmock.h"
-class HttpNegotiateTest : public testing::Test {
- protected:
- HttpNegotiateTest() {
- }
-};
-
-class TestHttpNegotiate
- : public CComObjectRootEx<CComMultiThreadModel>,
- public IHttpNegotiate {
- public:
- TestHttpNegotiate()
- : beginning_transaction_ret_(S_OK), additional_headers_(NULL) {
- }
-
-BEGIN_COM_MAP(TestHttpNegotiate)
- COM_INTERFACE_ENTRY(IHttpNegotiate)
-END_COM_MAP()
- STDMETHOD(BeginningTransaction)(LPCWSTR url, LPCWSTR headers, // NOLINT
- DWORD reserved, // NOLINT
- LPWSTR* additional_headers) { // NOLINT
- if (additional_headers_) {
- int len = lstrlenW(additional_headers_);
- len++;
- *additional_headers = reinterpret_cast<wchar_t*>(
- ::CoTaskMemAlloc(len * sizeof(wchar_t)));
- lstrcpyW(*additional_headers, additional_headers_);
- }
- return beginning_transaction_ret_;
- }
-
- STDMETHOD(OnResponse)(DWORD response_code, LPCWSTR response_header,
- LPCWSTR request_header,
- LPWSTR* additional_request_headers) {
- return S_OK;
- }
-
- HRESULT beginning_transaction_ret_;
- const wchar_t* additional_headers_;
-};
-
-TEST_F(HttpNegotiateTest, BeginningTransaction) {
- static const int kBeginningTransactionIndex = 3;
- CComObjectStackEx<TestHttpNegotiate> test_http;
- IHttpNegotiate_BeginningTransaction_Fn original =
- reinterpret_cast<IHttpNegotiate_BeginningTransaction_Fn>(
- (*reinterpret_cast<void***>(
- static_cast<IHttpNegotiate*>(
- &test_http)))[kBeginningTransactionIndex]);
-
- std::wstring cf_ua(
- ASCIIToWide(http_utils::GetDefaultUserAgentHeaderWithCFTag()));
- std::wstring cf_tag(
- ASCIIToWide(http_utils::GetChromeFrameUserAgent()));
-
- EXPECT_NE(std::wstring::npos, cf_ua.find(cf_tag));
-
- struct TestCase {
- const std::wstring original_headers_;
- const std::wstring delegate_additional_;
- const std::wstring expected_additional_;
- HRESULT delegate_return_value_;
- } test_cases[] = {
- { L"Accept: */*\r\n",
- L"",
- cf_ua + L"\r\n",
- S_OK },
- { L"Accept: */*\r\n",
- L"",
- L"",
- E_OUTOFMEMORY },
- { L"",
- L"Accept: */*\r\n",
- L"Accept: */*\r\n" + cf_ua + L"\r\n",
- S_OK },
- { L"User-Agent: Bingo/1.0\r\n",
- L"",
- L"User-Agent: Bingo/1.0 " + cf_tag + L"\r\n",
- S_OK },
- { L"User-Agent: NotMe/1.0\r\n",
- L"User-Agent: MeMeMe/1.0\r\n",
- L"User-Agent: MeMeMe/1.0 " + cf_tag + L"\r\n",
- S_OK },
- { L"",
- L"User-Agent: MeMeMe/1.0\r\n",
- L"User-Agent: MeMeMe/1.0 " + cf_tag + L"\r\n",
- S_OK },
- };
-
- for (int i = 0; i < arraysize(test_cases); ++i) {
- TestCase& test = test_cases[i];
- wchar_t* additional = NULL;
- test_http.beginning_transaction_ret_ = test.delegate_return_value_;
- test_http.additional_headers_ = test.delegate_additional_.c_str();
- HttpNegotiatePatch::BeginningTransaction(original, &test_http,
- L"http://www.google.com", test.original_headers_.c_str(), 0,
- &additional);
- EXPECT_TRUE(additional != NULL);
-
- if (additional) {
- // Check against the expected additional headers.
- EXPECT_EQ(test.expected_additional_, std::wstring(additional));
- ::CoTaskMemFree(additional);
- }
- }
-}
-
class TestInternetProtocolSink
: public CComObjectRootEx<CComMultiThreadModel>,
public IInternetProtocolSink {
diff --git a/chrome_frame/test/navigation_test.cc b/chrome_frame/test/navigation_test.cc
index 457793d..7e157ee 100644
--- a/chrome_frame/test/navigation_test.cc
+++ b/chrome_frame/test/navigation_test.cc
@@ -11,6 +11,7 @@
#include "chrome_frame/test/chrome_frame_ui_test_utils.h"
#include "chrome_frame/test/mock_ie_event_sink_actions.h"
#include "chrome_frame/test/mock_ie_event_sink_test.h"
+#include "net/http/http_util.h"
// Needed for CreateFunctor.
#define GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING
@@ -922,19 +923,20 @@ TEST_P(FullTabNavigationTest, RefreshContents) {
return;
}
+ const char kHeaders[] = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n"
+ "X-UA-Compatible: chrome=1\r\n";
+
+ const char kBody[] = "<html><body>Hi there. Got new content?"
+ "</body></html>";
+
std::wstring src_url = server_mock_.Resolve(L"/refresh_src.html");
EXPECT_CALL(server_mock_, Get(_, StrEq(L"/refresh_src.html"), _))
.Times(2)
- .WillRepeatedly(
- SendFast(
- "HTTP/1.1 200 OK\r\n"
- "Content-Type: text/html\r\n",
- "<html>"
- "<head><meta http-equiv=\"x-ua-compatible\" content=\"chrome=1\""
- "/></head>"
- "<body>Hi there. Got new content?"
- "</body></html>"));
+ .WillOnce(SendFast(kHeaders, kBody))
+ .WillOnce(testing::DoAll(
+ SendFast(kHeaders, kBody),
+ DelayCloseBrowserMock(&loop_, 4000, &ie_mock_)));
EXPECT_CALL(ie_mock_, OnFileDownload(_, _)).Times(testing::AnyNumber());
@@ -945,9 +947,7 @@ TEST_P(FullTabNavigationTest, RefreshContents) {
EXPECT_CALL(ie_mock_,
OnNavigateComplete2(_, testing::Field(&VARIANT::bstrVal,
StrEq(src_url))))
- .WillOnce(testing::DoAll(
- DelayRefresh(&ie_mock_, &loop_, 2000),
- DelayCloseBrowserMock(&loop_, 4000, &ie_mock_)));
+ .WillOnce(DelayRefresh(&ie_mock_, &loop_, 2000));
EXPECT_CALL(ie_mock_, OnLoad(in_cf, StrEq(src_url)))
.Times(2);
@@ -1104,4 +1104,62 @@ TEST_F(FullTabDownloadTest, TopLevelPostReissueFromChromeFramePage) {
LaunchIENavigateAndLoop(src_url, kChromeFrameLongNavigationTimeoutInSeconds);
}
+MATCHER_P(UserAgentHeaderMatcher, ua_string, "") {
+ std::string headers = arg.headers();
+ StringToUpperASCII(&headers);
+
+ std::string ua_string_to_search = ua_string;
+ StringToUpperASCII(&ua_string_to_search);
+
+ net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(),
+ "\r\n");
+ while (it.GetNext()) {
+ if (lstrcmpiA(it.name().c_str(), "User-Agent") == 0) {
+ if (it.values().find(ua_string_to_search) != std::string::npos)
+ return true;
+ }
+ }
+ return false;
+}
+
+// Tests refreshing causes a page load and that the chrome frame user agent
+// string is appended to the UA in the incoming top level HTTP requests.
+TEST_P(FullTabNavigationTest, RefreshContentsUATest) {
+ const char kBody[] = "<html><head></head>"
+ "<body>Hi there. Got new content?"
+ "</body></html>";
+
+ std::string headers = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n";
+ bool in_cf = GetParam().invokes_cf();
+ if (in_cf) {
+ headers.append("X-UA-Compatible: chrome=1\r\n");
+ }
+
+ std::wstring src_url = server_mock_.Resolve(L"/refresh_src.html");
+
+ EXPECT_CALL(server_mock_, Get(_, StrEq(L"/refresh_src.html"),
+ UserAgentHeaderMatcher("chromeframe")))
+ .Times(2)
+ .WillOnce(SendFast(headers, kBody))
+ .WillOnce(testing::DoAll(
+ SendFast(headers, kBody),
+ DelayCloseBrowserMock(&loop_, 4000, &ie_mock_)));
+
+ EXPECT_CALL(ie_mock_, OnFileDownload(_, _)).Times(testing::AnyNumber());
+
+ EXPECT_CALL(ie_mock_,
+ OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal,
+ StrEq(src_url)),
+ _, _, _, _, _));
+ EXPECT_CALL(ie_mock_,
+ OnNavigateComplete2(_, testing::Field(&VARIANT::bstrVal,
+ StrEq(src_url))))
+ .WillOnce(DelayRefresh(&ie_mock_, &loop_, 2000));
+
+ EXPECT_CALL(ie_mock_, OnLoad(in_cf, StrEq(src_url)))
+ .Times(testing::AtMost(2));
+
+ LaunchIEAndNavigate(src_url);
+}
+
} // namespace chrome_frame_test
diff --git a/chrome_frame/utils.cc b/chrome_frame/utils.cc
index c74a840..565990b1 100644
--- a/chrome_frame/utils.cc
+++ b/chrome_frame/utils.cc
@@ -1565,3 +1565,10 @@ void EnumerateKeyValues(HKEY parent_key, const wchar_t* sub_key_name,
++url_list;
}
}
+
+std::wstring GetCurrentModuleVersion() {
+ scoped_ptr<FileVersionInfo> module_version_info(
+ FileVersionInfo::CreateFileVersionInfoForCurrentModule());
+ DCHECK(module_version_info.get() != NULL);
+ return module_version_info->file_version();
+}
diff --git a/chrome_frame/utils.h b/chrome_frame/utils.h
index 2e167d2..f29d536 100644
--- a/chrome_frame/utils.h
+++ b/chrome_frame/utils.h
@@ -611,4 +611,7 @@ void EnumerateKeyValues(HKEY parent_key, const wchar_t* sub_key_name,
bool CheckXUaCompatibleDirective(const std::string& directive,
int ie_major_version);
+// Returns the version of the current module as a string.
+std::wstring GetCurrentModuleVersion();
+
#endif // CHROME_FRAME_UTILS_H_