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
52namespace {
53
54typedef std::vector<net::test_server::HttpRequest> RequestVector;
55typedef std::map<std::string, std::string> HttpRequestHeaderMap;
56
57// Credit Alfred, Lord Tennyson
58static 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 foreheads—you 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.
90static 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
98static const char kDictionaryURLPath[] = "/dict";
99static 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.
105bool 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.
120void 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.
130class 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
262class 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
563const 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.
568IN_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.
587IN_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.
607IN_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