Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / net / sdch_browsertest.cc
blob9c93d6b841dda2a74a62edc80a7e47aa3af5d16e
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.
5 // End-to-end SDCH tests. Uses the embedded test server to return SDCH
6 // results
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/base/sdch_observer.h"
38 #include "net/http/http_response_headers.h"
39 #include "net/test/embedded_test_server/embedded_test_server.h"
40 #include "net/test/embedded_test_server/http_request.h"
41 #include "net/test/embedded_test_server/http_response.h"
42 #include "net/url_request/url_fetcher.h"
43 #include "net/url_request/url_fetcher_delegate.h"
44 #include "net/url_request/url_request_context.h"
45 #include "net/url_request/url_request_context_getter.h"
46 #include "sdch/open-vcdiff/src/google/vcencoder.h"
47 #include "testing/gtest/include/gtest/gtest.h"
49 #if defined(OS_CHROMEOS)
50 #include "chromeos/chromeos_switches.h"
51 #endif
53 namespace {
55 typedef std::vector<net::test_server::HttpRequest> RequestVector;
56 typedef std::map<std::string, std::string> HttpRequestHeaderMap;
58 // Credit Alfred, Lord Tennyson
59 static const char kSampleData[] = "<html><body><pre>"
60 "There lies the port; the vessel puffs her sail:\n"
61 "There gloom the dark, broad seas. My mariners,\n"
62 "Souls that have toil'd, and wrought, and thought with me—\n"
63 "That ever with a frolic welcome took\n"
64 "The thunder and the sunshine, and opposed\n"
65 "Free hearts, free foreheads—you and I are old;\n"
66 "Old age hath yet his honour and his toil;\n"
67 "Death closes all: but something ere the end,\n"
68 "Some work of noble note, may yet be done,\n"
69 "Not unbecoming men that strove with Gods.\n"
70 "The lights begin to twinkle from the rocks:\n"
71 "The long day wanes: the slow moon climbs: the deep\n"
72 "Moans round with many voices. Come, my friends,\n"
73 "'T is not too late to seek a newer world.\n"
74 "Push off, and sitting well in order smite\n"
75 "The sounding furrows; for my purpose holds\n"
76 "To sail beyond the sunset, and the baths\n"
77 "Of all the western stars, until I die.\n"
78 "It may be that the gulfs will wash us down:\n"
79 "It may be we shall touch the Happy Isles,\n"
80 "And see the great Achilles, whom we knew.\n"
81 "Tho' much is taken, much abides; and tho'\n"
82 "We are not now that strength which in old days\n"
83 "Moved earth and heaven, that which we are, we are;\n"
84 "One equal temper of heroic hearts,\n"
85 "Made weak by time and fate, but strong in will\n"
86 "To strive, to seek, to find, and not to yield.\n"
87 "</pre></body></html>";
89 // Random selection of lines from above, to allow some encoding, but
90 // not a trivial encoding.
91 static const char kDictionaryContents[] =
92 "The thunder and the sunshine, and opposed\n"
93 "To sail beyond the sunset, and the baths\n"
94 "Of all the western stars, until I die.\n"
95 "Made weak by time and fate, but strong in will\n"
96 "Moans round with many voices. Come, my friends,\n"
97 "The lights begin to twinkle from the rocks:";
99 static const char kDictionaryURLPath[] = "/dict";
100 static const char kDataURLPath[] = "/data";
102 // Scans in a case-insensitive way for |header| in |map|,
103 // returning true if found and setting |*value| to the value
104 // of that header. Does not handle multiple instances of the same
105 // header.
106 bool GetRequestHeader(const HttpRequestHeaderMap& map,
107 const char* header,
108 std::string* value) {
109 for (HttpRequestHeaderMap::const_iterator it = map.begin();
110 it != map.end(); ++it) {
111 if (base::EqualsCaseInsensitiveASCII(it->first, header)) {
112 *value = it->second;
113 return true;
116 return false;
119 // Do a URL-safe base64 encoding. See the SDCH spec "Dictionary Identifier"
120 // section, and RFC 3548 section 4.
121 void SafeBase64Encode(const std::string& input_value, std::string* output) {
122 DCHECK(output);
123 base::Base64Encode(input_value, output);
124 std::replace(output->begin(), output->end(), '+', '-');
125 std::replace(output->begin(), output->end(), '/', '_');
128 // Class that bundles responses for an EmbeddedTestServer().
129 // Dictionary is at <domain>/dict, data at <domain>/data.
130 // The data is sent SDCH encoded if that's allowed by protoocol.
131 class SdchResponseHandler {
132 public:
133 // Do initial preparation so that SDCH requests can be handled.
134 explicit SdchResponseHandler(std::string domain)
135 : cache_sdch_response_(false),
136 weak_ptr_factory_(this) {
137 // Dictionary
138 sdch_dictionary_contents_ = "Domain: ";
139 sdch_dictionary_contents_ += domain;
140 sdch_dictionary_contents_ += "\n\n";
141 sdch_dictionary_contents_ += kDictionaryContents;
143 // Dictionary hash for client and server.
144 char binary_hash[32];
145 crypto::SHA256HashString(sdch_dictionary_contents_, binary_hash,
146 sizeof(binary_hash));
147 SafeBase64Encode(std::string(&binary_hash[0], 6), &dictionary_client_hash_);
148 SafeBase64Encode(std::string(&binary_hash[6], 6), &dictionary_server_hash_);
150 // Encoded response.
151 open_vcdiff::HashedDictionary vcdiff_dictionary(
152 kDictionaryContents, strlen(kDictionaryContents));
153 bool result = vcdiff_dictionary.Init();
154 DCHECK(result);
155 open_vcdiff::VCDiffStreamingEncoder encoder(&vcdiff_dictionary, 0, false);
156 encoded_data_ = dictionary_server_hash_;
157 encoded_data_ += '\0';
158 result = encoder.StartEncoding(&encoded_data_);
159 DCHECK(result);
160 result = encoder.EncodeChunk(
161 kSampleData, strlen(kSampleData), &encoded_data_);
162 DCHECK(result);
163 result = encoder.FinishEncoding(&encoded_data_);
164 DCHECK(result);
167 static bool ClientIsAdvertisingSdchEncoding(const HttpRequestHeaderMap& map) {
168 std::string value;
169 if (!GetRequestHeader(map, "accept-encoding", &value))
170 return false;
171 base::StringTokenizer tokenizer(value, " ,");
172 while (tokenizer.GetNext()) {
173 if (base::EqualsCaseInsensitiveASCII(tokenizer.token(), "sdch"))
174 return true;
176 return false;
179 bool ShouldRespondWithSdchEncoding(const HttpRequestHeaderMap& map) {
180 std::string value;
181 if (!GetRequestHeader(map, "avail-dictionary", &value))
182 return false;
183 return value == dictionary_client_hash_;
186 scoped_ptr<net::test_server::HttpResponse> HandleRequest(
187 const net::test_server::HttpRequest& request) {
188 request_vector_.push_back(request);
190 scoped_ptr<net::test_server::BasicHttpResponse> response(
191 new net::test_server::BasicHttpResponse);
192 if (request.relative_url == kDataURLPath) {
193 if (ShouldRespondWithSdchEncoding(request.headers)) {
194 // Note that chrome doesn't advertise accepting SDCH encoding
195 // for POSTs (because the meta-refresh hack would break a POST),
196 // but that's not for the server to enforce.
197 DCHECK_NE(encoded_data_, "");
198 response->set_content_type("text/html");
199 response->set_content(encoded_data_);
200 response->AddCustomHeader("Content-Encoding", "sdch");
201 // We allow tests to set caching on the sdch response,
202 // so that we can force an encoded response with no
203 // dictionary.
204 if (cache_sdch_response_)
205 response->AddCustomHeader("Cache-Control", "max-age=3600");
206 else
207 response->AddCustomHeader("Cache-Control", "no-store");
208 } else {
209 response->set_content_type("text/plain");
210 response->set_content(kSampleData);
211 if (ClientIsAdvertisingSdchEncoding(request.headers))
212 response->AddCustomHeader("Get-Dictionary", kDictionaryURLPath);
213 // We never cache the plain data response, to make it
214 // easy to refresh after we get the dictionary.
215 response->AddCustomHeader("Cache-Control", "no-store");
217 } else {
218 DCHECK_EQ(request.relative_url, kDictionaryURLPath);
219 DCHECK_NE(sdch_dictionary_contents_, "");
220 response->AddCustomHeader("Cache-Control", "max-age=3600");
221 response->set_content_type("application/x-sdch-dictionary");
222 response->set_content(sdch_dictionary_contents_);
224 std::vector<base::Closure> callbacks;
225 callbacks.swap(callback_vector_);
226 for (std::vector<base::Closure>::iterator it = callbacks.begin();
227 it != callbacks.end(); ++it) {
228 it->Run();
230 return response.Pass();
233 void WaitAndGetRequestVector(int num_requests,
234 base::Closure callback,
235 RequestVector* v) {
236 DCHECK_LT(0, num_requests);
237 if (static_cast<size_t>(num_requests) > request_vector_.size()) {
238 callback_vector_.push_back(
239 base::Bind(&SdchResponseHandler::WaitAndGetRequestVector,
240 weak_ptr_factory_.GetWeakPtr(), num_requests,
241 callback, v));
242 return;
244 *v = request_vector_;
245 content::BrowserThread::PostTask(
246 content::BrowserThread::UI, FROM_HERE, callback);
249 void set_cache_sdch_response(bool cache_sdch_response) {
250 cache_sdch_response_ = cache_sdch_response;
253 private:
254 bool cache_sdch_response_;
255 std::string encoded_data_;
256 std::string sdch_dictionary_contents_;
257 std::string dictionary_client_hash_;
258 std::string dictionary_server_hash_;
259 RequestVector request_vector_;
260 std::vector<base::Closure> callback_vector_;
261 base::WeakPtrFactory<SdchResponseHandler> weak_ptr_factory_;
264 class TestSdchObserver : public net::SdchObserver {
265 public:
266 TestSdchObserver() : manager_(nullptr), fetch_count_(0) {}
267 ~TestSdchObserver() override {
268 if (manager_) {
269 manager_->RemoveObserver(this);
273 void Observe(net::SdchManager* manager) {
274 DCHECK(!manager_);
275 manager_ = manager;
276 manager_->AddObserver(this);
279 // SdchObserver
280 void OnDictionaryAdded(const GURL& /* dictionary_url */,
281 const std::string& /* server_hash */) override {}
282 void OnDictionaryRemoved(const std::string& /* server_hash */) override {}
283 void OnGetDictionary(const GURL& /* request_url */,
284 const GURL& /* dictionary_url */) override {
285 fetch_count_++;
287 void OnDictionaryUsed(const std::string& /* server_hash */) override {}
288 void OnClearDictionaries() override {}
290 int fetch_count() const { return fetch_count_; }
292 private:
293 net::SdchManager* manager_;
294 int fetch_count_;
297 class SdchBrowserTest : public InProcessBrowserTest,
298 public net::URLFetcherDelegate {
299 public:
300 static const char kTestHost[];
302 SdchBrowserTest()
303 : response_handler_(kTestHost),
304 url_request_context_getter_(NULL),
305 url_fetch_complete_(false),
306 waiting_(false) {}
308 // Helper functions for fetching data.
310 void FetchUrlDetailed(GURL url, net::URLRequestContextGetter* getter) {
311 url_fetch_complete_ = false;
312 fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this);
313 fetcher_->SetRequestContext(getter);
314 fetcher_->Start();
315 if (!url_fetch_complete_) {
316 waiting_ = true;
317 content::RunMessageLoop();
318 waiting_ = false;
320 CHECK(url_fetch_complete_);
323 void FetchUrl(GURL url) {
324 FetchUrlDetailed(url, url_request_context_getter_.get());
327 const net::URLRequestStatus& FetcherStatus() const {
328 return fetcher_->GetStatus();
331 int FetcherResponseCode() const {
332 return (fetcher_->GetStatus().status() == net::URLRequestStatus::SUCCESS ?
333 fetcher_->GetResponseCode() : 0);
336 const net::HttpResponseHeaders* FetcherResponseHeaders() const {
337 return (fetcher_->GetStatus().status() == net::URLRequestStatus::SUCCESS ?
338 fetcher_->GetResponseHeaders() : NULL);
341 std::string FetcherResponseContents() const {
342 std::string contents;
343 if (fetcher_->GetStatus().status() == net::URLRequestStatus::SUCCESS)
344 CHECK(fetcher_->GetResponseAsString(&contents));
345 return contents;
348 // Get the data from the server. Return value is success/failure of the
349 // data operation, |*sdch_encoding_used| indicates whether or not the
350 // data was retrieved with sdch encoding.
351 // This is done through FetchUrl(), so the various helper functions
352 // will have valid status if it returns successfully.
353 bool GetDataDetailed(net::URLRequestContextGetter* getter,
354 bool* sdch_encoding_used) {
355 FetchUrlDetailed(
356 GURL(base::StringPrintf(
357 "http://%s:%u%s", kTestHost, test_server_port(), kDataURLPath)),
358 getter);
359 EXPECT_EQ(net::URLRequestStatus::SUCCESS, FetcherStatus().status())
360 << "Error code is " << FetcherStatus().error();
361 EXPECT_EQ(200, FetcherResponseCode());
362 EXPECT_EQ(kSampleData, FetcherResponseContents());
364 if (net::URLRequestStatus::SUCCESS != FetcherStatus().status() ||
365 200 != FetcherResponseCode()) {
366 *sdch_encoding_used = false;
367 return false;
370 *sdch_encoding_used =
371 FetcherResponseHeaders()->HasHeaderValue("Content-Encoding", "sdch");
373 if (FetcherResponseContents() != kSampleData)
374 return false;
376 return true;
379 bool GetData(bool* sdch_encoding_used) {
380 return GetDataDetailed(url_request_context_getter_.get(),
381 sdch_encoding_used);
384 // Client information and control.
386 int GetNumberOfDictionaryFetches(Profile* profile) {
387 int fetches = -1;
388 base::RunLoop run_loop;
389 content::BrowserThread::PostTaskAndReply(
390 content::BrowserThread::IO,
391 FROM_HERE,
392 base::Bind(&SdchBrowserTest::GetNumberOfDictionaryFetchesOnIOThread,
393 base::Unretained(this),
394 base::Unretained(profile->GetRequestContext()),
395 &fetches),
396 run_loop.QuitClosure());
397 run_loop.Run();
398 DCHECK_NE(-1, fetches);
399 return fetches;
402 void BrowsingDataRemoveAndWait(int remove_mask) {
403 BrowsingDataRemover* remover = BrowsingDataRemover::CreateForPeriod(
404 browser()->profile(), BrowsingDataRemover::LAST_HOUR);
405 BrowsingDataRemoverCompletionObserver completion_observer(remover);
406 remover->Remove(remove_mask, BrowsingDataHelper::UNPROTECTED_WEB);
407 completion_observer.BlockUntilCompletion();
410 // Something of a cheat; nuke the dictionaries off the SdchManager without
411 // touching the cache (which browsing data remover would do).
412 void NukeSdchDictionaries() {
413 base::RunLoop run_loop;
414 content::BrowserThread::PostTaskAndReply(
415 content::BrowserThread::IO, FROM_HERE,
416 base::Bind(&SdchBrowserTest::NukeSdchDictionariesOnIOThread,
417 url_request_context_getter_),
418 run_loop.QuitClosure());
419 run_loop.Run();
422 // Create a second browser based on a second profile to work within
423 // multi-profile.
424 bool SetupSecondBrowser() {
425 base::FilePath user_data_dir;
426 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
428 if (!second_profile_data_dir_.CreateUniqueTempDirUnderPath(user_data_dir))
429 return false;
431 second_profile_ = g_browser_process->profile_manager()->GetProfile(
432 second_profile_data_dir_.path());
433 if (!second_profile_) return false;
435 second_browser_ = new Browser(Browser::CreateParams(
436 second_profile_, browser()->host_desktop_type()));
437 if (!second_browser_) return false;
439 chrome::AddSelectedTabWithURL(second_browser_,
440 GURL(url::kAboutBlankURL),
441 ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
442 content::WaitForLoadStop(
443 second_browser_->tab_strip_model()->GetActiveWebContents());
444 second_browser_->window()->Show();
446 content::BrowserThread::PostTask(
447 content::BrowserThread::IO,
448 FROM_HERE,
449 base::Bind(&SdchBrowserTest::SubscribeToSdchNotifications,
450 base::Unretained(this),
451 make_scoped_refptr(
452 second_browser_->profile()->GetRequestContext())));
454 return true;
457 bool SetupIncognitoBrowser() {
458 incognito_browser_ = CreateIncognitoBrowser();
460 if (!incognito_browser_)
461 return false;
463 content::BrowserThread::PostTask(
464 content::BrowserThread::IO,
465 FROM_HERE,
466 base::Bind(&SdchBrowserTest::SubscribeToSdchNotifications,
467 base::Unretained(this),
468 make_scoped_refptr(
469 incognito_browser_->profile()->GetRequestContext())));
471 return true;
474 Browser* second_browser() { return second_browser_; }
475 Browser* incognito_browser() { return incognito_browser_; }
477 // Server information and control.
479 void WaitAndGetTestVector(int num_requests, RequestVector* result) {
480 base::RunLoop run_loop;
481 content::BrowserThread::PostTask(
482 content::BrowserThread::IO, FROM_HERE,
483 base::Bind(&SdchResponseHandler::WaitAndGetRequestVector,
484 base::Unretained(&response_handler_),
485 num_requests,
486 run_loop.QuitClosure(),
487 result));
488 run_loop.Run();
491 uint16 test_server_port() { return test_server_.port(); }
493 void SetSdchCacheability(bool cache_sdch_response) {
494 base::RunLoop run_loop;
495 content::BrowserThread::PostTaskAndReply(
496 content::BrowserThread::IO, FROM_HERE,
497 base::Bind(&SdchResponseHandler::set_cache_sdch_response,
498 base::Unretained(&response_handler_),
499 cache_sdch_response),
500 run_loop.QuitClosure());
501 run_loop.Run();
504 // Helper function for common test pattern.
506 // This function gets the data, confirms that the initial sending of the
507 // data included a dictionary advertisement, that that advertisement
508 // resulted in queueing a dictionary fetch, forces that fetch to
509 // go through, and confirms that a follow-on data load uses SDCH
510 // encoding. Returns true if the entire sequence of events occurred.
511 bool ForceSdchDictionaryLoad(Browser* browser) {
512 bool sdch_encoding_used = true;
513 bool data_gotten = GetDataDetailed(
514 browser->profile()->GetRequestContext(), &sdch_encoding_used);
515 EXPECT_TRUE(data_gotten);
516 if (!data_gotten) return false;
517 EXPECT_FALSE(sdch_encoding_used);
519 // Confirm that we were told to get the dictionary
520 const net::HttpResponseHeaders* headers = FetcherResponseHeaders();
521 std::string value;
522 bool have_dict_header =
523 headers->EnumerateHeader(NULL, "Get-Dictionary", &value);
524 EXPECT_TRUE(have_dict_header);
525 if (!have_dict_header) return false;
527 // If the above didn't result in a dictionary fetch being queued, the
528 // rest of the test will time out. Avoid that.
529 int num_fetches = GetNumberOfDictionaryFetches(browser->profile());
530 EXPECT_EQ(1, num_fetches);
531 if (1 != num_fetches) return false;
533 // Wait until the dictionary fetch actually happens.
534 RequestVector request_vector;
535 WaitAndGetTestVector(2, &request_vector);
536 EXPECT_EQ(request_vector[1].relative_url, kDictionaryURLPath);
537 if (request_vector[1].relative_url != kDictionaryURLPath) return false;
539 // Do a round trip to the server ignoring the encoding, presuming
540 // that if we've gotten data to this thread, the dictionary's made
541 // it into the SdchManager.
542 data_gotten = GetDataDetailed(
543 browser->profile()->GetRequestContext(), &sdch_encoding_used);
544 EXPECT_TRUE(data_gotten);
545 if (!data_gotten) return false;
547 // Now data fetches should be SDCH encoded.
548 sdch_encoding_used = false;
549 data_gotten = GetDataDetailed(
550 browser->profile()->GetRequestContext(), &sdch_encoding_used);
551 EXPECT_TRUE(data_gotten);
552 EXPECT_TRUE(sdch_encoding_used);
554 if (!data_gotten || !sdch_encoding_used) return false;
556 // Confirm the request vector looks at this point as expected.
557 WaitAndGetTestVector(4, &request_vector);
558 EXPECT_EQ(4u, request_vector.size());
559 EXPECT_EQ(request_vector[2].relative_url, kDataURLPath);
560 EXPECT_EQ(request_vector[3].relative_url, kDataURLPath);
561 return (4u == request_vector.size() &&
562 request_vector[2].relative_url == kDataURLPath &&
563 request_vector[3].relative_url == kDataURLPath);
566 private:
567 static void NukeSdchDictionariesOnIOThread(
568 net::URLRequestContextGetter* context_getter) {
569 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
570 net::SdchManager* sdch_manager =
571 context_getter->GetURLRequestContext()->sdch_manager();
572 DCHECK(sdch_manager);
573 sdch_manager->ClearData();
576 void GetNumberOfDictionaryFetchesOnIOThread(
577 net::URLRequestContextGetter* context_getter,
578 int* result) {
579 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
581 net::SdchManager* manager(
582 context_getter->GetURLRequestContext()->sdch_manager());
583 DCHECK(observers_.end() != observers_.find(manager));
585 *result = observers_[manager].fetch_count();
588 // InProcessBrowserTest
589 void SetUpCommandLine(base::CommandLine* command_line) override {
590 command_line->AppendSwitchASCII(
591 switches::kHostResolverRules,
592 "MAP " + std::string(kTestHost) + " 127.0.0.1");
593 #if defined(OS_CHROMEOS)
594 command_line->AppendSwitch(
595 chromeos::switches::kIgnoreUserProfileMappingForTests);
596 #endif
599 void SetUpOnMainThread() override {
600 test_server_.RegisterRequestHandler(
601 base::Bind(&SdchResponseHandler::HandleRequest,
602 base::Unretained(&response_handler_)));
603 CHECK(test_server_.InitializeAndWaitUntilReady());
604 url_request_context_getter_ = browser()->profile()->GetRequestContext();
606 content::BrowserThread::PostTask(
607 content::BrowserThread::IO,
608 FROM_HERE,
609 base::Bind(&SdchBrowserTest::SubscribeToSdchNotifications,
610 base::Unretained(this),
611 url_request_context_getter_));
614 void TearDownOnMainThread() override {
615 CHECK(test_server_.ShutdownAndWaitUntilComplete());
617 content::BrowserThread::PostTask(
618 content::BrowserThread::IO,
619 FROM_HERE,
620 base::Bind(&SdchBrowserTest::UnsubscribeFromAllSdchNotifications,
621 base::Unretained(this)));
624 void SubscribeToSdchNotifications(
625 net::URLRequestContextGetter* context_getter) {
626 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
628 net::SdchManager* manager =
629 context_getter->GetURLRequestContext()->sdch_manager();
630 DCHECK(observers_.end() == observers_.find(manager));
632 observers_[manager].Observe(manager);
635 void UnsubscribeFromAllSdchNotifications() {
636 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
637 observers_.clear();
640 // URLFetcherDelegate
641 void OnURLFetchComplete(const net::URLFetcher* source) override {
642 url_fetch_complete_ = true;
643 if (waiting_)
644 base::MessageLoopForUI::current()->Quit();
647 SdchResponseHandler response_handler_;
648 net::test_server::EmbeddedTestServer test_server_;
649 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
650 scoped_ptr<net::URLFetcher> fetcher_;
651 bool url_fetch_complete_;
652 bool waiting_;
653 base::ScopedTempDir second_profile_data_dir_;
654 Profile* second_profile_;
655 Browser* second_browser_;
656 Browser* incognito_browser_;
658 // IO Thread access only.
659 std::map<net::SdchManager*, TestSdchObserver> observers_;
662 const char SdchBrowserTest::kTestHost[] = "our.test.host.com";
664 // Confirm that after getting a dictionary, calling the browsing
665 // data remover renders it unusable. Also (in calling
666 // ForceSdchDictionaryLoad()) servers as a smoke test for SDCH.
667 IN_PROC_BROWSER_TEST_F(SdchBrowserTest, BrowsingDataRemover) {
668 ASSERT_TRUE(ForceSdchDictionaryLoad(browser()));
670 // Confirm browsing data remover without removing the cache leaves
671 // SDCH alone.
672 BrowsingDataRemoveAndWait(BrowsingDataRemover::REMOVE_ALL &
673 ~BrowsingDataRemover::REMOVE_CACHE);
674 bool sdch_encoding_used = false;
675 ASSERT_TRUE(GetData(&sdch_encoding_used));
676 EXPECT_TRUE(sdch_encoding_used);
678 // Confirm browsing data remover removing the cache clears SDCH state.
679 BrowsingDataRemoveAndWait(BrowsingDataRemover::REMOVE_CACHE);
680 sdch_encoding_used = false;
681 ASSERT_TRUE(GetData(&sdch_encoding_used));
682 EXPECT_FALSE(sdch_encoding_used);
685 // Confirm dictionaries not visible in other profiles.
686 IN_PROC_BROWSER_TEST_F(SdchBrowserTest, Isolation) {
687 ASSERT_TRUE(ForceSdchDictionaryLoad(browser()));
688 ASSERT_TRUE(SetupSecondBrowser());
689 ASSERT_TRUE(SetupIncognitoBrowser());
691 // Data fetches from incognito or separate profiles should not be SDCH
692 // encoded.
693 bool sdch_encoding_used = true;
694 EXPECT_TRUE(
695 GetDataDetailed(incognito_browser()->profile()->GetRequestContext(),
696 &sdch_encoding_used));
697 EXPECT_FALSE(sdch_encoding_used);
699 sdch_encoding_used = true;
700 EXPECT_TRUE(GetDataDetailed(
701 second_browser()->profile()->GetRequestContext(), &sdch_encoding_used));
702 EXPECT_FALSE(sdch_encoding_used);
705 // Confirm a dictionary loaded in incognito isn't visible in the main profile.
706 IN_PROC_BROWSER_TEST_F(SdchBrowserTest, ReverseIsolation) {
707 ASSERT_TRUE(SetupIncognitoBrowser());
708 ASSERT_TRUE(ForceSdchDictionaryLoad(incognito_browser()));
710 // Data fetches on main browser should not be SDCH encoded.
711 bool sdch_encoding_used = true;
712 ASSERT_TRUE(GetData(&sdch_encoding_used));
713 EXPECT_FALSE(sdch_encoding_used);
716 } // namespace