blob: 0b7d40898e37b440981acacaf27bf078e1f6324b [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
avi6846aef2015-12-26 01:09:388#include <stddef.h>
9#include <stdint.h>
dchenge73d8520c2015-12-27 01:19:0910#include <utility>
avi6846aef2015-12-26 01:09:3811
[email protected]33acd5b2014-08-19 19:56:2212#include "base/base64.h"
13#include "base/bind.h"
14#include "base/callback.h"
15#include "base/command_line.h"
16#include "base/files/scoped_temp_dir.h"
17#include "base/memory/weak_ptr.h"
18#include "base/path_service.h"
19#include "base/run_loop.h"
20#include "base/strings/string_tokenizer.h"
21#include "base/strings/string_util.h"
22#include "base/strings/stringprintf.h"
avi6846aef2015-12-26 01:09:3823#include "build/build_config.h"
[email protected]33acd5b2014-08-19 19:56:2224#include "chrome/browser/browser_process.h"
25#include "chrome/browser/browsing_data/browsing_data_helper.h"
26#include "chrome/browser/browsing_data/browsing_data_remover.h"
bauerb4530f302016-01-12 14:44:4527#include "chrome/browser/browsing_data/browsing_data_remover_factory.h"
[email protected]33acd5b2014-08-19 19:56:2228#include "chrome/browser/browsing_data/browsing_data_remover_test_util.h"
29#include "chrome/browser/profiles/profile.h"
30#include "chrome/browser/profiles/profile_manager.h"
31#include "chrome/browser/ui/browser.h"
32#include "chrome/browser/ui/browser_tabstrip.h"
33#include "chrome/browser/ui/browser_window.h"
34#include "chrome/browser/ui/tabs/tab_strip_model.h"
35#include "chrome/common/chrome_paths.h"
36#include "chrome/test/base/in_process_browser_test.h"
37#include "content/public/browser/browser_thread.h"
38#include "content/public/common/content_switches.h"
39#include "content/public/test/browser_test_utils.h"
40#include "content/public/test/test_utils.h"
41#include "crypto/sha2.h"
42#include "net/base/sdch_manager.h"
rdsmith47c133b2014-11-06 19:02:3043#include "net/base/sdch_observer.h"
[email protected]33acd5b2014-08-19 19:56:2244#include "net/http/http_response_headers.h"
45#include "net/test/embedded_test_server/embedded_test_server.h"
46#include "net/test/embedded_test_server/http_request.h"
47#include "net/test/embedded_test_server/http_response.h"
48#include "net/url_request/url_fetcher.h"
49#include "net/url_request/url_fetcher_delegate.h"
50#include "net/url_request/url_request_context.h"
51#include "net/url_request/url_request_context_getter.h"
52#include "sdch/open-vcdiff/src/google/vcencoder.h"
53#include "testing/gtest/include/gtest/gtest.h"
54
55#if defined(OS_CHROMEOS)
56#include "chromeos/chromeos_switches.h"
57#endif
58
59namespace {
60
61typedef std::vector<net::test_server::HttpRequest> RequestVector;
tzike4e4d492015-12-21 08:56:1162typedef net::test_server::HttpRequest::HeaderMap HttpRequestHeaderMap;
[email protected]33acd5b2014-08-19 19:56:2263
64// Credit Alfred, Lord Tennyson
65static const char kSampleData[] = "<html><body><pre>"
66 "There lies the port; the vessel puffs her sail:\n"
67 "There gloom the dark, broad seas. My mariners,\n"
68 "Souls that have toil'd, and wrought, and thought with me—\n"
69 "That ever with a frolic welcome took\n"
70 "The thunder and the sunshine, and opposed\n"
71 "Free hearts, free foreheads—you and I are old;\n"
72 "Old age hath yet his honour and his toil;\n"
73 "Death closes all: but something ere the end,\n"
74 "Some work of noble note, may yet be done,\n"
75 "Not unbecoming men that strove with Gods.\n"
76 "The lights begin to twinkle from the rocks:\n"
77 "The long day wanes: the slow moon climbs: the deep\n"
78 "Moans round with many voices. Come, my friends,\n"
79 "'T is not too late to seek a newer world.\n"
80 "Push off, and sitting well in order smite\n"
81 "The sounding furrows; for my purpose holds\n"
82 "To sail beyond the sunset, and the baths\n"
83 "Of all the western stars, until I die.\n"
84 "It may be that the gulfs will wash us down:\n"
85 "It may be we shall touch the Happy Isles,\n"
86 "And see the great Achilles, whom we knew.\n"
87 "Tho' much is taken, much abides; and tho'\n"
88 "We are not now that strength which in old days\n"
89 "Moved earth and heaven, that which we are, we are;\n"
90 "One equal temper of heroic hearts,\n"
91 "Made weak by time and fate, but strong in will\n"
92 "To strive, to seek, to find, and not to yield.\n"
93 "</pre></body></html>";
94
95// Random selection of lines from above, to allow some encoding, but
96// not a trivial encoding.
97static const char kDictionaryContents[] =
98 "The thunder and the sunshine, and opposed\n"
99 "To sail beyond the sunset, and the baths\n"
100 "Of all the western stars, until I die.\n"
101 "Made weak by time and fate, but strong in will\n"
102 "Moans round with many voices. Come, my friends,\n"
103 "The lights begin to twinkle from the rocks:";
104
105static const char kDictionaryURLPath[] = "/dict";
106static const char kDataURLPath[] = "/data";
107
108// Scans in a case-insensitive way for |header| in |map|,
109// returning true if found and setting |*value| to the value
110// of that header. Does not handle multiple instances of the same
111// header.
112bool GetRequestHeader(const HttpRequestHeaderMap& map,
113 const char* header,
114 std::string* value) {
115 for (HttpRequestHeaderMap::const_iterator it = map.begin();
116 it != map.end(); ++it) {
brettw8a800902015-07-10 18:28:33117 if (base::EqualsCaseInsensitiveASCII(it->first, header)) {
[email protected]33acd5b2014-08-19 19:56:22118 *value = it->second;
119 return true;
120 }
121 }
122 return false;
123}
124
125// Do a URL-safe base64 encoding. See the SDCH spec "Dictionary Identifier"
126// section, and RFC 3548 section 4.
127void SafeBase64Encode(const std::string& input_value, std::string* output) {
128 DCHECK(output);
129 base::Base64Encode(input_value, output);
130 std::replace(output->begin(), output->end(), '+', '-');
131 std::replace(output->begin(), output->end(), '/', '_');
132}
133
134// Class that bundles responses for an EmbeddedTestServer().
135// Dictionary is at <domain>/dict, data at <domain>/data.
136// The data is sent SDCH encoded if that's allowed by protoocol.
137class SdchResponseHandler {
138 public:
139 // Do initial preparation so that SDCH requests can be handled.
ki.stfuf38f9312015-09-27 14:44:37140 explicit SdchResponseHandler(const std::string& domain)
141 : cache_sdch_response_(false), weak_ptr_factory_(this) {
[email protected]33acd5b2014-08-19 19:56:22142 // Dictionary
143 sdch_dictionary_contents_ = "Domain: ";
144 sdch_dictionary_contents_ += domain;
145 sdch_dictionary_contents_ += "\n\n";
146 sdch_dictionary_contents_ += kDictionaryContents;
147
148 // Dictionary hash for client and server.
149 char binary_hash[32];
150 crypto::SHA256HashString(sdch_dictionary_contents_, binary_hash,
151 sizeof(binary_hash));
152 SafeBase64Encode(std::string(&binary_hash[0], 6), &dictionary_client_hash_);
153 SafeBase64Encode(std::string(&binary_hash[6], 6), &dictionary_server_hash_);
154
155 // Encoded response.
156 open_vcdiff::HashedDictionary vcdiff_dictionary(
157 kDictionaryContents, strlen(kDictionaryContents));
158 bool result = vcdiff_dictionary.Init();
159 DCHECK(result);
160 open_vcdiff::VCDiffStreamingEncoder encoder(&vcdiff_dictionary, 0, false);
161 encoded_data_ = dictionary_server_hash_;
162 encoded_data_ += '\0';
163 result = encoder.StartEncoding(&encoded_data_);
164 DCHECK(result);
165 result = encoder.EncodeChunk(
166 kSampleData, strlen(kSampleData), &encoded_data_);
167 DCHECK(result);
168 result = encoder.FinishEncoding(&encoded_data_);
169 DCHECK(result);
170 }
171
172 static bool ClientIsAdvertisingSdchEncoding(const HttpRequestHeaderMap& map) {
173 std::string value;
174 if (!GetRequestHeader(map, "accept-encoding", &value))
175 return false;
176 base::StringTokenizer tokenizer(value, " ,");
177 while (tokenizer.GetNext()) {
brettw8a800902015-07-10 18:28:33178 if (base::EqualsCaseInsensitiveASCII(tokenizer.token(), "sdch"))
[email protected]33acd5b2014-08-19 19:56:22179 return true;
180 }
181 return false;
182 }
183
184 bool ShouldRespondWithSdchEncoding(const HttpRequestHeaderMap& map) {
185 std::string value;
186 if (!GetRequestHeader(map, "avail-dictionary", &value))
187 return false;
188 return value == dictionary_client_hash_;
189 }
190
191 scoped_ptr<net::test_server::HttpResponse> HandleRequest(
192 const net::test_server::HttpRequest& request) {
193 request_vector_.push_back(request);
194
195 scoped_ptr<net::test_server::BasicHttpResponse> response(
196 new net::test_server::BasicHttpResponse);
197 if (request.relative_url == kDataURLPath) {
198 if (ShouldRespondWithSdchEncoding(request.headers)) {
199 // Note that chrome doesn't advertise accepting SDCH encoding
200 // for POSTs (because the meta-refresh hack would break a POST),
201 // but that's not for the server to enforce.
202 DCHECK_NE(encoded_data_, "");
203 response->set_content_type("text/html");
204 response->set_content(encoded_data_);
205 response->AddCustomHeader("Content-Encoding", "sdch");
206 // We allow tests to set caching on the sdch response,
207 // so that we can force an encoded response with no
208 // dictionary.
209 if (cache_sdch_response_)
210 response->AddCustomHeader("Cache-Control", "max-age=3600");
211 else
212 response->AddCustomHeader("Cache-Control", "no-store");
213 } else {
214 response->set_content_type("text/plain");
215 response->set_content(kSampleData);
216 if (ClientIsAdvertisingSdchEncoding(request.headers))
217 response->AddCustomHeader("Get-Dictionary", kDictionaryURLPath);
218 // We never cache the plain data response, to make it
219 // easy to refresh after we get the dictionary.
220 response->AddCustomHeader("Cache-Control", "no-store");
221 }
222 } else {
223 DCHECK_EQ(request.relative_url, kDictionaryURLPath);
224 DCHECK_NE(sdch_dictionary_contents_, "");
ellyjonesd0ff25592015-03-09 22:32:49225 response->AddCustomHeader("Cache-Control", "max-age=3600");
[email protected]33acd5b2014-08-19 19:56:22226 response->set_content_type("application/x-sdch-dictionary");
227 response->set_content(sdch_dictionary_contents_);
228 }
229 std::vector<base::Closure> callbacks;
230 callbacks.swap(callback_vector_);
231 for (std::vector<base::Closure>::iterator it = callbacks.begin();
232 it != callbacks.end(); ++it) {
233 it->Run();
234 }
dchenge73d8520c2015-12-27 01:19:09235 return std::move(response);
[email protected]33acd5b2014-08-19 19:56:22236 }
237
238 void WaitAndGetRequestVector(int num_requests,
239 base::Closure callback,
240 RequestVector* v) {
241 DCHECK_LT(0, num_requests);
242 if (static_cast<size_t>(num_requests) > request_vector_.size()) {
243 callback_vector_.push_back(
244 base::Bind(&SdchResponseHandler::WaitAndGetRequestVector,
245 weak_ptr_factory_.GetWeakPtr(), num_requests,
246 callback, v));
247 return;
248 }
249 *v = request_vector_;
250 content::BrowserThread::PostTask(
251 content::BrowserThread::UI, FROM_HERE, callback);
252 }
253
254 void set_cache_sdch_response(bool cache_sdch_response) {
255 cache_sdch_response_ = cache_sdch_response;
256 }
257
258 private:
259 bool cache_sdch_response_;
260 std::string encoded_data_;
261 std::string sdch_dictionary_contents_;
262 std::string dictionary_client_hash_;
263 std::string dictionary_server_hash_;
264 RequestVector request_vector_;
265 std::vector<base::Closure> callback_vector_;
266 base::WeakPtrFactory<SdchResponseHandler> weak_ptr_factory_;
267};
268
ellyjones887d31b2015-05-14 20:28:55269class TestSdchObserver : public net::SdchObserver {
270 public:
271 TestSdchObserver() : manager_(nullptr), fetch_count_(0) {}
272 ~TestSdchObserver() override {
273 if (manager_) {
274 manager_->RemoveObserver(this);
275 }
276 }
277
278 void Observe(net::SdchManager* manager) {
279 DCHECK(!manager_);
280 manager_ = manager;
281 manager_->AddObserver(this);
282 }
283
284 // SdchObserver
285 void OnDictionaryAdded(const GURL& /* dictionary_url */,
286 const std::string& /* server_hash */) override {}
287 void OnDictionaryRemoved(const std::string& /* server_hash */) override {}
288 void OnGetDictionary(const GURL& /* request_url */,
289 const GURL& /* dictionary_url */) override {
290 fetch_count_++;
291 }
292 void OnDictionaryUsed(const std::string& /* server_hash */) override {}
293 void OnClearDictionaries() override {}
294
295 int fetch_count() const { return fetch_count_; }
296
297 private:
298 net::SdchManager* manager_;
299 int fetch_count_;
300};
301
rdsmith47c133b2014-11-06 19:02:30302class SdchBrowserTest : public InProcessBrowserTest,
ellyjones887d31b2015-05-14 20:28:55303 public net::URLFetcherDelegate {
[email protected]33acd5b2014-08-19 19:56:22304 public:
305 static const char kTestHost[];
306
307 SdchBrowserTest()
308 : response_handler_(kTestHost),
309 url_request_context_getter_(NULL),
310 url_fetch_complete_(false),
311 waiting_(false) {}
312
313 // Helper functions for fetching data.
314
315 void FetchUrlDetailed(GURL url, net::URLRequestContextGetter* getter) {
316 url_fetch_complete_ = false;
dtapuskadafcf892015-05-01 13:58:25317 fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this);
[email protected]33acd5b2014-08-19 19:56:22318 fetcher_->SetRequestContext(getter);
319 fetcher_->Start();
320 if (!url_fetch_complete_) {
321 waiting_ = true;
322 content::RunMessageLoop();
323 waiting_ = false;
324 }
325 CHECK(url_fetch_complete_);
326 }
327
328 void FetchUrl(GURL url) {
dcheng758c95c2014-08-26 22:07:37329 FetchUrlDetailed(url, url_request_context_getter_.get());
[email protected]33acd5b2014-08-19 19:56:22330 }
331
332 const net::URLRequestStatus& FetcherStatus() const {
333 return fetcher_->GetStatus();
334 }
335
336 int FetcherResponseCode() const {
337 return (fetcher_->GetStatus().status() == net::URLRequestStatus::SUCCESS ?
338 fetcher_->GetResponseCode() : 0);
339 }
340
341 const net::HttpResponseHeaders* FetcherResponseHeaders() const {
342 return (fetcher_->GetStatus().status() == net::URLRequestStatus::SUCCESS ?
343 fetcher_->GetResponseHeaders() : NULL);
344 }
345
346 std::string FetcherResponseContents() const {
347 std::string contents;
348 if (fetcher_->GetStatus().status() == net::URLRequestStatus::SUCCESS)
349 CHECK(fetcher_->GetResponseAsString(&contents));
350 return contents;
351 }
352
353 // Get the data from the server. Return value is success/failure of the
354 // data operation, |*sdch_encoding_used| indicates whether or not the
355 // data was retrieved with sdch encoding.
356 // This is done through FetchUrl(), so the various helper functions
357 // will have valid status if it returns successfully.
358 bool GetDataDetailed(net::URLRequestContextGetter* getter,
359 bool* sdch_encoding_used) {
360 FetchUrlDetailed(
361 GURL(base::StringPrintf(
pkastingcba13292014-11-20 03:35:21362 "http://%s:%u%s", kTestHost, test_server_port(), kDataURLPath)),
[email protected]33acd5b2014-08-19 19:56:22363 getter);
364 EXPECT_EQ(net::URLRequestStatus::SUCCESS, FetcherStatus().status())
365 << "Error code is " << FetcherStatus().error();
366 EXPECT_EQ(200, FetcherResponseCode());
367 EXPECT_EQ(kSampleData, FetcherResponseContents());
368
369 if (net::URLRequestStatus::SUCCESS != FetcherStatus().status() ||
370 200 != FetcherResponseCode()) {
371 *sdch_encoding_used = false;
372 return false;
373 }
374
375 *sdch_encoding_used =
376 FetcherResponseHeaders()->HasHeaderValue("Content-Encoding", "sdch");
377
378 if (FetcherResponseContents() != kSampleData)
379 return false;
380
381 return true;
382 }
383
384 bool GetData(bool* sdch_encoding_used) {
dcheng758c95c2014-08-26 22:07:37385 return GetDataDetailed(url_request_context_getter_.get(),
386 sdch_encoding_used);
[email protected]33acd5b2014-08-19 19:56:22387 }
388
389 // Client information and control.
390
391 int GetNumberOfDictionaryFetches(Profile* profile) {
392 int fetches = -1;
393 base::RunLoop run_loop;
394 content::BrowserThread::PostTaskAndReply(
rdsmith47c133b2014-11-06 19:02:30395 content::BrowserThread::IO,
396 FROM_HERE,
[email protected]33acd5b2014-08-19 19:56:22397 base::Bind(&SdchBrowserTest::GetNumberOfDictionaryFetchesOnIOThread,
rdsmith47c133b2014-11-06 19:02:30398 base::Unretained(this),
[email protected]33acd5b2014-08-19 19:56:22399 base::Unretained(profile->GetRequestContext()),
400 &fetches),
401 run_loop.QuitClosure());
402 run_loop.Run();
403 DCHECK_NE(-1, fetches);
404 return fetches;
405 }
406
407 void BrowsingDataRemoveAndWait(int remove_mask) {
bauerb4530f302016-01-12 14:44:45408 BrowsingDataRemover* remover =
409 BrowsingDataRemoverFactory::GetForBrowserContext(browser()->profile());
[email protected]33acd5b2014-08-19 19:56:22410 BrowsingDataRemoverCompletionObserver completion_observer(remover);
bauerb4530f302016-01-12 14:44:45411 remover->Remove(BrowsingDataRemover::Period(BrowsingDataRemover::LAST_HOUR),
412 remove_mask, BrowsingDataHelper::UNPROTECTED_WEB);
[email protected]33acd5b2014-08-19 19:56:22413 completion_observer.BlockUntilCompletion();
414 }
415
416 // Something of a cheat; nuke the dictionaries off the SdchManager without
417 // touching the cache (which browsing data remover would do).
418 void NukeSdchDictionaries() {
419 base::RunLoop run_loop;
420 content::BrowserThread::PostTaskAndReply(
421 content::BrowserThread::IO, FROM_HERE,
422 base::Bind(&SdchBrowserTest::NukeSdchDictionariesOnIOThread,
vmpstra34d11322016-03-21 20:28:47423 base::RetainedRef(url_request_context_getter_)),
[email protected]33acd5b2014-08-19 19:56:22424 run_loop.QuitClosure());
425 run_loop.Run();
426 }
427
428 // Create a second browser based on a second profile to work within
429 // multi-profile.
430 bool SetupSecondBrowser() {
431 base::FilePath user_data_dir;
432 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
433
434 if (!second_profile_data_dir_.CreateUniqueTempDirUnderPath(user_data_dir))
435 return false;
436
437 second_profile_ = g_browser_process->profile_manager()->GetProfile(
438 second_profile_data_dir_.path());
439 if (!second_profile_) return false;
440
scottmg851949002016-02-09 20:09:44441 second_browser_ = new Browser(Browser::CreateParams(second_profile_));
[email protected]33acd5b2014-08-19 19:56:22442 if (!second_browser_) return false;
443
444 chrome::AddSelectedTabWithURL(second_browser_,
445 GURL(url::kAboutBlankURL),
Sylvain Defresnec6ccc77d2014-09-19 10:19:35446 ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
[email protected]33acd5b2014-08-19 19:56:22447 content::WaitForLoadStop(
448 second_browser_->tab_strip_model()->GetActiveWebContents());
449 second_browser_->window()->Show();
450
rdsmith47c133b2014-11-06 19:02:30451 content::BrowserThread::PostTask(
vmpstra34d11322016-03-21 20:28:47452 content::BrowserThread::IO, FROM_HERE,
rdsmith47c133b2014-11-06 19:02:30453 base::Bind(&SdchBrowserTest::SubscribeToSdchNotifications,
454 base::Unretained(this),
vmpstra34d11322016-03-21 20:28:47455 base::RetainedRef(
rdsmith47c133b2014-11-06 19:02:30456 second_browser_->profile()->GetRequestContext())));
457
458 return true;
459 }
460
461 bool SetupIncognitoBrowser() {
462 incognito_browser_ = CreateIncognitoBrowser();
463
464 if (!incognito_browser_)
465 return false;
466
467 content::BrowserThread::PostTask(
vmpstra34d11322016-03-21 20:28:47468 content::BrowserThread::IO, FROM_HERE,
rdsmith47c133b2014-11-06 19:02:30469 base::Bind(&SdchBrowserTest::SubscribeToSdchNotifications,
470 base::Unretained(this),
vmpstra34d11322016-03-21 20:28:47471 base::RetainedRef(
rdsmith47c133b2014-11-06 19:02:30472 incognito_browser_->profile()->GetRequestContext())));
473
[email protected]33acd5b2014-08-19 19:56:22474 return true;
475 }
476
477 Browser* second_browser() { return second_browser_; }
rdsmith47c133b2014-11-06 19:02:30478 Browser* incognito_browser() { return incognito_browser_; }
[email protected]33acd5b2014-08-19 19:56:22479
480 // Server information and control.
481
482 void WaitAndGetTestVector(int num_requests, RequestVector* result) {
483 base::RunLoop run_loop;
484 content::BrowserThread::PostTask(
485 content::BrowserThread::IO, FROM_HERE,
486 base::Bind(&SdchResponseHandler::WaitAndGetRequestVector,
487 base::Unretained(&response_handler_),
488 num_requests,
489 run_loop.QuitClosure(),
490 result));
491 run_loop.Run();
492 }
493
avi6846aef2015-12-26 01:09:38494 uint16_t test_server_port() { return test_server_.port(); }
[email protected]33acd5b2014-08-19 19:56:22495
496 void SetSdchCacheability(bool cache_sdch_response) {
497 base::RunLoop run_loop;
498 content::BrowserThread::PostTaskAndReply(
499 content::BrowserThread::IO, FROM_HERE,
500 base::Bind(&SdchResponseHandler::set_cache_sdch_response,
501 base::Unretained(&response_handler_),
502 cache_sdch_response),
503 run_loop.QuitClosure());
504 run_loop.Run();
505 }
506
507 // Helper function for common test pattern.
508 //
509 // This function gets the data, confirms that the initial sending of the
510 // data included a dictionary advertisement, that that advertisement
511 // resulted in queueing a dictionary fetch, forces that fetch to
512 // go through, and confirms that a follow-on data load uses SDCH
513 // encoding. Returns true if the entire sequence of events occurred.
514 bool ForceSdchDictionaryLoad(Browser* browser) {
515 bool sdch_encoding_used = true;
516 bool data_gotten = GetDataDetailed(
517 browser->profile()->GetRequestContext(), &sdch_encoding_used);
518 EXPECT_TRUE(data_gotten);
519 if (!data_gotten) return false;
520 EXPECT_FALSE(sdch_encoding_used);
521
522 // Confirm that we were told to get the dictionary
523 const net::HttpResponseHeaders* headers = FetcherResponseHeaders();
524 std::string value;
525 bool have_dict_header =
526 headers->EnumerateHeader(NULL, "Get-Dictionary", &value);
527 EXPECT_TRUE(have_dict_header);
528 if (!have_dict_header) return false;
529
530 // If the above didn't result in a dictionary fetch being queued, the
531 // rest of the test will time out. Avoid that.
532 int num_fetches = GetNumberOfDictionaryFetches(browser->profile());
533 EXPECT_EQ(1, num_fetches);
534 if (1 != num_fetches) return false;
535
536 // Wait until the dictionary fetch actually happens.
537 RequestVector request_vector;
538 WaitAndGetTestVector(2, &request_vector);
539 EXPECT_EQ(request_vector[1].relative_url, kDictionaryURLPath);
540 if (request_vector[1].relative_url != kDictionaryURLPath) return false;
541
542 // Do a round trip to the server ignoring the encoding, presuming
543 // that if we've gotten data to this thread, the dictionary's made
544 // it into the SdchManager.
545 data_gotten = GetDataDetailed(
546 browser->profile()->GetRequestContext(), &sdch_encoding_used);
547 EXPECT_TRUE(data_gotten);
548 if (!data_gotten) return false;
549
550 // Now data fetches should be SDCH encoded.
551 sdch_encoding_used = false;
552 data_gotten = GetDataDetailed(
553 browser->profile()->GetRequestContext(), &sdch_encoding_used);
554 EXPECT_TRUE(data_gotten);
555 EXPECT_TRUE(sdch_encoding_used);
556
557 if (!data_gotten || !sdch_encoding_used) return false;
558
559 // Confirm the request vector looks at this point as expected.
560 WaitAndGetTestVector(4, &request_vector);
561 EXPECT_EQ(4u, request_vector.size());
562 EXPECT_EQ(request_vector[2].relative_url, kDataURLPath);
563 EXPECT_EQ(request_vector[3].relative_url, kDataURLPath);
564 return (4u == request_vector.size() &&
565 request_vector[2].relative_url == kDataURLPath &&
566 request_vector[3].relative_url == kDataURLPath);
567 }
568
569 private:
570 static void NukeSdchDictionariesOnIOThread(
571 net::URLRequestContextGetter* context_getter) {
anujk.sharma2e02ce162015-04-29 23:10:02572 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
[email protected]33acd5b2014-08-19 19:56:22573 net::SdchManager* sdch_manager =
574 context_getter->GetURLRequestContext()->sdch_manager();
575 DCHECK(sdch_manager);
576 sdch_manager->ClearData();
577 }
578
rdsmith47c133b2014-11-06 19:02:30579 void GetNumberOfDictionaryFetchesOnIOThread(
580 net::URLRequestContextGetter* context_getter,
[email protected]33acd5b2014-08-19 19:56:22581 int* result) {
anujk.sharma2e02ce162015-04-29 23:10:02582 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
rdsmith47c133b2014-11-06 19:02:30583
584 net::SdchManager* manager(
585 context_getter->GetURLRequestContext()->sdch_manager());
ellyjones887d31b2015-05-14 20:28:55586 DCHECK(observers_.end() != observers_.find(manager));
rdsmith47c133b2014-11-06 19:02:30587
ellyjones887d31b2015-05-14 20:28:55588 *result = observers_[manager].fetch_count();
[email protected]33acd5b2014-08-19 19:56:22589 }
590
591 // InProcessBrowserTest
dchengfce29ad2014-10-23 03:47:47592 void SetUpCommandLine(base::CommandLine* command_line) override {
[email protected]33acd5b2014-08-19 19:56:22593 command_line->AppendSwitchASCII(
594 switches::kHostResolverRules,
595 "MAP " + std::string(kTestHost) + " 127.0.0.1");
596#if defined(OS_CHROMEOS)
597 command_line->AppendSwitch(
598 chromeos::switches::kIgnoreUserProfileMappingForTests);
599#endif
600 }
601
dchengfce29ad2014-10-23 03:47:47602 void SetUpOnMainThread() override {
[email protected]33acd5b2014-08-19 19:56:22603 test_server_.RegisterRequestHandler(
604 base::Bind(&SdchResponseHandler::HandleRequest,
605 base::Unretained(&response_handler_)));
svaldeze2745872015-11-04 23:30:20606 CHECK(test_server_.Start());
[email protected]33acd5b2014-08-19 19:56:22607 url_request_context_getter_ = browser()->profile()->GetRequestContext();
rdsmith47c133b2014-11-06 19:02:30608
609 content::BrowserThread::PostTask(
vmpstra34d11322016-03-21 20:28:47610 content::BrowserThread::IO, FROM_HERE,
rdsmith47c133b2014-11-06 19:02:30611 base::Bind(&SdchBrowserTest::SubscribeToSdchNotifications,
612 base::Unretained(this),
vmpstra34d11322016-03-21 20:28:47613 base::RetainedRef(url_request_context_getter_)));
[email protected]33acd5b2014-08-19 19:56:22614 }
615
dchengfce29ad2014-10-23 03:47:47616 void TearDownOnMainThread() override {
[email protected]33acd5b2014-08-19 19:56:22617 CHECK(test_server_.ShutdownAndWaitUntilComplete());
rdsmith47c133b2014-11-06 19:02:30618
619 content::BrowserThread::PostTask(
620 content::BrowserThread::IO,
621 FROM_HERE,
622 base::Bind(&SdchBrowserTest::UnsubscribeFromAllSdchNotifications,
623 base::Unretained(this)));
[email protected]33acd5b2014-08-19 19:56:22624 }
625
rdsmith47c133b2014-11-06 19:02:30626 void SubscribeToSdchNotifications(
627 net::URLRequestContextGetter* context_getter) {
anujk.sharma2e02ce162015-04-29 23:10:02628 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
rdsmith47c133b2014-11-06 19:02:30629
630 net::SdchManager* manager =
631 context_getter->GetURLRequestContext()->sdch_manager();
ellyjones887d31b2015-05-14 20:28:55632 DCHECK(observers_.end() == observers_.find(manager));
rdsmith47c133b2014-11-06 19:02:30633
ellyjones887d31b2015-05-14 20:28:55634 observers_[manager].Observe(manager);
rdsmith47c133b2014-11-06 19:02:30635 }
636
637 void UnsubscribeFromAllSdchNotifications() {
anujk.sharma2e02ce162015-04-29 23:10:02638 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
ellyjones887d31b2015-05-14 20:28:55639 observers_.clear();
rdsmith47c133b2014-11-06 19:02:30640 }
641
[email protected]33acd5b2014-08-19 19:56:22642 // URLFetcherDelegate
dchengfce29ad2014-10-23 03:47:47643 void OnURLFetchComplete(const net::URLFetcher* source) override {
[email protected]33acd5b2014-08-19 19:56:22644 url_fetch_complete_ = true;
645 if (waiting_)
ki.stfuc4f8e242015-10-09 20:40:20646 base::MessageLoopForUI::current()->QuitWhenIdle();
[email protected]33acd5b2014-08-19 19:56:22647 }
648
649 SdchResponseHandler response_handler_;
svaldeze2745872015-11-04 23:30:20650 net::EmbeddedTestServer test_server_;
[email protected]33acd5b2014-08-19 19:56:22651 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
652 scoped_ptr<net::URLFetcher> fetcher_;
653 bool url_fetch_complete_;
654 bool waiting_;
655 base::ScopedTempDir second_profile_data_dir_;
656 Profile* second_profile_;
657 Browser* second_browser_;
rdsmith47c133b2014-11-06 19:02:30658 Browser* incognito_browser_;
659
660 // IO Thread access only.
ellyjones887d31b2015-05-14 20:28:55661 std::map<net::SdchManager*, TestSdchObserver> observers_;
[email protected]33acd5b2014-08-19 19:56:22662};
663
664const char SdchBrowserTest::kTestHost[] = "our.test.host.com";
665
666// Confirm that after getting a dictionary, calling the browsing
667// data remover renders it unusable. Also (in calling
668// ForceSdchDictionaryLoad()) servers as a smoke test for SDCH.
669IN_PROC_BROWSER_TEST_F(SdchBrowserTest, BrowsingDataRemover) {
670 ASSERT_TRUE(ForceSdchDictionaryLoad(browser()));
671
672 // Confirm browsing data remover without removing the cache leaves
673 // SDCH alone.
674 BrowsingDataRemoveAndWait(BrowsingDataRemover::REMOVE_ALL &
675 ~BrowsingDataRemover::REMOVE_CACHE);
676 bool sdch_encoding_used = false;
677 ASSERT_TRUE(GetData(&sdch_encoding_used));
678 EXPECT_TRUE(sdch_encoding_used);
679
680 // Confirm browsing data remover removing the cache clears SDCH state.
681 BrowsingDataRemoveAndWait(BrowsingDataRemover::REMOVE_CACHE);
682 sdch_encoding_used = false;
683 ASSERT_TRUE(GetData(&sdch_encoding_used));
684 EXPECT_FALSE(sdch_encoding_used);
685}
686
687// Confirm dictionaries not visible in other profiles.
688IN_PROC_BROWSER_TEST_F(SdchBrowserTest, Isolation) {
689 ASSERT_TRUE(ForceSdchDictionaryLoad(browser()));
690 ASSERT_TRUE(SetupSecondBrowser());
rdsmith47c133b2014-11-06 19:02:30691 ASSERT_TRUE(SetupIncognitoBrowser());
[email protected]33acd5b2014-08-19 19:56:22692
693 // Data fetches from incognito or separate profiles should not be SDCH
694 // encoded.
695 bool sdch_encoding_used = true;
rdsmith47c133b2014-11-06 19:02:30696 EXPECT_TRUE(
697 GetDataDetailed(incognito_browser()->profile()->GetRequestContext(),
698 &sdch_encoding_used));
[email protected]33acd5b2014-08-19 19:56:22699 EXPECT_FALSE(sdch_encoding_used);
700
701 sdch_encoding_used = true;
702 EXPECT_TRUE(GetDataDetailed(
703 second_browser()->profile()->GetRequestContext(), &sdch_encoding_used));
704 EXPECT_FALSE(sdch_encoding_used);
705}
706
707// Confirm a dictionary loaded in incognito isn't visible in the main profile.
708IN_PROC_BROWSER_TEST_F(SdchBrowserTest, ReverseIsolation) {
rdsmith47c133b2014-11-06 19:02:30709 ASSERT_TRUE(SetupIncognitoBrowser());
710 ASSERT_TRUE(ForceSdchDictionaryLoad(incognito_browser()));
[email protected]33acd5b2014-08-19 19:56:22711
712 // Data fetches on main browser should not be SDCH encoded.
713 bool sdch_encoding_used = true;
714 ASSERT_TRUE(GetData(&sdch_encoding_used));
715 EXPECT_FALSE(sdch_encoding_used);
716}
717
718} // namespace