Home | History | Annotate | Download | only in net
      1 // Copyright 2014 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 // End-to-end SDCH tests.  Uses the embedded test server to return SDCH
      6 // results
      7 
      8 #include "base/base64.h"
      9 #include "base/bind.h"
     10 #include "base/callback.h"
     11 #include "base/command_line.h"
     12 #include "base/files/scoped_temp_dir.h"
     13 #include "base/memory/weak_ptr.h"
     14 #include "base/path_service.h"
     15 #include "base/run_loop.h"
     16 #include "base/strings/string_tokenizer.h"
     17 #include "base/strings/string_util.h"
     18 #include "base/strings/stringprintf.h"
     19 #include "chrome/browser/browser_process.h"
     20 #include "chrome/browser/browsing_data/browsing_data_helper.h"
     21 #include "chrome/browser/browsing_data/browsing_data_remover.h"
     22 #include "chrome/browser/browsing_data/browsing_data_remover_test_util.h"
     23 #include "chrome/browser/profiles/profile.h"
     24 #include "chrome/browser/profiles/profile_manager.h"
     25 #include "chrome/browser/ui/browser.h"
     26 #include "chrome/browser/ui/browser_tabstrip.h"
     27 #include "chrome/browser/ui/browser_window.h"
     28 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     29 #include "chrome/common/chrome_paths.h"
     30 #include "chrome/test/base/in_process_browser_test.h"
     31 #include "content/public/browser/browser_thread.h"
     32 #include "content/public/common/content_switches.h"
     33 #include "content/public/test/browser_test_utils.h"
     34 #include "content/public/test/test_utils.h"
     35 #include "crypto/sha2.h"
     36 #include "net/base/sdch_manager.h"
     37 #include "net/http/http_response_headers.h"
     38 #include "net/test/embedded_test_server/embedded_test_server.h"
     39 #include "net/test/embedded_test_server/http_request.h"
     40 #include "net/test/embedded_test_server/http_response.h"
     41 #include "net/url_request/url_fetcher.h"
     42 #include "net/url_request/url_fetcher_delegate.h"
     43 #include "net/url_request/url_request_context.h"
     44 #include "net/url_request/url_request_context_getter.h"
     45 #include "sdch/open-vcdiff/src/google/vcencoder.h"
     46 #include "testing/gtest/include/gtest/gtest.h"
     47 
     48 #if defined(OS_CHROMEOS)
     49 #include "chromeos/chromeos_switches.h"
     50 #endif
     51 
     52 namespace {
     53 
     54 typedef std::vector<net::test_server::HttpRequest> RequestVector;
     55 typedef std::map<std::string, std::string> HttpRequestHeaderMap;
     56 
     57 // Credit Alfred, Lord Tennyson
     58 static const char kSampleData[] = "<html><body><pre>"
     59     "There lies the port; the vessel puffs her sail:\n"
     60     "There gloom the dark, broad seas. My mariners,\n"
     61     "Souls that have toil'd, and wrought, and thought with me\n"
     62     "That ever with a frolic welcome took\n"
     63     "The thunder and the sunshine, and opposed\n"
     64     "Free hearts, free foreheadsyou and I are old;\n"
     65     "Old age hath yet his honour and his toil;\n"
     66     "Death closes all: but something ere the end,\n"
     67     "Some work of noble note, may yet be done,\n"
     68     "Not unbecoming men that strove with Gods.\n"
     69     "The lights begin to twinkle from the rocks:\n"
     70     "The long day wanes: the slow moon climbs: the deep\n"
     71     "Moans round with many voices. Come, my friends,\n"
     72     "'T is not too late to seek a newer world.\n"
     73     "Push off, and sitting well in order smite\n"
     74     "The sounding furrows; for my purpose holds\n"
     75     "To sail beyond the sunset, and the baths\n"
     76     "Of all the western stars, until I die.\n"
     77     "It may be that the gulfs will wash us down:\n"
     78     "It may be we shall touch the Happy Isles,\n"
     79     "And see the great Achilles, whom we knew.\n"
     80     "Tho' much is taken, much abides; and tho'\n"
     81     "We are not now that strength which in old days\n"
     82     "Moved earth and heaven, that which we are, we are;\n"
     83     "One equal temper of heroic hearts,\n"
     84     "Made weak by time and fate, but strong in will\n"
     85     "To strive, to seek, to find, and not to yield.\n"
     86     "</pre></body></html>";
     87 
     88 // Random selection of lines from above, to allow some encoding, but
     89 // not a trivial encoding.
     90 static const char kDictionaryContents[] =
     91     "The thunder and the sunshine, and opposed\n"
     92     "To sail beyond the sunset, and the baths\n"
     93     "Of all the western stars, until I die.\n"
     94     "Made weak by time and fate, but strong in will\n"
     95     "Moans round with many voices. Come, my friends,\n"
     96     "The lights begin to twinkle from the rocks:";
     97 
     98 static const char kDictionaryURLPath[] = "/dict";
     99 static const char kDataURLPath[] = "/data";
    100 
    101 // Scans in a case-insensitive way for |header| in |map|,
    102 // returning true if found and setting |*value| to the value
    103 // of that header.  Does not handle multiple instances of the same
    104 // header.
    105 bool GetRequestHeader(const HttpRequestHeaderMap& map,
    106                       const char* header,
    107                       std::string* value) {
    108   for (HttpRequestHeaderMap::const_iterator it = map.begin();
    109        it != map.end(); ++it) {
    110     if (!base::strcasecmp(it->first.c_str(), header)) {
    111       *value = it->second;
    112       return true;
    113     }
    114   }
    115   return false;
    116 }
    117 
    118 // Do a URL-safe base64 encoding.  See the SDCH spec "Dictionary Identifier"
    119 // section, and RFC 3548 section 4.
    120 void SafeBase64Encode(const std::string& input_value, std::string* output) {
    121   DCHECK(output);
    122   base::Base64Encode(input_value, output);
    123   std::replace(output->begin(), output->end(), '+', '-');
    124   std::replace(output->begin(), output->end(), '/', '_');
    125 }
    126 
    127 // Class that bundles responses for an EmbeddedTestServer().
    128 // Dictionary is at <domain>/dict, data at <domain>/data.
    129 // The data is sent SDCH encoded if that's allowed by protoocol.
    130 class SdchResponseHandler {
    131  public:
    132   // Do initial preparation so that SDCH requests can be handled.
    133   explicit SdchResponseHandler(std::string domain)
    134       : cache_sdch_response_(false),
    135         weak_ptr_factory_(this) {
    136     // Dictionary
    137     sdch_dictionary_contents_ = "Domain: ";
    138     sdch_dictionary_contents_ += domain;
    139     sdch_dictionary_contents_ += "\n\n";
    140     sdch_dictionary_contents_ += kDictionaryContents;
    141 
    142     // Dictionary hash for client and server.
    143     char binary_hash[32];
    144     crypto::SHA256HashString(sdch_dictionary_contents_, binary_hash,
    145                              sizeof(binary_hash));
    146     SafeBase64Encode(std::string(&binary_hash[0], 6), &dictionary_client_hash_);
    147     SafeBase64Encode(std::string(&binary_hash[6], 6), &dictionary_server_hash_);
    148 
    149     // Encoded response.
    150     open_vcdiff::HashedDictionary vcdiff_dictionary(
    151         kDictionaryContents, strlen(kDictionaryContents));
    152     bool result = vcdiff_dictionary.Init();
    153     DCHECK(result);
    154     open_vcdiff::VCDiffStreamingEncoder encoder(&vcdiff_dictionary, 0, false);
    155     encoded_data_ = dictionary_server_hash_;
    156     encoded_data_ += '\0';
    157     result = encoder.StartEncoding(&encoded_data_);
    158     DCHECK(result);
    159     result = encoder.EncodeChunk(
    160         kSampleData, strlen(kSampleData), &encoded_data_);
    161     DCHECK(result);
    162     result = encoder.FinishEncoding(&encoded_data_);
    163     DCHECK(result);
    164   }
    165 
    166   static bool ClientIsAdvertisingSdchEncoding(const HttpRequestHeaderMap& map) {
    167     std::string value;
    168     if (!GetRequestHeader(map, "accept-encoding", &value))
    169       return false;
    170     base::StringTokenizer tokenizer(value, " ,");
    171     while (tokenizer.GetNext()) {
    172       if (base::strcasecmp(tokenizer.token().c_str(), "sdch"))
    173         return true;
    174     }
    175     return false;
    176   }
    177 
    178   bool ShouldRespondWithSdchEncoding(const HttpRequestHeaderMap& map) {
    179     std::string value;
    180     if (!GetRequestHeader(map, "avail-dictionary", &value))
    181       return false;
    182     return value == dictionary_client_hash_;
    183   }
    184 
    185   scoped_ptr<net::test_server::HttpResponse> HandleRequest(
    186       const net::test_server::HttpRequest& request) {
    187     request_vector_.push_back(request);
    188 
    189     scoped_ptr<net::test_server::BasicHttpResponse> response(
    190         new net::test_server::BasicHttpResponse);
    191     if (request.relative_url == kDataURLPath) {
    192       if (ShouldRespondWithSdchEncoding(request.headers)) {
    193         // Note that chrome doesn't advertise accepting SDCH encoding
    194         // for POSTs (because the meta-refresh hack would break a POST),
    195         // but that's not for the server to enforce.
    196         DCHECK_NE(encoded_data_, "");
    197         response->set_content_type("text/html");
    198         response->set_content(encoded_data_);
    199         response->AddCustomHeader("Content-Encoding", "sdch");
    200         // We allow tests to set caching on the sdch response,
    201         // so that we can force an encoded response with no
    202         // dictionary.
    203         if (cache_sdch_response_)
    204           response->AddCustomHeader("Cache-Control", "max-age=3600");
    205         else
    206           response->AddCustomHeader("Cache-Control", "no-store");
    207       } else {
    208         response->set_content_type("text/plain");
    209         response->set_content(kSampleData);
    210         if (ClientIsAdvertisingSdchEncoding(request.headers))
    211           response->AddCustomHeader("Get-Dictionary", kDictionaryURLPath);
    212         // We never cache the plain data response, to make it
    213         // easy to refresh after we get the dictionary.
    214         response->AddCustomHeader("Cache-Control", "no-store");
    215       }
    216     } else {
    217       DCHECK_EQ(request.relative_url, kDictionaryURLPath);
    218       DCHECK_NE(sdch_dictionary_contents_, "");
    219       response->set_content_type("application/x-sdch-dictionary");
    220       response->set_content(sdch_dictionary_contents_);
    221     }
    222     std::vector<base::Closure> callbacks;
    223     callbacks.swap(callback_vector_);
    224     for (std::vector<base::Closure>::iterator it = callbacks.begin();
    225          it != callbacks.end(); ++it) {
    226       it->Run();
    227     }
    228     return response.PassAs<net::test_server::HttpResponse>();
    229   }
    230 
    231   void WaitAndGetRequestVector(int num_requests,
    232                                base::Closure callback,
    233                                RequestVector* v) {
    234     DCHECK_LT(0, num_requests);
    235     if (static_cast<size_t>(num_requests) > request_vector_.size()) {
    236       callback_vector_.push_back(
    237           base::Bind(&SdchResponseHandler::WaitAndGetRequestVector,
    238                      weak_ptr_factory_.GetWeakPtr(), num_requests,
    239                      callback, v));
    240       return;
    241     }
    242     *v = request_vector_;
    243     content::BrowserThread::PostTask(
    244         content::BrowserThread::UI, FROM_HERE, callback);
    245   }
    246 
    247   void set_cache_sdch_response(bool cache_sdch_response) {
    248     cache_sdch_response_ = cache_sdch_response;
    249   }
    250 
    251  private:
    252   bool cache_sdch_response_;
    253   std::string encoded_data_;
    254   std::string sdch_dictionary_contents_;
    255   std::string dictionary_client_hash_;
    256   std::string dictionary_server_hash_;
    257   RequestVector request_vector_;
    258   std::vector<base::Closure> callback_vector_;
    259   base::WeakPtrFactory<SdchResponseHandler> weak_ptr_factory_;
    260 };
    261 
    262 class SdchBrowserTest : public InProcessBrowserTest, net::URLFetcherDelegate {
    263  public:
    264   static const char kTestHost[];
    265 
    266   SdchBrowserTest()
    267       : response_handler_(kTestHost),
    268         url_request_context_getter_(NULL),
    269         url_fetch_complete_(false),
    270         waiting_(false) {}
    271 
    272   // Helper functions for fetching data.
    273 
    274   void FetchUrlDetailed(GURL url, net::URLRequestContextGetter* getter) {
    275     url_fetch_complete_ = false;
    276     fetcher_.reset(net::URLFetcher::Create(url, net::URLFetcher::GET, this));
    277     fetcher_->SetRequestContext(getter);
    278     fetcher_->Start();
    279     if (!url_fetch_complete_) {
    280       waiting_ = true;
    281       content::RunMessageLoop();
    282       waiting_ = false;
    283     }
    284     CHECK(url_fetch_complete_);
    285   }
    286 
    287   void FetchUrl(GURL url) {
    288     FetchUrlDetailed(url, url_request_context_getter_.get());
    289   }
    290 
    291   const net::URLRequestStatus& FetcherStatus() const {
    292     return fetcher_->GetStatus();
    293   }
    294 
    295   int FetcherResponseCode() const {
    296     return (fetcher_->GetStatus().status() == net::URLRequestStatus::SUCCESS ?
    297             fetcher_->GetResponseCode() : 0);
    298   }
    299 
    300   const net::HttpResponseHeaders* FetcherResponseHeaders() const {
    301     return (fetcher_->GetStatus().status() == net::URLRequestStatus::SUCCESS ?
    302             fetcher_->GetResponseHeaders() : NULL);
    303   }
    304 
    305   std::string FetcherResponseContents() const {
    306     std::string contents;
    307     if (fetcher_->GetStatus().status() == net::URLRequestStatus::SUCCESS)
    308       CHECK(fetcher_->GetResponseAsString(&contents));
    309     return contents;
    310   }
    311 
    312   // Get the data from the server.  Return value is success/failure of the
    313   // data operation, |*sdch_encoding_used| indicates whether or not the
    314   // data was retrieved with sdch encoding.
    315   // This is done through FetchUrl(), so the various helper functions
    316   // will have valid status if it returns successfully.
    317   bool GetDataDetailed(net::URLRequestContextGetter* getter,
    318                        bool* sdch_encoding_used) {
    319     FetchUrlDetailed(
    320         GURL(base::StringPrintf(
    321             "http://%s:%d%s", kTestHost, test_server_port(), kDataURLPath)),
    322         getter);
    323     EXPECT_EQ(net::URLRequestStatus::SUCCESS, FetcherStatus().status())
    324         << "Error code is " << FetcherStatus().error();
    325     EXPECT_EQ(200, FetcherResponseCode());
    326     EXPECT_EQ(kSampleData, FetcherResponseContents());
    327 
    328     if (net::URLRequestStatus::SUCCESS != FetcherStatus().status() ||
    329         200 != FetcherResponseCode()) {
    330       *sdch_encoding_used = false;
    331       return false;
    332     }
    333 
    334     *sdch_encoding_used =
    335         FetcherResponseHeaders()->HasHeaderValue("Content-Encoding", "sdch");
    336 
    337     if (FetcherResponseContents() != kSampleData)
    338       return false;
    339 
    340     return true;
    341   }
    342 
    343   bool GetData(bool* sdch_encoding_used) {
    344     return GetDataDetailed(url_request_context_getter_.get(),
    345                            sdch_encoding_used);
    346   }
    347 
    348   // Client information and control.
    349 
    350   int GetNumberOfDictionaryFetches(Profile* profile) {
    351     int fetches = -1;
    352     base::RunLoop run_loop;
    353     content::BrowserThread::PostTaskAndReply(
    354         content::BrowserThread::IO, FROM_HERE,
    355         base::Bind(&SdchBrowserTest::GetNumberOfDictionaryFetchesOnIOThread,
    356                    base::Unretained(profile->GetRequestContext()),
    357                    &fetches),
    358         run_loop.QuitClosure());
    359     run_loop.Run();
    360     DCHECK_NE(-1, fetches);
    361     return fetches;
    362   }
    363 
    364   void BrowsingDataRemoveAndWait(int remove_mask) {
    365     BrowsingDataRemover* remover = BrowsingDataRemover::CreateForPeriod(
    366         browser()->profile(), BrowsingDataRemover::LAST_HOUR);
    367     BrowsingDataRemoverCompletionObserver completion_observer(remover);
    368     remover->Remove(remove_mask, BrowsingDataHelper::UNPROTECTED_WEB);
    369     completion_observer.BlockUntilCompletion();
    370   }
    371 
    372   // Something of a cheat; nuke the dictionaries off the SdchManager without
    373   // touching the cache (which browsing data remover would do).
    374   void NukeSdchDictionaries() {
    375     base::RunLoop run_loop;
    376     content::BrowserThread::PostTaskAndReply(
    377         content::BrowserThread::IO, FROM_HERE,
    378         base::Bind(&SdchBrowserTest::NukeSdchDictionariesOnIOThread,
    379                    url_request_context_getter_),
    380         run_loop.QuitClosure());
    381     run_loop.Run();
    382   }
    383 
    384   // Create a second browser based on a second profile to work within
    385   // multi-profile.
    386   bool SetupSecondBrowser() {
    387     base::FilePath user_data_dir;
    388     PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
    389 
    390     if (!second_profile_data_dir_.CreateUniqueTempDirUnderPath(user_data_dir))
    391       return false;
    392 
    393     second_profile_ = g_browser_process->profile_manager()->GetProfile(
    394         second_profile_data_dir_.path());
    395     if (!second_profile_) return false;
    396 
    397     second_browser_ = new Browser(Browser::CreateParams(
    398         second_profile_, browser()->host_desktop_type()));
    399     if (!second_browser_) return false;
    400 
    401     chrome::AddSelectedTabWithURL(second_browser_,
    402                                   GURL(url::kAboutBlankURL),
    403                                   ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
    404     content::WaitForLoadStop(
    405         second_browser_->tab_strip_model()->GetActiveWebContents());
    406     second_browser_->window()->Show();
    407 
    408     return true;
    409   }
    410 
    411   Browser* second_browser() { return second_browser_; }
    412 
    413   // Server information and control.
    414 
    415   void WaitAndGetTestVector(int num_requests, RequestVector* result) {
    416     base::RunLoop run_loop;
    417     content::BrowserThread::PostTask(
    418         content::BrowserThread::IO, FROM_HERE,
    419         base::Bind(&SdchResponseHandler::WaitAndGetRequestVector,
    420                    base::Unretained(&response_handler_),
    421                    num_requests,
    422                    run_loop.QuitClosure(),
    423                    result));
    424     run_loop.Run();
    425   }
    426 
    427   int test_server_port() { return test_server_.port(); }
    428 
    429   void SetSdchCacheability(bool cache_sdch_response) {
    430     base::RunLoop run_loop;
    431     content::BrowserThread::PostTaskAndReply(
    432         content::BrowserThread::IO, FROM_HERE,
    433         base::Bind(&SdchResponseHandler::set_cache_sdch_response,
    434                    base::Unretained(&response_handler_),
    435                    cache_sdch_response),
    436         run_loop.QuitClosure());
    437     run_loop.Run();
    438   }
    439 
    440   // Helper function for common test pattern.
    441   //
    442   // This function gets the data, confirms that the initial sending of the
    443   // data included a dictionary advertisement, that that advertisement
    444   // resulted in queueing a dictionary fetch, forces that fetch to
    445   // go through, and confirms that a follow-on data load uses SDCH
    446   // encoding.  Returns true if the entire sequence of events occurred.
    447   bool ForceSdchDictionaryLoad(Browser* browser) {
    448     bool sdch_encoding_used = true;
    449     bool data_gotten = GetDataDetailed(
    450         browser->profile()->GetRequestContext(), &sdch_encoding_used);
    451     EXPECT_TRUE(data_gotten);
    452     if (!data_gotten) return false;
    453     EXPECT_FALSE(sdch_encoding_used);
    454 
    455     // Confirm that we were told to get the dictionary
    456     const net::HttpResponseHeaders* headers = FetcherResponseHeaders();
    457     std::string value;
    458     bool have_dict_header =
    459         headers->EnumerateHeader(NULL, "Get-Dictionary", &value);
    460     EXPECT_TRUE(have_dict_header);
    461     if (!have_dict_header) return false;
    462 
    463     // If the above didn't result in a dictionary fetch being queued, the
    464     // rest of the test will time out.  Avoid that.
    465     int num_fetches = GetNumberOfDictionaryFetches(browser->profile());
    466     EXPECT_EQ(1, num_fetches);
    467     if (1 != num_fetches) return false;
    468 
    469     // Wait until the dictionary fetch actually happens.
    470     RequestVector request_vector;
    471     WaitAndGetTestVector(2, &request_vector);
    472     EXPECT_EQ(request_vector[1].relative_url, kDictionaryURLPath);
    473     if (request_vector[1].relative_url != kDictionaryURLPath) return false;
    474 
    475     // Do a round trip to the server ignoring the encoding, presuming
    476     // that if we've gotten data to this thread, the dictionary's made
    477     // it into the SdchManager.
    478     data_gotten = GetDataDetailed(
    479         browser->profile()->GetRequestContext(), &sdch_encoding_used);
    480     EXPECT_TRUE(data_gotten);
    481     if (!data_gotten) return false;
    482 
    483     // Now data fetches should be SDCH encoded.
    484     sdch_encoding_used = false;
    485     data_gotten = GetDataDetailed(
    486         browser->profile()->GetRequestContext(), &sdch_encoding_used);
    487     EXPECT_TRUE(data_gotten);
    488     EXPECT_TRUE(sdch_encoding_used);
    489 
    490     if (!data_gotten || !sdch_encoding_used) return false;
    491 
    492     // Confirm the request vector looks at this point as expected.
    493     WaitAndGetTestVector(4, &request_vector);
    494     EXPECT_EQ(4u, request_vector.size());
    495     EXPECT_EQ(request_vector[2].relative_url, kDataURLPath);
    496     EXPECT_EQ(request_vector[3].relative_url, kDataURLPath);
    497     return (4u == request_vector.size() &&
    498             request_vector[2].relative_url == kDataURLPath &&
    499             request_vector[3].relative_url == kDataURLPath);
    500   }
    501 
    502  private:
    503   static void NukeSdchDictionariesOnIOThread(
    504       net::URLRequestContextGetter* context_getter) {
    505     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
    506     net::SdchManager* sdch_manager =
    507         context_getter->GetURLRequestContext()->sdch_manager();
    508     DCHECK(sdch_manager);
    509     sdch_manager->ClearData();
    510   }
    511 
    512   static void GetNumberOfDictionaryFetchesOnIOThread(
    513       net::URLRequestContextGetter* url_request_context_getter,
    514       int* result) {
    515     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
    516     net::SdchManager* sdch_manager =
    517         url_request_context_getter->GetURLRequestContext()->sdch_manager();
    518     DCHECK(sdch_manager);
    519     *result = sdch_manager->GetFetchesCountForTesting();
    520   }
    521 
    522   // InProcessBrowserTest
    523   virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
    524     command_line->AppendSwitchASCII(
    525         switches::kHostResolverRules,
    526         "MAP " + std::string(kTestHost) + " 127.0.0.1");
    527 #if defined(OS_CHROMEOS)
    528     command_line->AppendSwitch(
    529         chromeos::switches::kIgnoreUserProfileMappingForTests);
    530 #endif
    531   }
    532 
    533   virtual void SetUpOnMainThread() OVERRIDE {
    534     test_server_.RegisterRequestHandler(
    535         base::Bind(&SdchResponseHandler::HandleRequest,
    536                    base::Unretained(&response_handler_)));
    537     CHECK(test_server_.InitializeAndWaitUntilReady());
    538     url_request_context_getter_ = browser()->profile()->GetRequestContext();
    539   }
    540 
    541   virtual void TearDownOnMainThread() OVERRIDE {
    542     CHECK(test_server_.ShutdownAndWaitUntilComplete());
    543   }
    544 
    545   // URLFetcherDelegate
    546   virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
    547     url_fetch_complete_ = true;
    548     if (waiting_)
    549       base::MessageLoopForUI::current()->Quit();
    550   }
    551 
    552   SdchResponseHandler response_handler_;
    553   net::test_server::EmbeddedTestServer test_server_;
    554   scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
    555   scoped_ptr<net::URLFetcher> fetcher_;
    556   bool url_fetch_complete_;
    557   bool waiting_;
    558   base::ScopedTempDir second_profile_data_dir_;
    559   Profile* second_profile_;
    560   Browser* second_browser_;
    561 };
    562 
    563 const char SdchBrowserTest::kTestHost[] = "our.test.host.com";
    564 
    565 // Confirm that after getting a dictionary, calling the browsing
    566 // data remover renders it unusable.  Also (in calling
    567 // ForceSdchDictionaryLoad()) servers as a smoke test for SDCH.
    568 IN_PROC_BROWSER_TEST_F(SdchBrowserTest, BrowsingDataRemover) {
    569   ASSERT_TRUE(ForceSdchDictionaryLoad(browser()));
    570 
    571   // Confirm browsing data remover without removing the cache leaves
    572   // SDCH alone.
    573   BrowsingDataRemoveAndWait(BrowsingDataRemover::REMOVE_ALL &
    574                             ~BrowsingDataRemover::REMOVE_CACHE);
    575   bool sdch_encoding_used = false;
    576   ASSERT_TRUE(GetData(&sdch_encoding_used));
    577   EXPECT_TRUE(sdch_encoding_used);
    578 
    579   // Confirm browsing data remover removing the cache clears SDCH state.
    580   BrowsingDataRemoveAndWait(BrowsingDataRemover::REMOVE_CACHE);
    581   sdch_encoding_used = false;
    582   ASSERT_TRUE(GetData(&sdch_encoding_used));
    583   EXPECT_FALSE(sdch_encoding_used);
    584 }
    585 
    586 // Confirm dictionaries not visible in other profiles.
    587 IN_PROC_BROWSER_TEST_F(SdchBrowserTest, Isolation) {
    588   ASSERT_TRUE(ForceSdchDictionaryLoad(browser()));
    589   ASSERT_TRUE(SetupSecondBrowser());
    590 
    591   // Data fetches from incognito or separate profiles should not be SDCH
    592   // encoded.
    593   bool sdch_encoding_used = true;
    594   Browser* incognito_browser = CreateIncognitoBrowser();
    595   EXPECT_TRUE(GetDataDetailed(
    596       incognito_browser->profile()->GetRequestContext(),
    597       &sdch_encoding_used));
    598   EXPECT_FALSE(sdch_encoding_used);
    599 
    600   sdch_encoding_used = true;
    601   EXPECT_TRUE(GetDataDetailed(
    602       second_browser()->profile()->GetRequestContext(), &sdch_encoding_used));
    603   EXPECT_FALSE(sdch_encoding_used);
    604 }
    605 
    606 // Confirm a dictionary loaded in incognito isn't visible in the main profile.
    607 IN_PROC_BROWSER_TEST_F(SdchBrowserTest, ReverseIsolation) {
    608   Browser* incognito_browser = CreateIncognitoBrowser();
    609   ASSERT_TRUE(ForceSdchDictionaryLoad(incognito_browser));
    610 
    611   // Data fetches on main browser should not be SDCH encoded.
    612   bool sdch_encoding_used = true;
    613   ASSERT_TRUE(GetData(&sdch_encoding_used));
    614   EXPECT_FALSE(sdch_encoding_used);
    615 }
    616 
    617 }  // namespace
    618