blob: 49abbaf1f14986f675a23707345b1ee40da8d381 [file] [log] [blame]
[email protected]33acd5b2014-08-19 19:56:221// 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 }
dcheng0f3f5252014-10-16 19:36:46228 return response.Pass();
[email protected]33acd5b2014-08-19 19:56:22229 }
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) {
dcheng758c95c2014-08-26 22:07:37288 FetchUrlDetailed(url, url_request_context_getter_.get());
[email protected]33acd5b2014-08-19 19:56:22289 }
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) {
dcheng758c95c2014-08-26 22:07:37344 return GetDataDetailed(url_request_context_getter_.get(),
345 sdch_encoding_used);
[email protected]33acd5b2014-08-19 19:56:22346 }
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),
Sylvain Defresnec6ccc77d2014-09-19 10:19:35403 ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
[email protected]33acd5b2014-08-19 19:56:22404 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
mostynb2b52d1db2014-10-07 02:47:17523 virtual void SetUpCommandLine(base::CommandLine* command_line) override {
[email protected]33acd5b2014-08-19 19:56:22524 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
mostynb2b52d1db2014-10-07 02:47:17533 virtual void SetUpOnMainThread() override {
[email protected]33acd5b2014-08-19 19:56:22534 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
mostynb2b52d1db2014-10-07 02:47:17541 virtual void TearDownOnMainThread() override {
[email protected]33acd5b2014-08-19 19:56:22542 CHECK(test_server_.ShutdownAndWaitUntilComplete());
543 }
544
545 // URLFetcherDelegate
mostynb2b52d1db2014-10-07 02:47:17546 virtual void OnURLFetchComplete(const net::URLFetcher* source) override {
[email protected]33acd5b2014-08-19 19:56:22547 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