- add sources.
[platform/framework/web/crosswalk.git] / src / chrome_frame / test / http_negotiate_unittest.cc
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   string16 cf_ua(
71       ASCIIToWide(http_utils::GetDefaultUserAgentHeaderWithCFTag()));
72   string16 cf_tag(
73       ASCIIToWide(http_utils::GetChromeFrameUserAgent()));
74
75   EXPECT_NE(string16::npos, cf_ua.find(L"chromeframe/"));
76
77   struct TestCase {
78     const string16 original_headers_;
79     const string16 delegate_additional_;
80     const 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_, 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   string16 nocf_ua(
137       ASCIIToWide(http_utils::RemoveChromeFrameFromUserAgentValue(
138           http_utils::GetDefaultUserAgentHeaderWithCFTag())));
139   string16 cf_ua(
140       ASCIIToWide(http_utils::AddChromeFrameToUserAgentValue(
141           WideToASCII(nocf_ua))));
142
143   EXPECT_EQ(string16::npos, nocf_ua.find(L"chromeframe/"));
144   EXPECT_NE(string16::npos, cf_ua.find(L"chromeframe/"));
145
146   string16 ua_url(L"www.withua.com");
147   string16 no_ua_url(L"www.noua.com");
148
149   RegistryListPreferencesHolder& ua_holder =
150       GetUserAgentPreferencesHolderForTesting();
151   ua_holder.AddStringForTesting(no_ua_url);
152
153   struct TestCase {
154     const string16 url_;
155     const string16 original_headers_;
156     const string16 delegate_additional_;
157     const string16 expected_additional_;
158   } test_cases[] = {
159     { ua_url,
160       L"",
161       L"Accept: */*\r\n" + cf_ua + L"\r\n",
162       L"Accept: */*\r\n" + cf_ua + L"\r\n" },
163     { ua_url,
164       L"",
165       L"Accept: */*\r\n" + nocf_ua + L"\r\n",
166       L"Accept: */*\r\n" + cf_ua + L"\r\n" },
167     { no_ua_url,
168       L"",
169       L"Accept: */*\r\n" + cf_ua + L"\r\n",
170       L"Accept: */*\r\n" + nocf_ua + L"\r\n" },
171     { no_ua_url,
172       L"",
173       L"Accept: */*\r\n" + nocf_ua + L"\r\n",
174       L"Accept: */*\r\n" + nocf_ua + L"\r\n" },
175   };
176
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,
184         &additional);
185     EXPECT_TRUE(additional != NULL);
186
187     if (additional) {
188       // Check against the expected additional headers.
189       EXPECT_EQ(test.expected_additional_, string16(additional))
190           << "Iteration: " << i;
191       ::CoTaskMemFree(additional);
192     }
193   }
194 }
195
196
197 class TestInternetProtocolSink
198     : public CComObjectRootEx<CComMultiThreadModel>,
199       public IInternetProtocolSink {
200  public:
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));
208     if (SUCCEEDED(hr)) {
209       browser_->Navigate(base::win::ScopedBstr(L"about:blank"),
210                          NULL, NULL, NULL, NULL);
211     }
212   }
213
214   ~TestInternetProtocolSink() {
215     if (browser_)
216       browser_->Quit();
217   }
218
219 BEGIN_COM_MAP(TestInternetProtocolSink)
220   COM_INTERFACE_ENTRY(IInternetProtocolSink)
221   COM_INTERFACE_ENTRY_AGGREGATE(IID_IServiceProvider, browser_)
222 END_COM_MAP()
223
224   // IInternetProtocolSink.
225   STDMETHOD(Switch)(PROTOCOLDATA* data) {
226     NOTREACHED();
227     return S_OK;
228   }
229
230   STDMETHOD(ReportProgress)(ULONG status, LPCWSTR text) {
231     status_ = status;
232     status_text_ = text ? text : L"";
233     return S_OK;
234   }
235
236   STDMETHOD(ReportData)(DWORD bscf, ULONG progress, ULONG progress_max) {
237     NOTREACHED();
238     return S_OK;
239   }
240
241   STDMETHOD(ReportResult)(HRESULT hr, DWORD err, LPCWSTR result) {
242     NOTREACHED();
243     return S_OK;
244   }
245
246   ULONG last_status() const {
247     return status_;
248   }
249
250   const string16& last_status_text() const {
251     return status_text_;
252   }
253
254  protected:
255   ULONG status_;
256   string16 status_text_;
257   base::win::ScopedComPtr<IWebBrowser2> browser_;
258 };
259
260 using testing::AllOf;
261 using testing::ContainsRegex;
262 using testing::HasSubstr;
263
264 TEST(AppendUserAgent, Append) {
265   EXPECT_THAT(AppendCFUserAgentString(NULL, NULL),
266       testing::ContainsRegex("User-Agent:.+chromeframe.+\r\n"));
267
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"))));
272
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"));
276
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"));
281
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")));
290 }