1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
8 #include "base/strings/string16.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/win/scoped_bstr.h"
12 #include "base/win/scoped_comptr.h"
13 #include "chrome_frame/html_utils.h"
14 #include "chrome_frame/http_negotiate.h"
15 #include "chrome_frame/registry_list_preferences_holder.h"
16 #include "chrome_frame/test/chrome_frame_test_utils.h"
17 #include "chrome_frame/utils.h"
18 #include "gmock/gmock.h"
19 #include "gtest/gtest.h"
21 class HttpNegotiateTest : public testing::Test {
27 class TestHttpNegotiate
28 : public CComObjectRootEx<CComMultiThreadModel>,
29 public IHttpNegotiate {
32 : beginning_transaction_ret_(S_OK), additional_headers_(NULL) {
35 BEGIN_COM_MAP(TestHttpNegotiate)
36 COM_INTERFACE_ENTRY(IHttpNegotiate)
38 STDMETHOD(BeginningTransaction)(LPCWSTR url, LPCWSTR headers, // NOLINT
39 DWORD reserved, // NOLINT
40 LPWSTR* additional_headers) { // NOLINT
41 if (additional_headers_) {
42 int len = lstrlenW(additional_headers_);
44 *additional_headers = reinterpret_cast<wchar_t*>(
45 ::CoTaskMemAlloc(len * sizeof(wchar_t)));
46 lstrcpyW(*additional_headers, additional_headers_);
48 return beginning_transaction_ret_;
51 STDMETHOD(OnResponse)(DWORD response_code, LPCWSTR response_header,
52 LPCWSTR request_header,
53 LPWSTR* additional_request_headers) {
57 HRESULT beginning_transaction_ret_;
58 const wchar_t* additional_headers_;
61 TEST_F(HttpNegotiateTest, BeginningTransaction) {
62 static const int kBeginningTransactionIndex = 3;
63 CComObjectStackEx<TestHttpNegotiate> test_http;
64 IHttpNegotiate_BeginningTransaction_Fn original =
65 reinterpret_cast<IHttpNegotiate_BeginningTransaction_Fn>(
66 (*reinterpret_cast<void***>(
67 static_cast<IHttpNegotiate*>(
68 &test_http)))[kBeginningTransactionIndex]);
71 ASCIIToWide(http_utils::GetDefaultUserAgentHeaderWithCFTag()));
73 ASCIIToWide(http_utils::GetChromeFrameUserAgent()));
75 EXPECT_NE(string16::npos, cf_ua.find(L"chromeframe/"));
78 const string16 original_headers_;
79 const string16 delegate_additional_;
80 const string16 expected_additional_;
81 HRESULT delegate_return_value_;
93 L"Accept: */*\r\n" + cf_ua + L"\r\n",
95 { L"User-Agent: Bingo/1.0\r\n",
97 L"User-Agent: Bingo/1.0 " + cf_tag + L"\r\n",
99 { L"User-Agent: NotMe/1.0\r\n",
100 L"User-Agent: MeMeMe/1.0\r\n",
101 L"User-Agent: MeMeMe/1.0 " + cf_tag + L"\r\n",
104 L"User-Agent: MeMeMe/1.0\r\n",
105 L"User-Agent: MeMeMe/1.0 " + cf_tag + L"\r\n",
109 for (int i = 0; i < arraysize(test_cases); ++i) {
110 TestCase& test = test_cases[i];
111 wchar_t* additional = NULL;
112 test_http.beginning_transaction_ret_ = test.delegate_return_value_;
113 test_http.additional_headers_ = test.delegate_additional_.c_str();
114 HttpNegotiatePatch::BeginningTransaction(original, &test_http,
115 L"http://www.google.com", test.original_headers_.c_str(), 0,
117 EXPECT_TRUE(additional != NULL);
120 // Check against the expected additional headers.
121 EXPECT_EQ(test.expected_additional_, string16(additional));
122 ::CoTaskMemFree(additional);
127 TEST_F(HttpNegotiateTest, BeginningTransactionUARemoval) {
128 static const int kBeginningTransactionIndex = 3;
129 CComObjectStackEx<TestHttpNegotiate> test_http;
130 IHttpNegotiate_BeginningTransaction_Fn original =
131 reinterpret_cast<IHttpNegotiate_BeginningTransaction_Fn>(
132 (*reinterpret_cast<void***>(
133 static_cast<IHttpNegotiate*>(
134 &test_http)))[kBeginningTransactionIndex]);
137 ASCIIToWide(http_utils::RemoveChromeFrameFromUserAgentValue(
138 http_utils::GetDefaultUserAgentHeaderWithCFTag())));
140 ASCIIToWide(http_utils::AddChromeFrameToUserAgentValue(
141 WideToASCII(nocf_ua))));
143 EXPECT_EQ(string16::npos, nocf_ua.find(L"chromeframe/"));
144 EXPECT_NE(string16::npos, cf_ua.find(L"chromeframe/"));
146 string16 ua_url(L"www.withua.com");
147 string16 no_ua_url(L"www.noua.com");
149 RegistryListPreferencesHolder& ua_holder =
150 GetUserAgentPreferencesHolderForTesting();
151 ua_holder.AddStringForTesting(no_ua_url);
155 const string16 original_headers_;
156 const string16 delegate_additional_;
157 const string16 expected_additional_;
161 L"Accept: */*\r\n" + cf_ua + L"\r\n",
162 L"Accept: */*\r\n" + cf_ua + L"\r\n" },
165 L"Accept: */*\r\n" + nocf_ua + L"\r\n",
166 L"Accept: */*\r\n" + cf_ua + L"\r\n" },
169 L"Accept: */*\r\n" + cf_ua + L"\r\n",
170 L"Accept: */*\r\n" + nocf_ua + L"\r\n" },
173 L"Accept: */*\r\n" + nocf_ua + L"\r\n",
174 L"Accept: */*\r\n" + nocf_ua + L"\r\n" },
177 for (int i = 0; i < arraysize(test_cases); ++i) {
178 TestCase& test = test_cases[i];
179 wchar_t* additional = NULL;
180 test_http.beginning_transaction_ret_ = S_OK;
181 test_http.additional_headers_ = test.delegate_additional_.c_str();
182 HttpNegotiatePatch::BeginningTransaction(original, &test_http,
183 test.url_.c_str(), test.original_headers_.c_str(), 0,
185 EXPECT_TRUE(additional != NULL);
188 // Check against the expected additional headers.
189 EXPECT_EQ(test.expected_additional_, string16(additional))
190 << "Iteration: " << i;
191 ::CoTaskMemFree(additional);
197 class TestInternetProtocolSink
198 : public CComObjectRootEx<CComMultiThreadModel>,
199 public IInternetProtocolSink {
201 TestInternetProtocolSink() : status_(0) {
202 // Create an instance of IE to fullfill the requirements of being able
203 // to detect whether a sub-frame or top-frame is being loaded (see
204 // IsSubFrameRequest) and to be able to mark an IBrowserService
205 // implementation as a target for CF navigation.
206 HRESULT hr = browser_.CreateInstance(CLSID_InternetExplorer);
207 CHECK(SUCCEEDED(hr));
209 browser_->Navigate(base::win::ScopedBstr(L"about:blank"),
210 NULL, NULL, NULL, NULL);
214 ~TestInternetProtocolSink() {
219 BEGIN_COM_MAP(TestInternetProtocolSink)
220 COM_INTERFACE_ENTRY(IInternetProtocolSink)
221 COM_INTERFACE_ENTRY_AGGREGATE(IID_IServiceProvider, browser_)
224 // IInternetProtocolSink.
225 STDMETHOD(Switch)(PROTOCOLDATA* data) {
230 STDMETHOD(ReportProgress)(ULONG status, LPCWSTR text) {
232 status_text_ = text ? text : L"";
236 STDMETHOD(ReportData)(DWORD bscf, ULONG progress, ULONG progress_max) {
241 STDMETHOD(ReportResult)(HRESULT hr, DWORD err, LPCWSTR result) {
246 ULONG last_status() const {
250 const string16& last_status_text() const {
256 string16 status_text_;
257 base::win::ScopedComPtr<IWebBrowser2> browser_;
260 using testing::AllOf;
261 using testing::ContainsRegex;
262 using testing::HasSubstr;
264 TEST(AppendUserAgent, Append) {
265 EXPECT_THAT(AppendCFUserAgentString(NULL, NULL),
266 testing::ContainsRegex("User-Agent:.+chromeframe.+\r\n"));
268 // Check Http headers are reasonably parsed.
269 EXPECT_THAT(AppendCFUserAgentString(L"Bad User-Agent: Age Tuners;\r\n", NULL),
270 AllOf(ContainsRegex("User-Agent:.+chromeframe.+\r\n"),
271 testing::Not(testing::HasSubstr("Age Tuners"))));
273 // Honor headers User-Agent, if additional headers does not specify one.
274 EXPECT_THAT(AppendCFUserAgentString(L"User-Agent: A Tense Rug;\r\n", NULL),
275 ContainsRegex("User-Agent: A Tense Rug; chromeframe.+\r\n"));
277 // Honor additional headers User-Agent.
278 EXPECT_THAT(AppendCFUserAgentString(L"User-Agent: Near Guest;\r\n",
279 L"User-Agent: Rat see Gun;\r\n"),
280 ContainsRegex("User-Agent: Rat see Gun; chromeframe.+\r\n"));
282 // Check additional headers are preserved.
283 EXPECT_THAT(AppendCFUserAgentString(NULL,
284 L"Authorization: A Zoo That I Ruin\r\n"
285 L"User-Agent: Get a Nurse;\r\n"
286 L"Accept-Language: Cleanup a Cat Egg\r\n"),
287 AllOf(ContainsRegex("User-Agent: Get a Nurse; chromeframe.+\r\n"),
288 HasSubstr("Authorization: A Zoo That I Ruin\r\n"),
289 HasSubstr("Accept-Language: Cleanup a Cat Egg\r\n")));