Home | History | Annotate | Download | only in test
      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 }
    291