blob: 1fa531831d5b8f801fa6447810be0ffbacc554d8 [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"
msramek1c2b3ca2017-03-14 17:57:5629#include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
[email protected]33acd5b2014-08-19 19:56:2230#include "chrome/browser/profiles/profile.h"
31#include "chrome/browser/profiles/profile_manager.h"
32#include "chrome/browser/ui/browser.h"
33#include "chrome/browser/ui/browser_tabstrip.h"
34#include "chrome/browser/ui/browser_window.h"
35#include "chrome/browser/ui/tabs/tab_strip_model.h"
36#include "chrome/common/chrome_paths.h"
37#include "chrome/test/base/in_process_browser_test.h"
msramek1c8e19d2017-01-04 20:04:5338#include "components/browsing_data/core/browsing_data_utils.h"
[email protected]33acd5b2014-08-19 19:56:2239#include "content/public/browser/browser_thread.h"
40#include "content/public/common/content_switches.h"
41#include "content/public/test/browser_test_utils.h"
42#include "content/public/test/test_utils.h"
43#include "crypto/sha2.h"
44#include "net/base/sdch_manager.h"
rdsmith47c133b2014-11-06 19:02:3045#include "net/base/sdch_observer.h"
[email protected]33acd5b2014-08-19 19:56:2246#include "net/http/http_response_headers.h"
47#include "net/test/embedded_test_server/embedded_test_server.h"
48#include "net/test/embedded_test_server/http_request.h"
49#include "net/test/embedded_test_server/http_response.h"
50#include "net/url_request/url_fetcher.h"
51#include "net/url_request/url_fetcher_delegate.h"
52#include "net/url_request/url_request_context.h"
53#include "net/url_request/url_request_context_getter.h"
54#include "sdch/open-vcdiff/src/google/vcencoder.h"
55#include "testing/gtest/include/gtest/gtest.h"
56
57#if defined(OS_CHROMEOS)
58#include "chromeos/chromeos_switches.h"
59#endif
60
61namespace {
62
63typedef std::vector<net::test_server::HttpRequest> RequestVector;
tzike4e4d492015-12-21 08:56:1164typedef net::test_server::HttpRequest::HeaderMap HttpRequestHeaderMap;
[email protected]33acd5b2014-08-19 19:56:2265
66// Credit Alfred, Lord Tennyson
67static const char kSampleData[] = "<html><body><pre>"
68 "There lies the port; the vessel puffs her sail:\n"
69 "There gloom the dark, broad seas. My mariners,\n"
70 "Souls that have toil'd, and wrought, and thought with me—\n"
71 "That ever with a frolic welcome took\n"
72 "The thunder and the sunshine, and opposed\n"
73 "Free hearts, free foreheads—you and I are old;\n"
74 "Old age hath yet his honour and his toil;\n"
75 "Death closes all: but something ere the end,\n"
76 "Some work of noble note, may yet be done,\n"
77 "Not unbecoming men that strove with Gods.\n"
78 "The lights begin to twinkle from the rocks:\n"
79 "The long day wanes: the slow moon climbs: the deep\n"
80 "Moans round with many voices. Come, my friends,\n"
81 "'T is not too late to seek a newer world.\n"
82 "Push off, and sitting well in order smite\n"
83 "The sounding furrows; for my purpose holds\n"
84 "To sail beyond the sunset, and the baths\n"
85 "Of all the western stars, until I die.\n"
86 "It may be that the gulfs will wash us down:\n"
87 "It may be we shall touch the Happy Isles,\n"
88 "And see the great Achilles, whom we knew.\n"
89 "Tho' much is taken, much abides; and tho'\n"
90 "We are not now that strength which in old days\n"
91 "Moved earth and heaven, that which we are, we are;\n"
92 "One equal temper of heroic hearts,\n"
93 "Made weak by time and fate, but strong in will\n"
94 "To strive, to seek, to find, and not to yield.\n"
95 "</pre></body></html>";
96
97// Random selection of lines from above, to allow some encoding, but
98// not a trivial encoding.
99static const char kDictionaryContents[] =
100 "The thunder and the sunshine, and opposed\n"
101 "To sail beyond the sunset, and the baths\n"
102 "Of all the western stars, until I die.\n"
103 "Made weak by time and fate, but strong in will\n"
104 "Moans round with many voices. Come, my friends,\n"
105 "The lights begin to twinkle from the rocks:";
106
107static const char kDictionaryURLPath[] = "/dict";
108static const char kDataURLPath[] = "/data";
109
110// Scans in a case-insensitive way for |header| in |map|,
111// returning true if found and setting |*value| to the value
112// of that header. Does not handle multiple instances of the same
113// header.
114bool GetRequestHeader(const HttpRequestHeaderMap& map,
115 const char* header,
116 std::string* value) {
117 for (HttpRequestHeaderMap::const_iterator it = map.begin();
118 it != map.end(); ++it) {
brettw8a800902015-07-10 18:28:33119 if (base::EqualsCaseInsensitiveASCII(it->first, header)) {
[email protected]33acd5b2014-08-19 19:56:22120 *value = it->second;
121 return true;
122 }
123 }
124 return false;
125}
126
127// Do a URL-safe base64 encoding. See the SDCH spec "Dictionary Identifier"
128// section, and RFC 3548 section 4.
129void SafeBase64Encode(const std::string& input_value, std::string* output) {
130 DCHECK(output);
131 base::Base64Encode(input_value, output);
132 std::replace(output->begin(), output->end(), '+', '-');
133 std::replace(output->begin(), output->end(), '/', '_');
134}
135
136// Class that bundles responses for an EmbeddedTestServer().
137// Dictionary is at <domain>/dict, data at <domain>/data.
138// The data is sent SDCH encoded if that's allowed by protoocol.
139class SdchResponseHandler {
140 public:
141 // Do initial preparation so that SDCH requests can be handled.
ki.stfuf38f9312015-09-27 14:44:37142 explicit SdchResponseHandler(const std::string& domain)
143 : cache_sdch_response_(false), weak_ptr_factory_(this) {
[email protected]33acd5b2014-08-19 19:56:22144 // Dictionary
145 sdch_dictionary_contents_ = "Domain: ";
146 sdch_dictionary_contents_ += domain;
147 sdch_dictionary_contents_ += "\n\n";
148 sdch_dictionary_contents_ += kDictionaryContents;
149
150 // Dictionary hash for client and server.
151 char binary_hash[32];
152 crypto::SHA256HashString(sdch_dictionary_contents_, binary_hash,
153 sizeof(binary_hash));
154 SafeBase64Encode(std::string(&binary_hash[0], 6), &dictionary_client_hash_);
155 SafeBase64Encode(std::string(&binary_hash[6], 6), &dictionary_server_hash_);
156
157 // Encoded response.
158 open_vcdiff::HashedDictionary vcdiff_dictionary(
159 kDictionaryContents, strlen(kDictionaryContents));
160 bool result = vcdiff_dictionary.Init();
161 DCHECK(result);
162 open_vcdiff::VCDiffStreamingEncoder encoder(&vcdiff_dictionary, 0, false);
163 encoded_data_ = dictionary_server_hash_;
164 encoded_data_ += '\0';
165 result = encoder.StartEncoding(&encoded_data_);
166 DCHECK(result);
167 result = encoder.EncodeChunk(
168 kSampleData, strlen(kSampleData), &encoded_data_);
169 DCHECK(result);
170 result = encoder.FinishEncoding(&encoded_data_);
171 DCHECK(result);
172 }
173
174 static bool ClientIsAdvertisingSdchEncoding(const HttpRequestHeaderMap& map) {
175 std::string value;
176 if (!GetRequestHeader(map, "accept-encoding", &value))
177 return false;
178 base::StringTokenizer tokenizer(value, " ,");
179 while (tokenizer.GetNext()) {
brettw8a800902015-07-10 18:28:33180 if (base::EqualsCaseInsensitiveASCII(tokenizer.token(), "sdch"))
[email protected]33acd5b2014-08-19 19:56:22181 return true;
182 }
183 return false;
184 }
185
186 bool ShouldRespondWithSdchEncoding(const HttpRequestHeaderMap& map) {
187 std::string value;
188 if (!GetRequestHeader(map, "avail-dictionary", &value))
189 return false;
190 return value == dictionary_client_hash_;
191 }
192
dcheng4e7c0422016-04-14 00:59:05193 std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
[email protected]33acd5b2014-08-19 19:56:22194 const net::test_server::HttpRequest& request) {
195 request_vector_.push_back(request);
196
dcheng4e7c0422016-04-14 00:59:05197 std::unique_ptr<net::test_server::BasicHttpResponse> response(
[email protected]33acd5b2014-08-19 19:56:22198 new net::test_server::BasicHttpResponse);
199 if (request.relative_url == kDataURLPath) {
200 if (ShouldRespondWithSdchEncoding(request.headers)) {
201 // Note that chrome doesn't advertise accepting SDCH encoding
202 // for POSTs (because the meta-refresh hack would break a POST),
203 // but that's not for the server to enforce.
204 DCHECK_NE(encoded_data_, "");
205 response->set_content_type("text/html");
206 response->set_content(encoded_data_);
207 response->AddCustomHeader("Content-Encoding", "sdch");
208 // We allow tests to set caching on the sdch response,
209 // so that we can force an encoded response with no
210 // dictionary.
211 if (cache_sdch_response_)
212 response->AddCustomHeader("Cache-Control", "max-age=3600");
213 else
214 response->AddCustomHeader("Cache-Control", "no-store");
215 } else {
216 response->set_content_type("text/plain");
217 response->set_content(kSampleData);
218 if (ClientIsAdvertisingSdchEncoding(request.headers))
219 response->AddCustomHeader("Get-Dictionary", kDictionaryURLPath);
220 // We never cache the plain data response, to make it
221 // easy to refresh after we get the dictionary.
222 response->AddCustomHeader("Cache-Control", "no-store");
223 }
224 } else {
225 DCHECK_EQ(request.relative_url, kDictionaryURLPath);
226 DCHECK_NE(sdch_dictionary_contents_, "");
ellyjonesd0ff25592015-03-09 22:32:49227 response->AddCustomHeader("Cache-Control", "max-age=3600");
[email protected]33acd5b2014-08-19 19:56:22228 response->set_content_type("application/x-sdch-dictionary");
229 response->set_content(sdch_dictionary_contents_);
230 }
231 std::vector<base::Closure> callbacks;
232 callbacks.swap(callback_vector_);
233 for (std::vector<base::Closure>::iterator it = callbacks.begin();
234 it != callbacks.end(); ++it) {
235 it->Run();
236 }
dchenge73d8520c2015-12-27 01:19:09237 return std::move(response);
[email protected]33acd5b2014-08-19 19:56:22238 }
239
240 void WaitAndGetRequestVector(int num_requests,
241 base::Closure callback,
242 RequestVector* v) {
243 DCHECK_LT(0, num_requests);
244 if (static_cast<size_t>(num_requests) > request_vector_.size()) {
245 callback_vector_.push_back(
246 base::Bind(&SdchResponseHandler::WaitAndGetRequestVector,
247 weak_ptr_factory_.GetWeakPtr(), num_requests,
248 callback, v));
249 return;
250 }
251 *v = request_vector_;
252 content::BrowserThread::PostTask(
253 content::BrowserThread::UI, FROM_HERE, callback);
254 }
255
256 void set_cache_sdch_response(bool cache_sdch_response) {
257 cache_sdch_response_ = cache_sdch_response;
258 }
259
260 private:
261 bool cache_sdch_response_;
262 std::string encoded_data_;
263 std::string sdch_dictionary_contents_;
264 std::string dictionary_client_hash_;
265 std::string dictionary_server_hash_;
266 RequestVector request_vector_;
267 std::vector<base::Closure> callback_vector_;
268 base::WeakPtrFactory<SdchResponseHandler> weak_ptr_factory_;
269};
270
ellyjones887d31b2015-05-14 20:28:55271class TestSdchObserver : public net::SdchObserver {
272 public:
273 TestSdchObserver() : manager_(nullptr), fetch_count_(0) {}
274 ~TestSdchObserver() override {
275 if (manager_) {
276 manager_->RemoveObserver(this);
277 }
278 }
279
280 void Observe(net::SdchManager* manager) {
281 DCHECK(!manager_);
282 manager_ = manager;
283 manager_->AddObserver(this);
284 }
285
286 // SdchObserver
287 void OnDictionaryAdded(const GURL& /* dictionary_url */,
288 const std::string& /* server_hash */) override {}
289 void OnDictionaryRemoved(const std::string& /* server_hash */) override {}
290 void OnGetDictionary(const GURL& /* request_url */,
291 const GURL& /* dictionary_url */) override {
292 fetch_count_++;
293 }
294 void OnDictionaryUsed(const std::string& /* server_hash */) override {}
295 void OnClearDictionaries() override {}
296
297 int fetch_count() const { return fetch_count_; }
298
299 private:
300 net::SdchManager* manager_;
301 int fetch_count_;
302};
303
rdsmith47c133b2014-11-06 19:02:30304class SdchBrowserTest : public InProcessBrowserTest,
ellyjones887d31b2015-05-14 20:28:55305 public net::URLFetcherDelegate {
[email protected]33acd5b2014-08-19 19:56:22306 public:
307 static const char kTestHost[];
308
309 SdchBrowserTest()
310 : response_handler_(kTestHost),
311 url_request_context_getter_(NULL),
312 url_fetch_complete_(false),
313 waiting_(false) {}
314
315 // Helper functions for fetching data.
316
317 void FetchUrlDetailed(GURL url, net::URLRequestContextGetter* getter) {
318 url_fetch_complete_ = false;
dtapuskadafcf892015-05-01 13:58:25319 fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this);
[email protected]33acd5b2014-08-19 19:56:22320 fetcher_->SetRequestContext(getter);
321 fetcher_->Start();
322 if (!url_fetch_complete_) {
323 waiting_ = true;
324 content::RunMessageLoop();
325 waiting_ = false;
326 }
327 CHECK(url_fetch_complete_);
328 }
329
330 void FetchUrl(GURL url) {
dcheng758c95c2014-08-26 22:07:37331 FetchUrlDetailed(url, url_request_context_getter_.get());
[email protected]33acd5b2014-08-19 19:56:22332 }
333
334 const net::URLRequestStatus& FetcherStatus() const {
335 return fetcher_->GetStatus();
336 }
337
338 int FetcherResponseCode() const {
339 return (fetcher_->GetStatus().status() == net::URLRequestStatus::SUCCESS ?
340 fetcher_->GetResponseCode() : 0);
341 }
342
343 const net::HttpResponseHeaders* FetcherResponseHeaders() const {
344 return (fetcher_->GetStatus().status() == net::URLRequestStatus::SUCCESS ?
345 fetcher_->GetResponseHeaders() : NULL);
346 }
347
348 std::string FetcherResponseContents() const {
349 std::string contents;
350 if (fetcher_->GetStatus().status() == net::URLRequestStatus::SUCCESS)
351 CHECK(fetcher_->GetResponseAsString(&contents));
352 return contents;
353 }
354
355 // Get the data from the server. Return value is success/failure of the
356 // data operation, |*sdch_encoding_used| indicates whether or not the
357 // data was retrieved with sdch encoding.
358 // This is done through FetchUrl(), so the various helper functions
359 // will have valid status if it returns successfully.
360 bool GetDataDetailed(net::URLRequestContextGetter* getter,
361 bool* sdch_encoding_used) {
362 FetchUrlDetailed(
363 GURL(base::StringPrintf(
pkastingcba13292014-11-20 03:35:21364 "http://%s:%u%s", kTestHost, test_server_port(), kDataURLPath)),
[email protected]33acd5b2014-08-19 19:56:22365 getter);
366 EXPECT_EQ(net::URLRequestStatus::SUCCESS, FetcherStatus().status())
367 << "Error code is " << FetcherStatus().error();
368 EXPECT_EQ(200, FetcherResponseCode());
369 EXPECT_EQ(kSampleData, FetcherResponseContents());
370
371 if (net::URLRequestStatus::SUCCESS != FetcherStatus().status() ||
372 200 != FetcherResponseCode()) {
373 *sdch_encoding_used = false;
374 return false;
375 }
376
377 *sdch_encoding_used =
378 FetcherResponseHeaders()->HasHeaderValue("Content-Encoding", "sdch");
379
380 if (FetcherResponseContents() != kSampleData)
381 return false;
382
383 return true;
384 }
385
386 bool GetData(bool* sdch_encoding_used) {
dcheng758c95c2014-08-26 22:07:37387 return GetDataDetailed(url_request_context_getter_.get(),
388 sdch_encoding_used);
[email protected]33acd5b2014-08-19 19:56:22389 }
390
391 // Client information and control.
392
393 int GetNumberOfDictionaryFetches(Profile* profile) {
394 int fetches = -1;
395 base::RunLoop run_loop;
396 content::BrowserThread::PostTaskAndReply(
rdsmith47c133b2014-11-06 19:02:30397 content::BrowserThread::IO,
398 FROM_HERE,
[email protected]33acd5b2014-08-19 19:56:22399 base::Bind(&SdchBrowserTest::GetNumberOfDictionaryFetchesOnIOThread,
rdsmith47c133b2014-11-06 19:02:30400 base::Unretained(this),
[email protected]33acd5b2014-08-19 19:56:22401 base::Unretained(profile->GetRequestContext()),
402 &fetches),
403 run_loop.QuitClosure());
404 run_loop.Run();
405 DCHECK_NE(-1, fetches);
406 return fetches;
407 }
408
409 void BrowsingDataRemoveAndWait(int remove_mask) {
bauerb4530f302016-01-12 14:44:45410 BrowsingDataRemover* remover =
411 BrowsingDataRemoverFactory::GetForBrowserContext(browser()->profile());
[email protected]33acd5b2014-08-19 19:56:22412 BrowsingDataRemoverCompletionObserver completion_observer(remover);
dullweber303f4442017-03-03 11:50:19413 remover->RemoveAndReply(browsing_data::CalculateBeginDeleteTime(
414 browsing_data::TimePeriod::LAST_HOUR),
415 browsing_data::CalculateEndDeleteTime(
416 browsing_data::TimePeriod::LAST_HOUR),
msramek1c2b3ca2017-03-14 17:57:56417 remove_mask,
418 BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB,
dullweber303f4442017-03-03 11:50:19419 &completion_observer);
[email protected]33acd5b2014-08-19 19:56:22420 completion_observer.BlockUntilCompletion();
421 }
422
423 // Something of a cheat; nuke the dictionaries off the SdchManager without
424 // touching the cache (which browsing data remover would do).
425 void NukeSdchDictionaries() {
426 base::RunLoop run_loop;
427 content::BrowserThread::PostTaskAndReply(
428 content::BrowserThread::IO, FROM_HERE,
429 base::Bind(&SdchBrowserTest::NukeSdchDictionariesOnIOThread,
vmpstra34d11322016-03-21 20:28:47430 base::RetainedRef(url_request_context_getter_)),
[email protected]33acd5b2014-08-19 19:56:22431 run_loop.QuitClosure());
432 run_loop.Run();
433 }
434
435 // Create a second browser based on a second profile to work within
436 // multi-profile.
437 bool SetupSecondBrowser() {
438 base::FilePath user_data_dir;
439 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
440
441 if (!second_profile_data_dir_.CreateUniqueTempDirUnderPath(user_data_dir))
442 return false;
443
444 second_profile_ = g_browser_process->profile_manager()->GetProfile(
vabrb8582322016-09-09 08:05:37445 second_profile_data_dir_.GetPath());
[email protected]33acd5b2014-08-19 19:56:22446 if (!second_profile_) return false;
447
erg7b01d692017-02-22 21:57:35448 second_browser_ = new Browser(Browser::CreateParams(second_profile_, true));
[email protected]33acd5b2014-08-19 19:56:22449 if (!second_browser_) return false;
450
451 chrome::AddSelectedTabWithURL(second_browser_,
452 GURL(url::kAboutBlankURL),
Sylvain Defresnec6ccc77d2014-09-19 10:19:35453 ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
[email protected]33acd5b2014-08-19 19:56:22454 content::WaitForLoadStop(
455 second_browser_->tab_strip_model()->GetActiveWebContents());
456 second_browser_->window()->Show();
457
rdsmith47c133b2014-11-06 19:02:30458 content::BrowserThread::PostTask(
vmpstra34d11322016-03-21 20:28:47459 content::BrowserThread::IO, FROM_HERE,
rdsmith47c133b2014-11-06 19:02:30460 base::Bind(&SdchBrowserTest::SubscribeToSdchNotifications,
461 base::Unretained(this),
vmpstra34d11322016-03-21 20:28:47462 base::RetainedRef(
rdsmith47c133b2014-11-06 19:02:30463 second_browser_->profile()->GetRequestContext())));
464
465 return true;
466 }
467
468 bool SetupIncognitoBrowser() {
469 incognito_browser_ = CreateIncognitoBrowser();
470
471 if (!incognito_browser_)
472 return false;
473
474 content::BrowserThread::PostTask(
vmpstra34d11322016-03-21 20:28:47475 content::BrowserThread::IO, FROM_HERE,
rdsmith47c133b2014-11-06 19:02:30476 base::Bind(&SdchBrowserTest::SubscribeToSdchNotifications,
477 base::Unretained(this),
vmpstra34d11322016-03-21 20:28:47478 base::RetainedRef(
rdsmith47c133b2014-11-06 19:02:30479 incognito_browser_->profile()->GetRequestContext())));
480
[email protected]33acd5b2014-08-19 19:56:22481 return true;
482 }
483
484 Browser* second_browser() { return second_browser_; }
rdsmith47c133b2014-11-06 19:02:30485 Browser* incognito_browser() { return incognito_browser_; }
[email protected]33acd5b2014-08-19 19:56:22486
487 // Server information and control.
488
489 void WaitAndGetTestVector(int num_requests, RequestVector* result) {
490 base::RunLoop run_loop;
491 content::BrowserThread::PostTask(
492 content::BrowserThread::IO, FROM_HERE,
493 base::Bind(&SdchResponseHandler::WaitAndGetRequestVector,
494 base::Unretained(&response_handler_),
495 num_requests,
496 run_loop.QuitClosure(),
497 result));
498 run_loop.Run();
499 }
500
avi6846aef2015-12-26 01:09:38501 uint16_t test_server_port() { return test_server_.port(); }
[email protected]33acd5b2014-08-19 19:56:22502
503 void SetSdchCacheability(bool cache_sdch_response) {
504 base::RunLoop run_loop;
505 content::BrowserThread::PostTaskAndReply(
506 content::BrowserThread::IO, FROM_HERE,
507 base::Bind(&SdchResponseHandler::set_cache_sdch_response,
508 base::Unretained(&response_handler_),
509 cache_sdch_response),
510 run_loop.QuitClosure());
511 run_loop.Run();
512 }
513
514 // Helper function for common test pattern.
515 //
516 // This function gets the data, confirms that the initial sending of the
517 // data included a dictionary advertisement, that that advertisement
518 // resulted in queueing a dictionary fetch, forces that fetch to
519 // go through, and confirms that a follow-on data load uses SDCH
520 // encoding. Returns true if the entire sequence of events occurred.
521 bool ForceSdchDictionaryLoad(Browser* browser) {
522 bool sdch_encoding_used = true;
523 bool data_gotten = GetDataDetailed(
524 browser->profile()->GetRequestContext(), &sdch_encoding_used);
525 EXPECT_TRUE(data_gotten);
526 if (!data_gotten) return false;
527 EXPECT_FALSE(sdch_encoding_used);
528
529 // Confirm that we were told to get the dictionary
530 const net::HttpResponseHeaders* headers = FetcherResponseHeaders();
531 std::string value;
532 bool have_dict_header =
533 headers->EnumerateHeader(NULL, "Get-Dictionary", &value);
534 EXPECT_TRUE(have_dict_header);
535 if (!have_dict_header) return false;
536
537 // If the above didn't result in a dictionary fetch being queued, the
538 // rest of the test will time out. Avoid that.
539 int num_fetches = GetNumberOfDictionaryFetches(browser->profile());
540 EXPECT_EQ(1, num_fetches);
541 if (1 != num_fetches) return false;
542
543 // Wait until the dictionary fetch actually happens.
544 RequestVector request_vector;
545 WaitAndGetTestVector(2, &request_vector);
546 EXPECT_EQ(request_vector[1].relative_url, kDictionaryURLPath);
547 if (request_vector[1].relative_url != kDictionaryURLPath) return false;
548
549 // Do a round trip to the server ignoring the encoding, presuming
550 // that if we've gotten data to this thread, the dictionary's made
551 // it into the SdchManager.
552 data_gotten = GetDataDetailed(
553 browser->profile()->GetRequestContext(), &sdch_encoding_used);
554 EXPECT_TRUE(data_gotten);
555 if (!data_gotten) return false;
556
557 // Now data fetches should be SDCH encoded.
558 sdch_encoding_used = false;
559 data_gotten = GetDataDetailed(
560 browser->profile()->GetRequestContext(), &sdch_encoding_used);
561 EXPECT_TRUE(data_gotten);
562 EXPECT_TRUE(sdch_encoding_used);
563
564 if (!data_gotten || !sdch_encoding_used) return false;
565
566 // Confirm the request vector looks at this point as expected.
567 WaitAndGetTestVector(4, &request_vector);
568 EXPECT_EQ(4u, request_vector.size());
569 EXPECT_EQ(request_vector[2].relative_url, kDataURLPath);
570 EXPECT_EQ(request_vector[3].relative_url, kDataURLPath);
571 return (4u == request_vector.size() &&
572 request_vector[2].relative_url == kDataURLPath &&
573 request_vector[3].relative_url == kDataURLPath);
574 }
575
576 private:
577 static void NukeSdchDictionariesOnIOThread(
578 net::URLRequestContextGetter* context_getter) {
anujk.sharma2e02ce162015-04-29 23:10:02579 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
[email protected]33acd5b2014-08-19 19:56:22580 net::SdchManager* sdch_manager =
581 context_getter->GetURLRequestContext()->sdch_manager();
582 DCHECK(sdch_manager);
583 sdch_manager->ClearData();
584 }
585
rdsmith47c133b2014-11-06 19:02:30586 void GetNumberOfDictionaryFetchesOnIOThread(
587 net::URLRequestContextGetter* context_getter,
[email protected]33acd5b2014-08-19 19:56:22588 int* result) {
anujk.sharma2e02ce162015-04-29 23:10:02589 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
rdsmith47c133b2014-11-06 19:02:30590
591 net::SdchManager* manager(
592 context_getter->GetURLRequestContext()->sdch_manager());
ellyjones887d31b2015-05-14 20:28:55593 DCHECK(observers_.end() != observers_.find(manager));
rdsmith47c133b2014-11-06 19:02:30594
ellyjones887d31b2015-05-14 20:28:55595 *result = observers_[manager].fetch_count();
[email protected]33acd5b2014-08-19 19:56:22596 }
597
598 // InProcessBrowserTest
dchengfce29ad2014-10-23 03:47:47599 void SetUpCommandLine(base::CommandLine* command_line) override {
[email protected]33acd5b2014-08-19 19:56:22600 command_line->AppendSwitchASCII(
601 switches::kHostResolverRules,
602 "MAP " + std::string(kTestHost) + " 127.0.0.1");
603#if defined(OS_CHROMEOS)
604 command_line->AppendSwitch(
605 chromeos::switches::kIgnoreUserProfileMappingForTests);
606#endif
607 }
608
dchengfce29ad2014-10-23 03:47:47609 void SetUpOnMainThread() override {
[email protected]33acd5b2014-08-19 19:56:22610 test_server_.RegisterRequestHandler(
611 base::Bind(&SdchResponseHandler::HandleRequest,
612 base::Unretained(&response_handler_)));
svaldeze2745872015-11-04 23:30:20613 CHECK(test_server_.Start());
[email protected]33acd5b2014-08-19 19:56:22614 url_request_context_getter_ = browser()->profile()->GetRequestContext();
rdsmith47c133b2014-11-06 19:02:30615
616 content::BrowserThread::PostTask(
vmpstra34d11322016-03-21 20:28:47617 content::BrowserThread::IO, FROM_HERE,
rdsmith47c133b2014-11-06 19:02:30618 base::Bind(&SdchBrowserTest::SubscribeToSdchNotifications,
619 base::Unretained(this),
vmpstra34d11322016-03-21 20:28:47620 base::RetainedRef(url_request_context_getter_)));
[email protected]33acd5b2014-08-19 19:56:22621 }
622
dchengfce29ad2014-10-23 03:47:47623 void TearDownOnMainThread() override {
[email protected]33acd5b2014-08-19 19:56:22624 CHECK(test_server_.ShutdownAndWaitUntilComplete());
rdsmith47c133b2014-11-06 19:02:30625
626 content::BrowserThread::PostTask(
627 content::BrowserThread::IO,
628 FROM_HERE,
629 base::Bind(&SdchBrowserTest::UnsubscribeFromAllSdchNotifications,
630 base::Unretained(this)));
[email protected]33acd5b2014-08-19 19:56:22631 }
632
rdsmith47c133b2014-11-06 19:02:30633 void SubscribeToSdchNotifications(
634 net::URLRequestContextGetter* context_getter) {
anujk.sharma2e02ce162015-04-29 23:10:02635 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
rdsmith47c133b2014-11-06 19:02:30636
637 net::SdchManager* manager =
638 context_getter->GetURLRequestContext()->sdch_manager();
ellyjones887d31b2015-05-14 20:28:55639 DCHECK(observers_.end() == observers_.find(manager));
rdsmith47c133b2014-11-06 19:02:30640
ellyjones887d31b2015-05-14 20:28:55641 observers_[manager].Observe(manager);
rdsmith47c133b2014-11-06 19:02:30642 }
643
644 void UnsubscribeFromAllSdchNotifications() {
anujk.sharma2e02ce162015-04-29 23:10:02645 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
ellyjones887d31b2015-05-14 20:28:55646 observers_.clear();
rdsmith47c133b2014-11-06 19:02:30647 }
648
[email protected]33acd5b2014-08-19 19:56:22649 // URLFetcherDelegate
dchengfce29ad2014-10-23 03:47:47650 void OnURLFetchComplete(const net::URLFetcher* source) override {
[email protected]33acd5b2014-08-19 19:56:22651 url_fetch_complete_ = true;
652 if (waiting_)
ki.stfuc4f8e242015-10-09 20:40:20653 base::MessageLoopForUI::current()->QuitWhenIdle();
[email protected]33acd5b2014-08-19 19:56:22654 }
655
656 SdchResponseHandler response_handler_;
svaldeze2745872015-11-04 23:30:20657 net::EmbeddedTestServer test_server_;
[email protected]33acd5b2014-08-19 19:56:22658 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
dcheng4e7c0422016-04-14 00:59:05659 std::unique_ptr<net::URLFetcher> fetcher_;
[email protected]33acd5b2014-08-19 19:56:22660 bool url_fetch_complete_;
661 bool waiting_;
662 base::ScopedTempDir second_profile_data_dir_;
663 Profile* second_profile_;
664 Browser* second_browser_;
rdsmith47c133b2014-11-06 19:02:30665 Browser* incognito_browser_;
666
667 // IO Thread access only.
ellyjones887d31b2015-05-14 20:28:55668 std::map<net::SdchManager*, TestSdchObserver> observers_;
[email protected]33acd5b2014-08-19 19:56:22669};
670
671const char SdchBrowserTest::kTestHost[] = "our.test.host.com";
672
673// Confirm that after getting a dictionary, calling the browsing
674// data remover renders it unusable. Also (in calling
675// ForceSdchDictionaryLoad()) servers as a smoke test for SDCH.
676IN_PROC_BROWSER_TEST_F(SdchBrowserTest, BrowsingDataRemover) {
677 ASSERT_TRUE(ForceSdchDictionaryLoad(browser()));
678
679 // Confirm browsing data remover without removing the cache leaves
680 // SDCH alone.
msramek1c2b3ca2017-03-14 17:57:56681 BrowsingDataRemoveAndWait(ChromeBrowsingDataRemoverDelegate::ALL_DATA_TYPES &
682 ~BrowsingDataRemover::DATA_TYPE_CACHE);
[email protected]33acd5b2014-08-19 19:56:22683 bool sdch_encoding_used = false;
684 ASSERT_TRUE(GetData(&sdch_encoding_used));
685 EXPECT_TRUE(sdch_encoding_used);
686
687 // Confirm browsing data remover removing the cache clears SDCH state.
msramek1c2b3ca2017-03-14 17:57:56688 BrowsingDataRemoveAndWait(BrowsingDataRemover::DATA_TYPE_CACHE);
[email protected]33acd5b2014-08-19 19:56:22689 sdch_encoding_used = false;
690 ASSERT_TRUE(GetData(&sdch_encoding_used));
691 EXPECT_FALSE(sdch_encoding_used);
692}
693
694// Confirm dictionaries not visible in other profiles.
695IN_PROC_BROWSER_TEST_F(SdchBrowserTest, Isolation) {
696 ASSERT_TRUE(ForceSdchDictionaryLoad(browser()));
697 ASSERT_TRUE(SetupSecondBrowser());
rdsmith47c133b2014-11-06 19:02:30698 ASSERT_TRUE(SetupIncognitoBrowser());
[email protected]33acd5b2014-08-19 19:56:22699
700 // Data fetches from incognito or separate profiles should not be SDCH
701 // encoded.
702 bool sdch_encoding_used = true;
rdsmith47c133b2014-11-06 19:02:30703 EXPECT_TRUE(
704 GetDataDetailed(incognito_browser()->profile()->GetRequestContext(),
705 &sdch_encoding_used));
[email protected]33acd5b2014-08-19 19:56:22706 EXPECT_FALSE(sdch_encoding_used);
707
708 sdch_encoding_used = true;
709 EXPECT_TRUE(GetDataDetailed(
710 second_browser()->profile()->GetRequestContext(), &sdch_encoding_used));
711 EXPECT_FALSE(sdch_encoding_used);
712}
713
714// Confirm a dictionary loaded in incognito isn't visible in the main profile.
715IN_PROC_BROWSER_TEST_F(SdchBrowserTest, ReverseIsolation) {
rdsmith47c133b2014-11-06 19:02:30716 ASSERT_TRUE(SetupIncognitoBrowser());
717 ASSERT_TRUE(ForceSdchDictionaryLoad(incognito_browser()));
[email protected]33acd5b2014-08-19 19:56:22718
719 // Data fetches on main browser should not be SDCH encoded.
720 bool sdch_encoding_used = true;
721 ASSERT_TRUE(GetData(&sdch_encoding_used));
722 EXPECT_FALSE(sdch_encoding_used);
723}
724
725} // namespace