OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include <atlbase.h> | |
6 #include <atlcom.h> | |
7 | |
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" | |
20 | |
21 class HttpNegotiateTest : public testing::Test { | |
22 protected: | |
23 HttpNegotiateTest() { | |
24 } | |
25 }; | |
26 | |
27 class TestHttpNegotiate | |
28 : public CComObjectRootEx<CComMultiThreadModel>, | |
29 public IHttpNegotiate { | |
30 public: | |
31 TestHttpNegotiate() | |
32 : beginning_transaction_ret_(S_OK), additional_headers_(NULL) { | |
33 } | |
34 | |
35 BEGIN_COM_MAP(TestHttpNegotiate) | |
36 COM_INTERFACE_ENTRY(IHttpNegotiate) | |
37 END_COM_MAP() | |
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_); | |
43 len++; | |
44 *additional_headers = reinterpret_cast<wchar_t*>( | |
45 ::CoTaskMemAlloc(len * sizeof(wchar_t))); | |
46 lstrcpyW(*additional_headers, additional_headers_); | |
47 } | |
48 return beginning_transaction_ret_; | |
49 } | |
50 | |
51 STDMETHOD(OnResponse)(DWORD response_code, LPCWSTR response_header, | |
52 LPCWSTR request_header, | |
53 LPWSTR* additional_request_headers) { | |
54 return S_OK; | |
55 } | |
56 | |
57 HRESULT beginning_transaction_ret_; | |
58 const wchar_t* additional_headers_; | |
59 }; | |
60 | |
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]); | |
69 | |
70 base::string16 cf_ua( | |
71 base::ASCIIToWide(http_utils::GetDefaultUserAgentHeaderWithCFTag())); | |
72 base::string16 cf_tag( | |
73 base::ASCIIToWide(http_utils::GetChromeFrameUserAgent())); | |
74 | |
75 EXPECT_NE(base::string16::npos, cf_ua.find(L"chromeframe/")); | |
76 | |
77 struct TestCase { | |
78 const base::string16 original_headers_; | |
79 const base::string16 delegate_additional_; | |
80 const base::string16 expected_additional_; | |
81 HRESULT delegate_return_value_; | |
82 } test_cases[] = { | |
83 { L"Accept: */*\r\n", | |
84 L"", | |
85 cf_ua + L"\r\n", | |
86 S_OK }, | |
87 { L"Accept: */*\r\n", | |
88 L"", | |
89 L"", | |
90 E_OUTOFMEMORY }, | |
91 { L"", | |
92 L"Accept: */*\r\n", | |
93 L"Accept: */*\r\n" + cf_ua + L"\r\n", | |
94 S_OK }, | |
95 { L"User-Agent: Bingo/1.0\r\n", | |
96 L"", | |
97 L"User-Agent: Bingo/1.0 " + cf_tag + L"\r\n", | |
98 S_OK }, | |
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", | |
102 S_OK }, | |
103 { L"", | |
104 L"User-Agent: MeMeMe/1.0\r\n", | |
105 L"User-Agent: MeMeMe/1.0 " + cf_tag + L"\r\n", | |
106 S_OK }, | |
107 }; | |
108 | |
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, | |
116 &additional); | |
117 EXPECT_TRUE(additional != NULL); | |
118 | |
119 if (additional) { | |
120 // Check against the expected additional headers. | |
121 EXPECT_EQ(test.expected_additional_, base::string16(additional)); | |
122 ::CoTaskMemFree(additional); | |
123 } | |
124 } | |
125 } | |
126 | |
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]); | |
135 | |
136 base::string16 nocf_ua( | |
137 base::ASCIIToWide(http_utils::RemoveChromeFrameFromUserAgentValue( | |
138 http_utils::GetDefaultUserAgentHeaderWithCFTag()))); | |
139 base::string16 cf_ua(base::ASCIIToWide( | |
140 http_utils::AddChromeFrameToUserAgentValue(WideToASCII(nocf_ua)))); | |
141 | |
142 EXPECT_EQ(base::string16::npos, nocf_ua.find(L"chromeframe/")); | |
143 EXPECT_NE(base::string16::npos, cf_ua.find(L"chromeframe/")); | |
144 | |
145 base::string16 ua_url(L"www.withua.com"); | |
146 base::string16 no_ua_url(L"www.noua.com"); | |
147 | |
148 RegistryListPreferencesHolder& ua_holder = | |
149 GetUserAgentPreferencesHolderForTesting(); | |
150 ua_holder.AddStringForTesting(no_ua_url); | |
151 | |
152 struct TestCase { | |
153 const base::string16 url_; | |
154 const base::string16 original_headers_; | |
155 const base::string16 delegate_additional_; | |
156 const base::string16 expected_additional_; | |
157 } test_cases[] = { | |
158 { ua_url, | |
159 L"", | |
160 L"Accept: */*\r\n" + cf_ua + L"\r\n", | |
161 L"Accept: */*\r\n" + cf_ua + L"\r\n" }, | |
162 { ua_url, | |
163 L"", | |
164 L"Accept: */*\r\n" + nocf_ua + L"\r\n", | |
165 L"Accept: */*\r\n" + cf_ua + L"\r\n" }, | |
166 { no_ua_url, | |
167 L"", | |
168 L"Accept: */*\r\n" + cf_ua + L"\r\n", | |
169 L"Accept: */*\r\n" + nocf_ua + L"\r\n" }, | |
170 { no_ua_url, | |
171 L"", | |
172 L"Accept: */*\r\n" + nocf_ua + L"\r\n", | |
173 L"Accept: */*\r\n" + nocf_ua + L"\r\n" }, | |
174 }; | |
175 | |
176 for (int i = 0; i < arraysize(test_cases); ++i) { | |
177 TestCase& test = test_cases[i]; | |
178 wchar_t* additional = NULL; | |
179 test_http.beginning_transaction_ret_ = S_OK; | |
180 test_http.additional_headers_ = test.delegate_additional_.c_str(); | |
181 HttpNegotiatePatch::BeginningTransaction(original, &test_http, | |
182 test.url_.c_str(), test.original_headers_.c_str(), 0, | |
183 &additional); | |
184 EXPECT_TRUE(additional != NULL); | |
185 | |
186 if (additional) { | |
187 // Check against the expected additional headers. | |
188 EXPECT_EQ(test.expected_additional_, base::string16(additional)) | |
189 << "Iteration: " << i; | |
190 ::CoTaskMemFree(additional); | |
191 } | |
192 } | |
193 } | |
194 | |
195 | |
196 class TestInternetProtocolSink | |
197 : public CComObjectRootEx<CComMultiThreadModel>, | |
198 public IInternetProtocolSink { | |
199 public: | |
200 TestInternetProtocolSink() : status_(0) { | |
201 // Create an instance of IE to fullfill the requirements of being able | |
202 // to detect whether a sub-frame or top-frame is being loaded (see | |
203 // IsSubFrameRequest) and to be able to mark an IBrowserService | |
204 // implementation as a target for CF navigation. | |
205 HRESULT hr = browser_.CreateInstance(CLSID_InternetExplorer); | |
206 CHECK(SUCCEEDED(hr)); | |
207 if (SUCCEEDED(hr)) { | |
208 browser_->Navigate(base::win::ScopedBstr(L"about:blank"), | |
209 NULL, NULL, NULL, NULL); | |
210 } | |
211 } | |
212 | |
213 ~TestInternetProtocolSink() { | |
214 if (browser_) | |
215 browser_->Quit(); | |
216 } | |
217 | |
218 BEGIN_COM_MAP(TestInternetProtocolSink) | |
219 COM_INTERFACE_ENTRY(IInternetProtocolSink) | |
220 COM_INTERFACE_ENTRY_AGGREGATE(IID_IServiceProvider, browser_) | |
221 END_COM_MAP() | |
222 | |
223 // IInternetProtocolSink. | |
224 STDMETHOD(Switch)(PROTOCOLDATA* data) { | |
225 NOTREACHED(); | |
226 return S_OK; | |
227 } | |
228 | |
229 STDMETHOD(ReportProgress)(ULONG status, LPCWSTR text) { | |
230 status_ = status; | |
231 status_text_ = text ? text : L""; | |
232 return S_OK; | |
233 } | |
234 | |
235 STDMETHOD(ReportData)(DWORD bscf, ULONG progress, ULONG progress_max) { | |
236 NOTREACHED(); | |
237 return S_OK; | |
238 } | |
239 | |
240 STDMETHOD(ReportResult)(HRESULT hr, DWORD err, LPCWSTR result) { | |
241 NOTREACHED(); | |
242 return S_OK; | |
243 } | |
244 | |
245 ULONG last_status() const { | |
246 return status_; | |
247 } | |
248 | |
249 const base::string16& last_status_text() const { | |
250 return status_text_; | |
251 } | |
252 | |
253 protected: | |
254 ULONG status_; | |
255 base::string16 status_text_; | |
256 base::win::ScopedComPtr<IWebBrowser2> browser_; | |
257 }; | |
258 | |
259 using testing::AllOf; | |
260 using testing::ContainsRegex; | |
261 using testing::HasSubstr; | |
262 | |
263 TEST(AppendUserAgent, Append) { | |
264 EXPECT_THAT(AppendCFUserAgentString(NULL, NULL), | |
265 testing::ContainsRegex("User-Agent:.+chromeframe.+\r\n")); | |
266 | |
267 // Check Http headers are reasonably parsed. | |
268 EXPECT_THAT(AppendCFUserAgentString(L"Bad User-Agent: Age Tuners;\r\n", NULL), | |
269 AllOf(ContainsRegex("User-Agent:.+chromeframe.+\r\n"), | |
270 testing::Not(testing::HasSubstr("Age Tuners")))); | |
271 | |
272 // Honor headers User-Agent, if additional headers does not specify one. | |
273 EXPECT_THAT(AppendCFUserAgentString(L"User-Agent: A Tense Rug;\r\n", NULL), | |
274 ContainsRegex("User-Agent: A Tense Rug; chromeframe.+\r\n")); | |
275 | |
276 // Honor additional headers User-Agent. | |
277 EXPECT_THAT(AppendCFUserAgentString(L"User-Agent: Near Guest;\r\n", | |
278 L"User-Agent: Rat see Gun;\r\n"), | |
279 ContainsRegex("User-Agent: Rat see Gun; chromeframe.+\r\n")); | |
280 | |
281 // Check additional headers are preserved. | |
282 EXPECT_THAT(AppendCFUserAgentString(NULL, | |
283 L"Authorization: A Zoo That I Ruin\r\n" | |
284 L"User-Agent: Get a Nurse;\r\n" | |
285 L"Accept-Language: Cleanup a Cat Egg\r\n"), | |
286 AllOf(ContainsRegex("User-Agent: Get a Nurse; chromeframe.+\r\n"), | |
287 HasSubstr("Authorization: A Zoo That I Ruin\r\n"), | |
288 HasSubstr("Accept-Language: Cleanup a Cat Egg\r\n"))); | |
289 } | |
OLD | NEW |