blob: 0600802fab94121a4ef2d31d9f611079f61fc966 [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"
gabf64a25e2017-05-12 19:42:5618#include "base/message_loop/message_loop.h"
[email protected]33acd5b2014-08-19 19:56:2219#include "base/path_service.h"
20#include "base/run_loop.h"
21#include "base/strings/string_tokenizer.h"
22#include "base/strings/string_util.h"
23#include "base/strings/stringprintf.h"
avi6846aef2015-12-26 01:09:3824#include "build/build_config.h"
[email protected]33acd5b2014-08-19 19:56:2225#include "chrome/browser/browser_process.h"
26#include "chrome/browser/browsing_data/browsing_data_helper.h"
msramek1c2b3ca2017-03-14 17:57:5627#include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
[email protected]33acd5b2014-08-19 19:56:2228#include "chrome/browser/profiles/profile.h"
29#include "chrome/browser/profiles/profile_manager.h"
30#include "chrome/browser/ui/browser.h"
31#include "chrome/browser/ui/browser_tabstrip.h"
32#include "chrome/browser/ui/browser_window.h"
33#include "chrome/browser/ui/tabs/tab_strip_model.h"
34#include "chrome/common/chrome_paths.h"
35#include "chrome/test/base/in_process_browser_test.h"
msramek1c8e19d2017-01-04 20:04:5336#include "components/browsing_data/core/browsing_data_utils.h"
[email protected]33acd5b2014-08-19 19:56:2237#include "content/public/browser/browser_thread.h"
msrameke169ccb2017-04-26 05:21:4138#include "content/public/browser/browsing_data_remover.h"
[email protected]33acd5b2014-08-19 19:56:2239#include "content/public/common/content_switches.h"
40#include "content/public/test/browser_test_utils.h"
msrameke169ccb2017-04-26 05:21:4141#include "content/public/test/browsing_data_remover_test_util.h"
[email protected]33acd5b2014-08-19 19:56:2242#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"
rhalavati9f5f6e0d2017-04-05 05:05:5250#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
[email protected]33acd5b2014-08-19 19:56:2251#include "net/url_request/url_fetcher.h"
52#include "net/url_request/url_fetcher_delegate.h"
53#include "net/url_request/url_request_context.h"
54#include "net/url_request/url_request_context_getter.h"
55#include "sdch/open-vcdiff/src/google/vcencoder.h"
56#include "testing/gtest/include/gtest/gtest.h"
57
58#if defined(OS_CHROMEOS)
59#include "chromeos/chromeos_switches.h"
60#endif
61
62namespace {
63
64typedef std::vector<net::test_server::HttpRequest> RequestVector;
tzike4e4d492015-12-21 08:56:1165typedef net::test_server::HttpRequest::HeaderMap HttpRequestHeaderMap;
[email protected]33acd5b2014-08-19 19:56:2266
67// Credit Alfred, Lord Tennyson
68static const char kSampleData[] = "<html><body><pre>"
69 "There lies the port; the vessel puffs her sail:\n"
70 "There gloom the dark, broad seas. My mariners,\n"
71 "Souls that have toil'd, and wrought, and thought with me—\n"
72 "That ever with a frolic welcome took\n"
73 "The thunder and the sunshine, and opposed\n"
74 "Free hearts, free foreheads—you and I are old;\n"
75 "Old age hath yet his honour and his toil;\n"
76 "Death closes all: but something ere the end,\n"
77 "Some work of noble note, may yet be done,\n"
78 "Not unbecoming men that strove with Gods.\n"
79 "The lights begin to twinkle from the rocks:\n"
80 "The long day wanes: the slow moon climbs: the deep\n"
81 "Moans round with many voices. Come, my friends,\n"
82 "'T is not too late to seek a newer world.\n"
83 "Push off, and sitting well in order smite\n"
84 "The sounding furrows; for my purpose holds\n"
85 "To sail beyond the sunset, and the baths\n"
86 "Of all the western stars, until I die.\n"
87 "It may be that the gulfs will wash us down:\n"
88 "It may be we shall touch the Happy Isles,\n"
89 "And see the great Achilles, whom we knew.\n"
90 "Tho' much is taken, much abides; and tho'\n"
91 "We are not now that strength which in old days\n"
92 "Moved earth and heaven, that which we are, we are;\n"
93 "One equal temper of heroic hearts,\n"
94 "Made weak by time and fate, but strong in will\n"
95 "To strive, to seek, to find, and not to yield.\n"
96 "</pre></body></html>";
97
98// Random selection of lines from above, to allow some encoding, but
99// not a trivial encoding.
100static const char kDictionaryContents[] =
101 "The thunder and the sunshine, and opposed\n"
102 "To sail beyond the sunset, and the baths\n"
103 "Of all the western stars, until I die.\n"
104 "Made weak by time and fate, but strong in will\n"
105 "Moans round with many voices. Come, my friends,\n"
106 "The lights begin to twinkle from the rocks:";
107
108static const char kDictionaryURLPath[] = "/dict";
109static const char kDataURLPath[] = "/data";
110
111// Scans in a case-insensitive way for |header| in |map|,
112// returning true if found and setting |*value| to the value
113// of that header. Does not handle multiple instances of the same
114// header.
115bool GetRequestHeader(const HttpRequestHeaderMap& map,
116 const char* header,
117 std::string* value) {
118 for (HttpRequestHeaderMap::const_iterator it = map.begin();
119 it != map.end(); ++it) {
brettw8a800902015-07-10 18:28:33120 if (base::EqualsCaseInsensitiveASCII(it->first, header)) {
[email protected]33acd5b2014-08-19 19:56:22121 *value = it->second;
122 return true;
123 }
124 }
125 return false;
126}
127
128// Do a URL-safe base64 encoding. See the SDCH spec "Dictionary Identifier"
129// section, and RFC 3548 section 4.
130void SafeBase64Encode(const std::string& input_value, std::string* output) {
131 DCHECK(output);
132 base::Base64Encode(input_value, output);
133 std::replace(output->begin(), output->end(), '+', '-');
134 std::replace(output->begin(), output->end(), '/', '_');
135}
136
137// Class that bundles responses for an EmbeddedTestServer().
138// Dictionary is at <domain>/dict, data at <domain>/data.
139// The data is sent SDCH encoded if that's allowed by protoocol.
140class SdchResponseHandler {
141 public:
142 // Do initial preparation so that SDCH requests can be handled.
ki.stfuf38f9312015-09-27 14:44:37143 explicit SdchResponseHandler(const std::string& domain)
144 : cache_sdch_response_(false), weak_ptr_factory_(this) {
[email protected]33acd5b2014-08-19 19:56:22145 // Dictionary
146 sdch_dictionary_contents_ = "Domain: ";
147 sdch_dictionary_contents_ += domain;
148 sdch_dictionary_contents_ += "\n\n";
149 sdch_dictionary_contents_ += kDictionaryContents;
150
151 // Dictionary hash for client and server.
152 char binary_hash[32];
153 crypto::SHA256HashString(sdch_dictionary_contents_, binary_hash,
154 sizeof(binary_hash));
155 SafeBase64Encode(std::string(&binary_hash[0], 6), &dictionary_client_hash_);
156 SafeBase64Encode(std::string(&binary_hash[6], 6), &dictionary_server_hash_);
157
158 // Encoded response.
159 open_vcdiff::HashedDictionary vcdiff_dictionary(
160 kDictionaryContents, strlen(kDictionaryContents));
161 bool result = vcdiff_dictionary.Init();
162 DCHECK(result);
163 open_vcdiff::VCDiffStreamingEncoder encoder(&vcdiff_dictionary, 0, false);
164 encoded_data_ = dictionary_server_hash_;
165 encoded_data_ += '\0';
166 result = encoder.StartEncoding(&encoded_data_);
167 DCHECK(result);
168 result = encoder.EncodeChunk(
169 kSampleData, strlen(kSampleData), &encoded_data_);
170 DCHECK(result);
171 result = encoder.FinishEncoding(&encoded_data_);
172 DCHECK(result);
173 }
174
175 static bool ClientIsAdvertisingSdchEncoding(const HttpRequestHeaderMap& map) {
176 std::string value;
177 if (!GetRequestHeader(map, "accept-encoding", &value))
178 return false;
179 base::StringTokenizer tokenizer(value, " ,");
180 while (tokenizer.GetNext()) {
brettw8a800902015-07-10 18:28:33181 if (base::EqualsCaseInsensitiveASCII(tokenizer.token(), "sdch"))
[email protected]33acd5b2014-08-19 19:56:22182 return true;
183 }
184 return false;
185 }
186
187 bool ShouldRespondWithSdchEncoding(const HttpRequestHeaderMap& map) {
188 std::string value;
189 if (!GetRequestHeader(map, "avail-dictionary", &value))
190 return false;
191 return value == dictionary_client_hash_;
192 }
193
dcheng4e7c0422016-04-14 00:59:05194 std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
[email protected]33acd5b2014-08-19 19:56:22195 const net::test_server::HttpRequest& request) {
196 request_vector_.push_back(request);
197
dcheng4e7c0422016-04-14 00:59:05198 std::unique_ptr<net::test_server::BasicHttpResponse> response(
[email protected]33acd5b2014-08-19 19:56:22199 new net::test_server::BasicHttpResponse);
200 if (request.relative_url == kDataURLPath) {
201 if (ShouldRespondWithSdchEncoding(request.headers)) {
202 // Note that chrome doesn't advertise accepting SDCH encoding
203 // for POSTs (because the meta-refresh hack would break a POST),
204 // but that's not for the server to enforce.
205 DCHECK_NE(encoded_data_, "");
206 response->set_content_type("text/html");
207 response->set_content(encoded_data_);
208 response->AddCustomHeader("Content-Encoding", "sdch");
209 // We allow tests to set caching on the sdch response,
210 // so that we can force an encoded response with no
211 // dictionary.
212 if (cache_sdch_response_)
213 response->AddCustomHeader("Cache-Control", "max-age=3600");
214 else
215 response->AddCustomHeader("Cache-Control", "no-store");
216 } else {
217 response->set_content_type("text/plain");
218 response->set_content(kSampleData);
219 if (ClientIsAdvertisingSdchEncoding(request.headers))
220 response->AddCustomHeader("Get-Dictionary", kDictionaryURLPath);
221 // We never cache the plain data response, to make it
222 // easy to refresh after we get the dictionary.
223 response->AddCustomHeader("Cache-Control", "no-store");
224 }
225 } else {
226 DCHECK_EQ(request.relative_url, kDictionaryURLPath);
227 DCHECK_NE(sdch_dictionary_contents_, "");
ellyjonesd0ff25592015-03-09 22:32:49228 response->AddCustomHeader("Cache-Control", "max-age=3600");
[email protected]33acd5b2014-08-19 19:56:22229 response->set_content_type("application/x-sdch-dictionary");
230 response->set_content(sdch_dictionary_contents_);
231 }
232 std::vector<base::Closure> callbacks;
233 callbacks.swap(callback_vector_);
234 for (std::vector<base::Closure>::iterator it = callbacks.begin();
235 it != callbacks.end(); ++it) {
236 it->Run();
237 }
dchenge73d8520c2015-12-27 01:19:09238 return std::move(response);
[email protected]33acd5b2014-08-19 19:56:22239 }
240
241 void WaitAndGetRequestVector(int num_requests,
242 base::Closure callback,
243 RequestVector* v) {
244 DCHECK_LT(0, num_requests);
245 if (static_cast<size_t>(num_requests) > request_vector_.size()) {
246 callback_vector_.push_back(
247 base::Bind(&SdchResponseHandler::WaitAndGetRequestVector,
248 weak_ptr_factory_.GetWeakPtr(), num_requests,
249 callback, v));
250 return;
251 }
252 *v = request_vector_;
253 content::BrowserThread::PostTask(
254 content::BrowserThread::UI, FROM_HERE, callback);
255 }
256
257 void set_cache_sdch_response(bool cache_sdch_response) {
258 cache_sdch_response_ = cache_sdch_response;
259 }
260
261 private:
262 bool cache_sdch_response_;
263 std::string encoded_data_;
264 std::string sdch_dictionary_contents_;
265 std::string dictionary_client_hash_;
266 std::string dictionary_server_hash_;
267 RequestVector request_vector_;
268 std::vector<base::Closure> callback_vector_;
269 base::WeakPtrFactory<SdchResponseHandler> weak_ptr_factory_;
270};
271
ellyjones887d31b2015-05-14 20:28:55272class TestSdchObserver : public net::SdchObserver {
273 public:
274 TestSdchObserver() : manager_(nullptr), fetch_count_(0) {}
275 ~TestSdchObserver() override {
276 if (manager_) {
277 manager_->RemoveObserver(this);
278 }
279 }
280
281 void Observe(net::SdchManager* manager) {
282 DCHECK(!manager_);
283 manager_ = manager;
284 manager_->AddObserver(this);
285 }
286
287 // SdchObserver
288 void OnDictionaryAdded(const GURL& /* dictionary_url */,
289 const std::string& /* server_hash */) override {}
290 void OnDictionaryRemoved(const std::string& /* server_hash */) override {}
291 void OnGetDictionary(const GURL& /* request_url */,
292 const GURL& /* dictionary_url */) override {
293 fetch_count_++;
294 }
295 void OnDictionaryUsed(const std::string& /* server_hash */) override {}
296 void OnClearDictionaries() override {}
297
298 int fetch_count() const { return fetch_count_; }
299
300 private:
301 net::SdchManager* manager_;
302 int fetch_count_;
303};
304
rdsmith47c133b2014-11-06 19:02:30305class SdchBrowserTest : public InProcessBrowserTest,
ellyjones887d31b2015-05-14 20:28:55306 public net::URLFetcherDelegate {
[email protected]33acd5b2014-08-19 19:56:22307 public:
308 static const char kTestHost[];
309
rdsmith4152e172017-03-31 12:29:44310 SdchBrowserTest() : response_handler_(kTestHost) {}
[email protected]33acd5b2014-08-19 19:56:22311
312 // Helper functions for fetching data.
313
314 void FetchUrlDetailed(GURL url, net::URLRequestContextGetter* getter) {
315 url_fetch_complete_ = false;
rhalavati9f5f6e0d2017-04-05 05:05:52316 fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this,
317 TRAFFIC_ANNOTATION_FOR_TESTS);
[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(
tzik53a7b9022017-04-24 11:14:48395 content::BrowserThread::IO, FROM_HERE,
396 base::BindOnce(&SdchBrowserTest::GetNumberOfDictionaryFetchesOnIOThread,
397 base::Unretained(this),
398 base::Unretained(profile->GetRequestContext()),
399 &fetches),
[email protected]33acd5b2014-08-19 19:56:22400 run_loop.QuitClosure());
401 run_loop.Run();
402 DCHECK_NE(-1, fetches);
403 return fetches;
404 }
405
406 void BrowsingDataRemoveAndWait(int remove_mask) {
msrameke169ccb2017-04-26 05:21:41407 content::BrowsingDataRemover* remover =
408 content::BrowserContext::GetBrowsingDataRemover(browser()->profile());
409 content::BrowsingDataRemoverCompletionObserver completion_observer(remover);
410 remover->RemoveAndReply(
411 browsing_data::CalculateBeginDeleteTime(
412 browsing_data::TimePeriod::LAST_HOUR),
413 browsing_data::CalculateEndDeleteTime(
414 browsing_data::TimePeriod::LAST_HOUR),
415 remove_mask, content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB,
416 &completion_observer);
[email protected]33acd5b2014-08-19 19:56:22417 completion_observer.BlockUntilCompletion();
418 }
419
420 // Something of a cheat; nuke the dictionaries off the SdchManager without
421 // touching the cache (which browsing data remover would do).
422 void NukeSdchDictionaries() {
423 base::RunLoop run_loop;
424 content::BrowserThread::PostTaskAndReply(
425 content::BrowserThread::IO, FROM_HERE,
tzik53a7b9022017-04-24 11:14:48426 base::BindOnce(&SdchBrowserTest::NukeSdchDictionariesOnIOThread,
427 base::RetainedRef(url_request_context_getter_)),
[email protected]33acd5b2014-08-19 19:56:22428 run_loop.QuitClosure());
429 run_loop.Run();
430 }
431
432 // Create a second browser based on a second profile to work within
433 // multi-profile.
434 bool SetupSecondBrowser() {
435 base::FilePath user_data_dir;
436 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
437
438 if (!second_profile_data_dir_.CreateUniqueTempDirUnderPath(user_data_dir))
439 return false;
440
441 second_profile_ = g_browser_process->profile_manager()->GetProfile(
vabrb8582322016-09-09 08:05:37442 second_profile_data_dir_.GetPath());
[email protected]33acd5b2014-08-19 19:56:22443 if (!second_profile_) return false;
444
erg7b01d692017-02-22 21:57:35445 second_browser_ = new Browser(Browser::CreateParams(second_profile_, true));
[email protected]33acd5b2014-08-19 19:56:22446 if (!second_browser_) return false;
447
448 chrome::AddSelectedTabWithURL(second_browser_,
449 GURL(url::kAboutBlankURL),
Sylvain Defresnec6ccc77d2014-09-19 10:19:35450 ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
[email protected]33acd5b2014-08-19 19:56:22451 content::WaitForLoadStop(
452 second_browser_->tab_strip_model()->GetActiveWebContents());
453 second_browser_->window()->Show();
454
rdsmith4152e172017-03-31 12:29:44455 bool sdch_enabled = false;
456 base::RunLoop run_loop;
457 content::BrowserThread::PostTaskAndReply(
vmpstra34d11322016-03-21 20:28:47458 content::BrowserThread::IO, FROM_HERE,
tzik53a7b9022017-04-24 11:14:48459 base::BindOnce(
rdsmith4152e172017-03-31 12:29:44460 &SdchBrowserTest::SubscribeToSdchNotifications,
461 base::Unretained(this),
462 base::RetainedRef(second_browser_->profile()->GetRequestContext()),
463 &sdch_enabled_),
464 run_loop.QuitClosure());
465 run_loop.Run();
466 DCHECK(sdch_enabled);
rdsmith47c133b2014-11-06 19:02:30467
468 return true;
469 }
470
471 bool SetupIncognitoBrowser() {
472 incognito_browser_ = CreateIncognitoBrowser();
473
474 if (!incognito_browser_)
475 return false;
476
rdsmith4152e172017-03-31 12:29:44477 bool sdch_enabled = false;
478 base::RunLoop run_loop;
479 content::BrowserThread::PostTaskAndReply(
vmpstra34d11322016-03-21 20:28:47480 content::BrowserThread::IO, FROM_HERE,
tzik53a7b9022017-04-24 11:14:48481 base::BindOnce(&SdchBrowserTest::SubscribeToSdchNotifications,
482 base::Unretained(this),
483 base::RetainedRef(
484 incognito_browser_->profile()->GetRequestContext()),
485 &sdch_enabled),
rdsmith4152e172017-03-31 12:29:44486 run_loop.QuitClosure());
487 run_loop.Run();
488 DCHECK(sdch_enabled);
rdsmith47c133b2014-11-06 19:02:30489
[email protected]33acd5b2014-08-19 19:56:22490 return true;
491 }
492
493 Browser* second_browser() { return second_browser_; }
rdsmith47c133b2014-11-06 19:02:30494 Browser* incognito_browser() { return incognito_browser_; }
[email protected]33acd5b2014-08-19 19:56:22495
496 // Server information and control.
497
498 void WaitAndGetTestVector(int num_requests, RequestVector* result) {
499 base::RunLoop run_loop;
500 content::BrowserThread::PostTask(
501 content::BrowserThread::IO, FROM_HERE,
tzik53a7b9022017-04-24 11:14:48502 base::BindOnce(&SdchResponseHandler::WaitAndGetRequestVector,
503 base::Unretained(&response_handler_), num_requests,
504 run_loop.QuitClosure(), result));
[email protected]33acd5b2014-08-19 19:56:22505 run_loop.Run();
506 }
507
avi6846aef2015-12-26 01:09:38508 uint16_t test_server_port() { return test_server_.port(); }
[email protected]33acd5b2014-08-19 19:56:22509
510 void SetSdchCacheability(bool cache_sdch_response) {
511 base::RunLoop run_loop;
512 content::BrowserThread::PostTaskAndReply(
513 content::BrowserThread::IO, FROM_HERE,
tzik53a7b9022017-04-24 11:14:48514 base::BindOnce(&SdchResponseHandler::set_cache_sdch_response,
515 base::Unretained(&response_handler_),
516 cache_sdch_response),
[email protected]33acd5b2014-08-19 19:56:22517 run_loop.QuitClosure());
518 run_loop.Run();
519 }
520
521 // Helper function for common test pattern.
522 //
523 // This function gets the data, confirms that the initial sending of the
524 // data included a dictionary advertisement, that that advertisement
525 // resulted in queueing a dictionary fetch, forces that fetch to
526 // go through, and confirms that a follow-on data load uses SDCH
527 // encoding. Returns true if the entire sequence of events occurred.
528 bool ForceSdchDictionaryLoad(Browser* browser) {
529 bool sdch_encoding_used = true;
530 bool data_gotten = GetDataDetailed(
531 browser->profile()->GetRequestContext(), &sdch_encoding_used);
532 EXPECT_TRUE(data_gotten);
533 if (!data_gotten) return false;
534 EXPECT_FALSE(sdch_encoding_used);
535
536 // Confirm that we were told to get the dictionary
537 const net::HttpResponseHeaders* headers = FetcherResponseHeaders();
538 std::string value;
539 bool have_dict_header =
540 headers->EnumerateHeader(NULL, "Get-Dictionary", &value);
541 EXPECT_TRUE(have_dict_header);
542 if (!have_dict_header) return false;
543
544 // If the above didn't result in a dictionary fetch being queued, the
545 // rest of the test will time out. Avoid that.
546 int num_fetches = GetNumberOfDictionaryFetches(browser->profile());
547 EXPECT_EQ(1, num_fetches);
548 if (1 != num_fetches) return false;
549
550 // Wait until the dictionary fetch actually happens.
551 RequestVector request_vector;
552 WaitAndGetTestVector(2, &request_vector);
553 EXPECT_EQ(request_vector[1].relative_url, kDictionaryURLPath);
554 if (request_vector[1].relative_url != kDictionaryURLPath) return false;
555
556 // Do a round trip to the server ignoring the encoding, presuming
557 // that if we've gotten data to this thread, the dictionary's made
558 // it into the SdchManager.
559 data_gotten = GetDataDetailed(
560 browser->profile()->GetRequestContext(), &sdch_encoding_used);
561 EXPECT_TRUE(data_gotten);
562 if (!data_gotten) return false;
563
564 // Now data fetches should be SDCH encoded.
565 sdch_encoding_used = false;
566 data_gotten = GetDataDetailed(
567 browser->profile()->GetRequestContext(), &sdch_encoding_used);
568 EXPECT_TRUE(data_gotten);
569 EXPECT_TRUE(sdch_encoding_used);
570
571 if (!data_gotten || !sdch_encoding_used) return false;
572
573 // Confirm the request vector looks at this point as expected.
574 WaitAndGetTestVector(4, &request_vector);
575 EXPECT_EQ(4u, request_vector.size());
576 EXPECT_EQ(request_vector[2].relative_url, kDataURLPath);
577 EXPECT_EQ(request_vector[3].relative_url, kDataURLPath);
578 return (4u == request_vector.size() &&
579 request_vector[2].relative_url == kDataURLPath &&
580 request_vector[3].relative_url == kDataURLPath);
581 }
582
rdsmith4152e172017-03-31 12:29:44583 bool sdch_enabled() const { return sdch_enabled_; }
584
[email protected]33acd5b2014-08-19 19:56:22585 private:
586 static void NukeSdchDictionariesOnIOThread(
587 net::URLRequestContextGetter* context_getter) {
anujk.sharma2e02ce162015-04-29 23:10:02588 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
[email protected]33acd5b2014-08-19 19:56:22589 net::SdchManager* sdch_manager =
590 context_getter->GetURLRequestContext()->sdch_manager();
591 DCHECK(sdch_manager);
592 sdch_manager->ClearData();
593 }
594
rdsmith47c133b2014-11-06 19:02:30595 void GetNumberOfDictionaryFetchesOnIOThread(
596 net::URLRequestContextGetter* context_getter,
[email protected]33acd5b2014-08-19 19:56:22597 int* result) {
anujk.sharma2e02ce162015-04-29 23:10:02598 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
rdsmith47c133b2014-11-06 19:02:30599
600 net::SdchManager* manager(
601 context_getter->GetURLRequestContext()->sdch_manager());
ellyjones887d31b2015-05-14 20:28:55602 DCHECK(observers_.end() != observers_.find(manager));
rdsmith47c133b2014-11-06 19:02:30603
ellyjones887d31b2015-05-14 20:28:55604 *result = observers_[manager].fetch_count();
[email protected]33acd5b2014-08-19 19:56:22605 }
606
607 // InProcessBrowserTest
dchengfce29ad2014-10-23 03:47:47608 void SetUpCommandLine(base::CommandLine* command_line) override {
[email protected]33acd5b2014-08-19 19:56:22609 command_line->AppendSwitchASCII(
610 switches::kHostResolverRules,
611 "MAP " + std::string(kTestHost) + " 127.0.0.1");
612#if defined(OS_CHROMEOS)
613 command_line->AppendSwitch(
614 chromeos::switches::kIgnoreUserProfileMappingForTests);
615#endif
616 }
617
dchengfce29ad2014-10-23 03:47:47618 void SetUpOnMainThread() override {
[email protected]33acd5b2014-08-19 19:56:22619 test_server_.RegisterRequestHandler(
620 base::Bind(&SdchResponseHandler::HandleRequest,
621 base::Unretained(&response_handler_)));
svaldeze2745872015-11-04 23:30:20622 CHECK(test_server_.Start());
[email protected]33acd5b2014-08-19 19:56:22623 url_request_context_getter_ = browser()->profile()->GetRequestContext();
rdsmith47c133b2014-11-06 19:02:30624
rdsmith4152e172017-03-31 12:29:44625 base::RunLoop run_loop;
626 content::BrowserThread::PostTaskAndReply(
vmpstra34d11322016-03-21 20:28:47627 content::BrowserThread::IO, FROM_HERE,
tzik53a7b9022017-04-24 11:14:48628 base::BindOnce(&SdchBrowserTest::SubscribeToSdchNotifications,
629 base::Unretained(this),
630 base::RetainedRef(url_request_context_getter_),
631 &sdch_enabled_),
rdsmith4152e172017-03-31 12:29:44632 run_loop.QuitClosure());
633 run_loop.Run();
[email protected]33acd5b2014-08-19 19:56:22634 }
635
dchengfce29ad2014-10-23 03:47:47636 void TearDownOnMainThread() override {
[email protected]33acd5b2014-08-19 19:56:22637 CHECK(test_server_.ShutdownAndWaitUntilComplete());
rdsmith47c133b2014-11-06 19:02:30638
639 content::BrowserThread::PostTask(
tzik53a7b9022017-04-24 11:14:48640 content::BrowserThread::IO, FROM_HERE,
641 base::BindOnce(&SdchBrowserTest::UnsubscribeFromAllSdchNotifications,
642 base::Unretained(this)));
[email protected]33acd5b2014-08-19 19:56:22643 }
644
rdsmith4152e172017-03-31 12:29:44645 // Check if SDCH is enabled, and if so subscribe an observer to the
646 // SDCH manager on the URLRequestContext that was passed in.
rdsmith47c133b2014-11-06 19:02:30647 void SubscribeToSdchNotifications(
rdsmith4152e172017-03-31 12:29:44648 net::URLRequestContextGetter* context_getter,
649 bool* sdch_enabled) {
anujk.sharma2e02ce162015-04-29 23:10:02650 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
rdsmith47c133b2014-11-06 19:02:30651
652 net::SdchManager* manager =
653 context_getter->GetURLRequestContext()->sdch_manager();
rdsmith4152e172017-03-31 12:29:44654 *sdch_enabled = !!manager;
655 if (!*sdch_enabled)
656 return;
657
ellyjones887d31b2015-05-14 20:28:55658 DCHECK(observers_.end() == observers_.find(manager));
rdsmith47c133b2014-11-06 19:02:30659
ellyjones887d31b2015-05-14 20:28:55660 observers_[manager].Observe(manager);
rdsmith47c133b2014-11-06 19:02:30661 }
662
663 void UnsubscribeFromAllSdchNotifications() {
anujk.sharma2e02ce162015-04-29 23:10:02664 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
ellyjones887d31b2015-05-14 20:28:55665 observers_.clear();
rdsmith47c133b2014-11-06 19:02:30666 }
667
[email protected]33acd5b2014-08-19 19:56:22668 // URLFetcherDelegate
dchengfce29ad2014-10-23 03:47:47669 void OnURLFetchComplete(const net::URLFetcher* source) override {
[email protected]33acd5b2014-08-19 19:56:22670 url_fetch_complete_ = true;
671 if (waiting_)
Gabriel Charette53a9ef812017-07-26 12:36:23672 base::RunLoop::QuitCurrentWhenIdleDeprecated();
[email protected]33acd5b2014-08-19 19:56:22673 }
674
rdsmith4152e172017-03-31 12:29:44675 bool sdch_enabled_ = false;
[email protected]33acd5b2014-08-19 19:56:22676 SdchResponseHandler response_handler_;
svaldeze2745872015-11-04 23:30:20677 net::EmbeddedTestServer test_server_;
rdsmith4152e172017-03-31 12:29:44678 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_ =
679 nullptr;
dcheng4e7c0422016-04-14 00:59:05680 std::unique_ptr<net::URLFetcher> fetcher_;
rdsmith4152e172017-03-31 12:29:44681 bool url_fetch_complete_ = false;
682 bool waiting_ = false;
[email protected]33acd5b2014-08-19 19:56:22683 base::ScopedTempDir second_profile_data_dir_;
684 Profile* second_profile_;
685 Browser* second_browser_;
rdsmith47c133b2014-11-06 19:02:30686 Browser* incognito_browser_;
687
688 // IO Thread access only.
ellyjones887d31b2015-05-14 20:28:55689 std::map<net::SdchManager*, TestSdchObserver> observers_;
[email protected]33acd5b2014-08-19 19:56:22690};
691
692const char SdchBrowserTest::kTestHost[] = "our.test.host.com";
693
694// Confirm that after getting a dictionary, calling the browsing
695// data remover renders it unusable. Also (in calling
696// ForceSdchDictionaryLoad()) servers as a smoke test for SDCH.
697IN_PROC_BROWSER_TEST_F(SdchBrowserTest, BrowsingDataRemover) {
rdsmith4152e172017-03-31 12:29:44698 if (!sdch_enabled()) {
699 LOG(ERROR) << "SDCH disabled; not running test.";
700 return;
701 }
702
[email protected]33acd5b2014-08-19 19:56:22703 ASSERT_TRUE(ForceSdchDictionaryLoad(browser()));
704
705 // Confirm browsing data remover without removing the cache leaves
706 // SDCH alone.
msramek1c2b3ca2017-03-14 17:57:56707 BrowsingDataRemoveAndWait(ChromeBrowsingDataRemoverDelegate::ALL_DATA_TYPES &
msrameke169ccb2017-04-26 05:21:41708 ~content::BrowsingDataRemover::DATA_TYPE_CACHE);
[email protected]33acd5b2014-08-19 19:56:22709 bool sdch_encoding_used = false;
710 ASSERT_TRUE(GetData(&sdch_encoding_used));
711 EXPECT_TRUE(sdch_encoding_used);
712
713 // Confirm browsing data remover removing the cache clears SDCH state.
msrameke169ccb2017-04-26 05:21:41714 BrowsingDataRemoveAndWait(content::BrowsingDataRemover::DATA_TYPE_CACHE);
[email protected]33acd5b2014-08-19 19:56:22715 sdch_encoding_used = false;
716 ASSERT_TRUE(GetData(&sdch_encoding_used));
717 EXPECT_FALSE(sdch_encoding_used);
718}
719
720// Confirm dictionaries not visible in other profiles.
721IN_PROC_BROWSER_TEST_F(SdchBrowserTest, Isolation) {
rdsmith4152e172017-03-31 12:29:44722 if (!sdch_enabled()) {
723 LOG(ERROR) << "SDCH disabled; not running test.";
724 return;
725 }
726
[email protected]33acd5b2014-08-19 19:56:22727 ASSERT_TRUE(ForceSdchDictionaryLoad(browser()));
728 ASSERT_TRUE(SetupSecondBrowser());
rdsmith47c133b2014-11-06 19:02:30729 ASSERT_TRUE(SetupIncognitoBrowser());
[email protected]33acd5b2014-08-19 19:56:22730
731 // Data fetches from incognito or separate profiles should not be SDCH
732 // encoded.
733 bool sdch_encoding_used = true;
rdsmith47c133b2014-11-06 19:02:30734 EXPECT_TRUE(
735 GetDataDetailed(incognito_browser()->profile()->GetRequestContext(),
736 &sdch_encoding_used));
[email protected]33acd5b2014-08-19 19:56:22737 EXPECT_FALSE(sdch_encoding_used);
738
739 sdch_encoding_used = true;
740 EXPECT_TRUE(GetDataDetailed(
741 second_browser()->profile()->GetRequestContext(), &sdch_encoding_used));
742 EXPECT_FALSE(sdch_encoding_used);
743}
744
745// Confirm a dictionary loaded in incognito isn't visible in the main profile.
746IN_PROC_BROWSER_TEST_F(SdchBrowserTest, ReverseIsolation) {
rdsmith4152e172017-03-31 12:29:44747 if (!sdch_enabled()) {
748 LOG(ERROR) << "SDCH disabled; not running test.";
749 return;
750 }
751
rdsmith47c133b2014-11-06 19:02:30752 ASSERT_TRUE(SetupIncognitoBrowser());
753 ASSERT_TRUE(ForceSdchDictionaryLoad(incognito_browser()));
[email protected]33acd5b2014-08-19 19:56:22754
755 // Data fetches on main browser should not be SDCH encoded.
756 bool sdch_encoding_used = true;
757 ASSERT_TRUE(GetData(&sdch_encoding_used));
758 EXPECT_FALSE(sdch_encoding_used);
759}
760
761} // namespace