blob: 0966cc4e5c467a77336d63cd913742fdaeff08f0 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// End-to-end SDCH tests. Uses the embedded test server to return SDCH
// results
#include <stddef.h>
#include <stdint.h>
#include <utility>
#include "base/base64.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/weak_ptr.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/string_tokenizer.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browsing_data/browsing_data_helper.h"
#include "chrome/browser/browsing_data/browsing_data_remover.h"
#include "chrome/browser/browsing_data/browsing_data_remover_factory.h"
#include "chrome/browser/browsing_data/browsing_data_remover_test_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/browsing_data/core/browsing_data_utils.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "crypto/sha2.h"
#include "net/base/sdch_manager.h"
#include "net/base/sdch_observer.h"
#include "net/http/http_response_headers.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "sdch/open-vcdiff/src/google/vcencoder.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_CHROMEOS)
#include "chromeos/chromeos_switches.h"
#endif
namespace {
typedef std::vector<net::test_server::HttpRequest> RequestVector;
typedef net::test_server::HttpRequest::HeaderMap HttpRequestHeaderMap;
// Credit Alfred, Lord Tennyson
static const char kSampleData[] = "<html><body><pre>"
"There lies the port; the vessel puffs her sail:\n"
"There gloom the dark, broad seas. My mariners,\n"
"Souls that have toil'd, and wrought, and thought with me—\n"
"That ever with a frolic welcome took\n"
"The thunder and the sunshine, and opposed\n"
"Free hearts, free foreheads—you and I are old;\n"
"Old age hath yet his honour and his toil;\n"
"Death closes all: but something ere the end,\n"
"Some work of noble note, may yet be done,\n"
"Not unbecoming men that strove with Gods.\n"
"The lights begin to twinkle from the rocks:\n"
"The long day wanes: the slow moon climbs: the deep\n"
"Moans round with many voices. Come, my friends,\n"
"'T is not too late to seek a newer world.\n"
"Push off, and sitting well in order smite\n"
"The sounding furrows; for my purpose holds\n"
"To sail beyond the sunset, and the baths\n"
"Of all the western stars, until I die.\n"
"It may be that the gulfs will wash us down:\n"
"It may be we shall touch the Happy Isles,\n"
"And see the great Achilles, whom we knew.\n"
"Tho' much is taken, much abides; and tho'\n"
"We are not now that strength which in old days\n"
"Moved earth and heaven, that which we are, we are;\n"
"One equal temper of heroic hearts,\n"
"Made weak by time and fate, but strong in will\n"
"To strive, to seek, to find, and not to yield.\n"
"</pre></body></html>";
// Random selection of lines from above, to allow some encoding, but
// not a trivial encoding.
static const char kDictionaryContents[] =
"The thunder and the sunshine, and opposed\n"
"To sail beyond the sunset, and the baths\n"
"Of all the western stars, until I die.\n"
"Made weak by time and fate, but strong in will\n"
"Moans round with many voices. Come, my friends,\n"
"The lights begin to twinkle from the rocks:";
static const char kDictionaryURLPath[] = "/dict";
static const char kDataURLPath[] = "/data";
// Scans in a case-insensitive way for |header| in |map|,
// returning true if found and setting |*value| to the value
// of that header. Does not handle multiple instances of the same
// header.
bool GetRequestHeader(const HttpRequestHeaderMap& map,
const char* header,
std::string* value) {
for (HttpRequestHeaderMap::const_iterator it = map.begin();
it != map.end(); ++it) {
if (base::EqualsCaseInsensitiveASCII(it->first, header)) {
*value = it->second;
return true;
}
}
return false;
}
// Do a URL-safe base64 encoding. See the SDCH spec "Dictionary Identifier"
// section, and RFC 3548 section 4.
void SafeBase64Encode(const std::string& input_value, std::string* output) {
DCHECK(output);
base::Base64Encode(input_value, output);
std::replace(output->begin(), output->end(), '+', '-');
std::replace(output->begin(), output->end(), '/', '_');
}
// Class that bundles responses for an EmbeddedTestServer().
// Dictionary is at <domain>/dict, data at <domain>/data.
// The data is sent SDCH encoded if that's allowed by protoocol.
class SdchResponseHandler {
public:
// Do initial preparation so that SDCH requests can be handled.
explicit SdchResponseHandler(const std::string& domain)
: cache_sdch_response_(false), weak_ptr_factory_(this) {
// Dictionary
sdch_dictionary_contents_ = "Domain: ";
sdch_dictionary_contents_ += domain;
sdch_dictionary_contents_ += "\n\n";
sdch_dictionary_contents_ += kDictionaryContents;
// Dictionary hash for client and server.
char binary_hash[32];
crypto::SHA256HashString(sdch_dictionary_contents_, binary_hash,
sizeof(binary_hash));
SafeBase64Encode(std::string(&binary_hash[0], 6), &dictionary_client_hash_);
SafeBase64Encode(std::string(&binary_hash[6], 6), &dictionary_server_hash_);
// Encoded response.
open_vcdiff::HashedDictionary vcdiff_dictionary(
kDictionaryContents, strlen(kDictionaryContents));
bool result = vcdiff_dictionary.Init();
DCHECK(result);
open_vcdiff::VCDiffStreamingEncoder encoder(&vcdiff_dictionary, 0, false);
encoded_data_ = dictionary_server_hash_;
encoded_data_ += '\0';
result = encoder.StartEncoding(&encoded_data_);
DCHECK(result);
result = encoder.EncodeChunk(
kSampleData, strlen(kSampleData), &encoded_data_);
DCHECK(result);
result = encoder.FinishEncoding(&encoded_data_);
DCHECK(result);
}
static bool ClientIsAdvertisingSdchEncoding(const HttpRequestHeaderMap& map) {
std::string value;
if (!GetRequestHeader(map, "accept-encoding", &value))
return false;
base::StringTokenizer tokenizer(value, " ,");
while (tokenizer.GetNext()) {
if (base::EqualsCaseInsensitiveASCII(tokenizer.token(), "sdch"))
return true;
}
return false;
}
bool ShouldRespondWithSdchEncoding(const HttpRequestHeaderMap& map) {
std::string value;
if (!GetRequestHeader(map, "avail-dictionary", &value))
return false;
return value == dictionary_client_hash_;
}
std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
const net::test_server::HttpRequest& request) {
request_vector_.push_back(request);
std::unique_ptr<net::test_server::BasicHttpResponse> response(
new net::test_server::BasicHttpResponse);
if (request.relative_url == kDataURLPath) {
if (ShouldRespondWithSdchEncoding(request.headers)) {
// Note that chrome doesn't advertise accepting SDCH encoding
// for POSTs (because the meta-refresh hack would break a POST),
// but that's not for the server to enforce.
DCHECK_NE(encoded_data_, "");
response->set_content_type("text/html");
response->set_content(encoded_data_);
response->AddCustomHeader("Content-Encoding", "sdch");
// We allow tests to set caching on the sdch response,
// so that we can force an encoded response with no
// dictionary.
if (cache_sdch_response_)
response->AddCustomHeader("Cache-Control", "max-age=3600");
else
response->AddCustomHeader("Cache-Control", "no-store");
} else {
response->set_content_type("text/plain");
response->set_content(kSampleData);
if (ClientIsAdvertisingSdchEncoding(request.headers))
response->AddCustomHeader("Get-Dictionary", kDictionaryURLPath);
// We never cache the plain data response, to make it
// easy to refresh after we get the dictionary.
response->AddCustomHeader("Cache-Control", "no-store");
}
} else {
DCHECK_EQ(request.relative_url, kDictionaryURLPath);
DCHECK_NE(sdch_dictionary_contents_, "");
response->AddCustomHeader("Cache-Control", "max-age=3600");
response->set_content_type("application/x-sdch-dictionary");
response->set_content(sdch_dictionary_contents_);
}
std::vector<base::Closure> callbacks;
callbacks.swap(callback_vector_);
for (std::vector<base::Closure>::iterator it = callbacks.begin();
it != callbacks.end(); ++it) {
it->Run();
}
return std::move(response);
}
void WaitAndGetRequestVector(int num_requests,
base::Closure callback,
RequestVector* v) {
DCHECK_LT(0, num_requests);
if (static_cast<size_t>(num_requests) > request_vector_.size()) {
callback_vector_.push_back(
base::Bind(&SdchResponseHandler::WaitAndGetRequestVector,
weak_ptr_factory_.GetWeakPtr(), num_requests,
callback, v));
return;
}
*v = request_vector_;
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE, callback);
}
void set_cache_sdch_response(bool cache_sdch_response) {
cache_sdch_response_ = cache_sdch_response;
}
private:
bool cache_sdch_response_;
std::string encoded_data_;
std::string sdch_dictionary_contents_;
std::string dictionary_client_hash_;
std::string dictionary_server_hash_;
RequestVector request_vector_;
std::vector<base::Closure> callback_vector_;
base::WeakPtrFactory<SdchResponseHandler> weak_ptr_factory_;
};
class TestSdchObserver : public net::SdchObserver {
public:
TestSdchObserver() : manager_(nullptr), fetch_count_(0) {}
~TestSdchObserver() override {
if (manager_) {
manager_->RemoveObserver(this);
}
}
void Observe(net::SdchManager* manager) {
DCHECK(!manager_);
manager_ = manager;
manager_->AddObserver(this);
}
// SdchObserver
void OnDictionaryAdded(const GURL& /* dictionary_url */,
const std::string& /* server_hash */) override {}
void OnDictionaryRemoved(const std::string& /* server_hash */) override {}
void OnGetDictionary(const GURL& /* request_url */,
const GURL& /* dictionary_url */) override {
fetch_count_++;
}
void OnDictionaryUsed(const std::string& /* server_hash */) override {}
void OnClearDictionaries() override {}
int fetch_count() const { return fetch_count_; }
private:
net::SdchManager* manager_;
int fetch_count_;
};
class SdchBrowserTest : public InProcessBrowserTest,
public net::URLFetcherDelegate {
public:
static const char kTestHost[];
SdchBrowserTest()
: response_handler_(kTestHost),
url_request_context_getter_(NULL),
url_fetch_complete_(false),
waiting_(false) {}
// Helper functions for fetching data.
void FetchUrlDetailed(GURL url, net::URLRequestContextGetter* getter) {
url_fetch_complete_ = false;
fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this);
fetcher_->SetRequestContext(getter);
fetcher_->Start();
if (!url_fetch_complete_) {
waiting_ = true;
content::RunMessageLoop();
waiting_ = false;
}
CHECK(url_fetch_complete_);
}
void FetchUrl(GURL url) {
FetchUrlDetailed(url, url_request_context_getter_.get());
}
const net::URLRequestStatus& FetcherStatus() const {
return fetcher_->GetStatus();
}
int FetcherResponseCode() const {
return (fetcher_->GetStatus().status() == net::URLRequestStatus::SUCCESS ?
fetcher_->GetResponseCode() : 0);
}
const net::HttpResponseHeaders* FetcherResponseHeaders() const {
return (fetcher_->GetStatus().status() == net::URLRequestStatus::SUCCESS ?
fetcher_->GetResponseHeaders() : NULL);
}
std::string FetcherResponseContents() const {
std::string contents;
if (fetcher_->GetStatus().status() == net::URLRequestStatus::SUCCESS)
CHECK(fetcher_->GetResponseAsString(&contents));
return contents;
}
// Get the data from the server. Return value is success/failure of the
// data operation, |*sdch_encoding_used| indicates whether or not the
// data was retrieved with sdch encoding.
// This is done through FetchUrl(), so the various helper functions
// will have valid status if it returns successfully.
bool GetDataDetailed(net::URLRequestContextGetter* getter,
bool* sdch_encoding_used) {
FetchUrlDetailed(
GURL(base::StringPrintf(
"http://%s:%u%s", kTestHost, test_server_port(), kDataURLPath)),
getter);
EXPECT_EQ(net::URLRequestStatus::SUCCESS, FetcherStatus().status())
<< "Error code is " << FetcherStatus().error();
EXPECT_EQ(200, FetcherResponseCode());
EXPECT_EQ(kSampleData, FetcherResponseContents());
if (net::URLRequestStatus::SUCCESS != FetcherStatus().status() ||
200 != FetcherResponseCode()) {
*sdch_encoding_used = false;
return false;
}
*sdch_encoding_used =
FetcherResponseHeaders()->HasHeaderValue("Content-Encoding", "sdch");
if (FetcherResponseContents() != kSampleData)
return false;
return true;
}
bool GetData(bool* sdch_encoding_used) {
return GetDataDetailed(url_request_context_getter_.get(),
sdch_encoding_used);
}
// Client information and control.
int GetNumberOfDictionaryFetches(Profile* profile) {
int fetches = -1;
base::RunLoop run_loop;
content::BrowserThread::PostTaskAndReply(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(&SdchBrowserTest::GetNumberOfDictionaryFetchesOnIOThread,
base::Unretained(this),
base::Unretained(profile->GetRequestContext()),
&fetches),
run_loop.QuitClosure());
run_loop.Run();
DCHECK_NE(-1, fetches);
return fetches;
}
void BrowsingDataRemoveAndWait(int remove_mask) {
BrowsingDataRemover* remover =
BrowsingDataRemoverFactory::GetForBrowserContext(browser()->profile());
BrowsingDataRemoverCompletionObserver completion_observer(remover);
remover->RemoveAndReply(browsing_data::CalculateBeginDeleteTime(
browsing_data::TimePeriod::LAST_HOUR),
browsing_data::CalculateEndDeleteTime(
browsing_data::TimePeriod::LAST_HOUR),
remove_mask, BrowsingDataHelper::UNPROTECTED_WEB,
&completion_observer);
completion_observer.BlockUntilCompletion();
}
// Something of a cheat; nuke the dictionaries off the SdchManager without
// touching the cache (which browsing data remover would do).
void NukeSdchDictionaries() {
base::RunLoop run_loop;
content::BrowserThread::PostTaskAndReply(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&SdchBrowserTest::NukeSdchDictionariesOnIOThread,
base::RetainedRef(url_request_context_getter_)),
run_loop.QuitClosure());
run_loop.Run();
}
// Create a second browser based on a second profile to work within
// multi-profile.
bool SetupSecondBrowser() {
base::FilePath user_data_dir;
PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
if (!second_profile_data_dir_.CreateUniqueTempDirUnderPath(user_data_dir))
return false;
second_profile_ = g_browser_process->profile_manager()->GetProfile(
second_profile_data_dir_.GetPath());
if (!second_profile_) return false;
second_browser_ = new Browser(Browser::CreateParams(second_profile_, true));
if (!second_browser_) return false;
chrome::AddSelectedTabWithURL(second_browser_,
GURL(url::kAboutBlankURL),
ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
content::WaitForLoadStop(
second_browser_->tab_strip_model()->GetActiveWebContents());
second_browser_->window()->Show();
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&SdchBrowserTest::SubscribeToSdchNotifications,
base::Unretained(this),
base::RetainedRef(
second_browser_->profile()->GetRequestContext())));
return true;
}
bool SetupIncognitoBrowser() {
incognito_browser_ = CreateIncognitoBrowser();
if (!incognito_browser_)
return false;
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&SdchBrowserTest::SubscribeToSdchNotifications,
base::Unretained(this),
base::RetainedRef(
incognito_browser_->profile()->GetRequestContext())));
return true;
}
Browser* second_browser() { return second_browser_; }
Browser* incognito_browser() { return incognito_browser_; }
// Server information and control.
void WaitAndGetTestVector(int num_requests, RequestVector* result) {
base::RunLoop run_loop;
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&SdchResponseHandler::WaitAndGetRequestVector,
base::Unretained(&response_handler_),
num_requests,
run_loop.QuitClosure(),
result));
run_loop.Run();
}
uint16_t test_server_port() { return test_server_.port(); }
void SetSdchCacheability(bool cache_sdch_response) {
base::RunLoop run_loop;
content::BrowserThread::PostTaskAndReply(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&SdchResponseHandler::set_cache_sdch_response,
base::Unretained(&response_handler_),
cache_sdch_response),
run_loop.QuitClosure());
run_loop.Run();
}
// Helper function for common test pattern.
//
// This function gets the data, confirms that the initial sending of the
// data included a dictionary advertisement, that that advertisement
// resulted in queueing a dictionary fetch, forces that fetch to
// go through, and confirms that a follow-on data load uses SDCH
// encoding. Returns true if the entire sequence of events occurred.
bool ForceSdchDictionaryLoad(Browser* browser) {
bool sdch_encoding_used = true;
bool data_gotten = GetDataDetailed(
browser->profile()->GetRequestContext(), &sdch_encoding_used);
EXPECT_TRUE(data_gotten);
if (!data_gotten) return false;
EXPECT_FALSE(sdch_encoding_used);
// Confirm that we were told to get the dictionary
const net::HttpResponseHeaders* headers = FetcherResponseHeaders();
std::string value;
bool have_dict_header =
headers->EnumerateHeader(NULL, "Get-Dictionary", &value);
EXPECT_TRUE(have_dict_header);
if (!have_dict_header) return false;
// If the above didn't result in a dictionary fetch being queued, the
// rest of the test will time out. Avoid that.
int num_fetches = GetNumberOfDictionaryFetches(browser->profile());
EXPECT_EQ(1, num_fetches);
if (1 != num_fetches) return false;
// Wait until the dictionary fetch actually happens.
RequestVector request_vector;
WaitAndGetTestVector(2, &request_vector);
EXPECT_EQ(request_vector[1].relative_url, kDictionaryURLPath);
if (request_vector[1].relative_url != kDictionaryURLPath) return false;
// Do a round trip to the server ignoring the encoding, presuming
// that if we've gotten data to this thread, the dictionary's made
// it into the SdchManager.
data_gotten = GetDataDetailed(
browser->profile()->GetRequestContext(), &sdch_encoding_used);
EXPECT_TRUE(data_gotten);
if (!data_gotten) return false;
// Now data fetches should be SDCH encoded.
sdch_encoding_used = false;
data_gotten = GetDataDetailed(
browser->profile()->GetRequestContext(), &sdch_encoding_used);
EXPECT_TRUE(data_gotten);
EXPECT_TRUE(sdch_encoding_used);
if (!data_gotten || !sdch_encoding_used) return false;
// Confirm the request vector looks at this point as expected.
WaitAndGetTestVector(4, &request_vector);
EXPECT_EQ(4u, request_vector.size());
EXPECT_EQ(request_vector[2].relative_url, kDataURLPath);
EXPECT_EQ(request_vector[3].relative_url, kDataURLPath);
return (4u == request_vector.size() &&
request_vector[2].relative_url == kDataURLPath &&
request_vector[3].relative_url == kDataURLPath);
}
private:
static void NukeSdchDictionariesOnIOThread(
net::URLRequestContextGetter* context_getter) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
net::SdchManager* sdch_manager =
context_getter->GetURLRequestContext()->sdch_manager();
DCHECK(sdch_manager);
sdch_manager->ClearData();
}
void GetNumberOfDictionaryFetchesOnIOThread(
net::URLRequestContextGetter* context_getter,
int* result) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
net::SdchManager* manager(
context_getter->GetURLRequestContext()->sdch_manager());
DCHECK(observers_.end() != observers_.find(manager));
*result = observers_[manager].fetch_count();
}
// InProcessBrowserTest
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitchASCII(
switches::kHostResolverRules,
"MAP " + std::string(kTestHost) + " 127.0.0.1");
#if defined(OS_CHROMEOS)
command_line->AppendSwitch(
chromeos::switches::kIgnoreUserProfileMappingForTests);
#endif
}
void SetUpOnMainThread() override {
test_server_.RegisterRequestHandler(
base::Bind(&SdchResponseHandler::HandleRequest,
base::Unretained(&response_handler_)));
CHECK(test_server_.Start());
url_request_context_getter_ = browser()->profile()->GetRequestContext();
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&SdchBrowserTest::SubscribeToSdchNotifications,
base::Unretained(this),
base::RetainedRef(url_request_context_getter_)));
}
void TearDownOnMainThread() override {
CHECK(test_server_.ShutdownAndWaitUntilComplete());
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(&SdchBrowserTest::UnsubscribeFromAllSdchNotifications,
base::Unretained(this)));
}
void SubscribeToSdchNotifications(
net::URLRequestContextGetter* context_getter) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
net::SdchManager* manager =
context_getter->GetURLRequestContext()->sdch_manager();
DCHECK(observers_.end() == observers_.find(manager));
observers_[manager].Observe(manager);
}
void UnsubscribeFromAllSdchNotifications() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
observers_.clear();
}
// URLFetcherDelegate
void OnURLFetchComplete(const net::URLFetcher* source) override {
url_fetch_complete_ = true;
if (waiting_)
base::MessageLoopForUI::current()->QuitWhenIdle();
}
SdchResponseHandler response_handler_;
net::EmbeddedTestServer test_server_;
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
std::unique_ptr<net::URLFetcher> fetcher_;
bool url_fetch_complete_;
bool waiting_;
base::ScopedTempDir second_profile_data_dir_;
Profile* second_profile_;
Browser* second_browser_;
Browser* incognito_browser_;
// IO Thread access only.
std::map<net::SdchManager*, TestSdchObserver> observers_;
};
const char SdchBrowserTest::kTestHost[] = "our.test.host.com";
// Confirm that after getting a dictionary, calling the browsing
// data remover renders it unusable. Also (in calling
// ForceSdchDictionaryLoad()) servers as a smoke test for SDCH.
IN_PROC_BROWSER_TEST_F(SdchBrowserTest, BrowsingDataRemover) {
ASSERT_TRUE(ForceSdchDictionaryLoad(browser()));
// Confirm browsing data remover without removing the cache leaves
// SDCH alone.
BrowsingDataRemoveAndWait(BrowsingDataRemover::REMOVE_ALL &
~BrowsingDataRemover::REMOVE_CACHE);
bool sdch_encoding_used = false;
ASSERT_TRUE(GetData(&sdch_encoding_used));
EXPECT_TRUE(sdch_encoding_used);
// Confirm browsing data remover removing the cache clears SDCH state.
BrowsingDataRemoveAndWait(BrowsingDataRemover::REMOVE_CACHE);
sdch_encoding_used = false;
ASSERT_TRUE(GetData(&sdch_encoding_used));
EXPECT_FALSE(sdch_encoding_used);
}
// Confirm dictionaries not visible in other profiles.
IN_PROC_BROWSER_TEST_F(SdchBrowserTest, Isolation) {
ASSERT_TRUE(ForceSdchDictionaryLoad(browser()));
ASSERT_TRUE(SetupSecondBrowser());
ASSERT_TRUE(SetupIncognitoBrowser());
// Data fetches from incognito or separate profiles should not be SDCH
// encoded.
bool sdch_encoding_used = true;
EXPECT_TRUE(
GetDataDetailed(incognito_browser()->profile()->GetRequestContext(),
&sdch_encoding_used));
EXPECT_FALSE(sdch_encoding_used);
sdch_encoding_used = true;
EXPECT_TRUE(GetDataDetailed(
second_browser()->profile()->GetRequestContext(), &sdch_encoding_used));
EXPECT_FALSE(sdch_encoding_used);
}
// Confirm a dictionary loaded in incognito isn't visible in the main profile.
IN_PROC_BROWSER_TEST_F(SdchBrowserTest, ReverseIsolation) {
ASSERT_TRUE(SetupIncognitoBrowser());
ASSERT_TRUE(ForceSdchDictionaryLoad(incognito_browser()));
// Data fetches on main browser should not be SDCH encoded.
bool sdch_encoding_used = true;
ASSERT_TRUE(GetData(&sdch_encoding_used));
EXPECT_FALSE(sdch_encoding_used);
}
} // namespace