sdch_manager_unittest.cc revision 116680a4aac90f2aa7413d9095a592090648e557
1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <limits.h>
6
7#include <string>
8
9#include "base/logging.h"
10#include "base/memory/scoped_ptr.h"
11#include "net/base/sdch_manager.h"
12#include "testing/gtest/include/gtest/gtest.h"
13
14namespace net {
15
16//------------------------------------------------------------------------------
17// Provide sample data and compression results with a sample VCDIFF dictionary.
18// Note an SDCH dictionary has extra meta-data before the VCDIFF dictionary.
19static const char kTestVcdiffDictionary[] = "DictionaryFor"
20    "SdchCompression1SdchCompression2SdchCompression3SdchCompression\n";
21
22//------------------------------------------------------------------------------
23
24class SdchManagerTest : public testing::Test {
25 protected:
26  SdchManagerTest()
27    : sdch_manager_(new SdchManager) {
28  }
29
30  SdchManager* sdch_manager() { return sdch_manager_.get(); }
31
32  // Reset globals back to default state.
33  virtual void TearDown() {
34    SdchManager::EnableSdchSupport(true);
35    SdchManager::EnableSecureSchemeSupport(false);
36  }
37
38 private:
39  scoped_ptr<SdchManager> sdch_manager_;
40};
41
42//------------------------------------------------------------------------------
43static std::string NewSdchDictionary(const std::string& domain) {
44  std::string dictionary;
45  if (!domain.empty()) {
46    dictionary.append("Domain: ");
47    dictionary.append(domain);
48    dictionary.append("\n");
49  }
50  dictionary.append("\n");
51  dictionary.append(kTestVcdiffDictionary, sizeof(kTestVcdiffDictionary) - 1);
52  return dictionary;
53}
54
55TEST_F(SdchManagerTest, DomainSupported) {
56  GURL google_url("http://www.google.com");
57
58  SdchManager::EnableSdchSupport(false);
59  EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(google_url));
60  SdchManager::EnableSdchSupport(true);
61  EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(google_url));
62}
63
64TEST_F(SdchManagerTest, DomainBlacklisting) {
65  GURL test_url("http://www.test.com");
66  GURL google_url("http://www.google.com");
67
68  sdch_manager()->BlacklistDomain(test_url);
69  EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(test_url));
70  EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(google_url));
71
72  sdch_manager()->BlacklistDomain(google_url);
73  EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(google_url));
74}
75
76TEST_F(SdchManagerTest, DomainBlacklistingCaseSensitivity) {
77  GURL test_url("http://www.TesT.com");
78  GURL test2_url("http://www.tEst.com");
79
80  EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(test_url));
81  EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(test2_url));
82  sdch_manager()->BlacklistDomain(test_url);
83  EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(test2_url));
84}
85
86TEST_F(SdchManagerTest, BlacklistingReset) {
87  GURL gurl("http://mytest.DoMain.com");
88  std::string domain(gurl.host());
89
90  sdch_manager()->ClearBlacklistings();
91  EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 0);
92  EXPECT_EQ(sdch_manager()->BlacklistDomainExponential(domain), 0);
93  EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(gurl));
94}
95
96TEST_F(SdchManagerTest, BlacklistingSingleBlacklist) {
97  GURL gurl("http://mytest.DoMain.com");
98  std::string domain(gurl.host());
99  sdch_manager()->ClearBlacklistings();
100
101  sdch_manager()->BlacklistDomain(gurl);
102  EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 1);
103  EXPECT_EQ(sdch_manager()->BlacklistDomainExponential(domain), 1);
104
105  // Check that any domain lookup reduces the blacklist counter.
106  EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(gurl));
107  EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 0);
108  EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(gurl));
109}
110
111TEST_F(SdchManagerTest, BlacklistingExponential) {
112  GURL gurl("http://mytest.DoMain.com");
113  std::string domain(gurl.host());
114  sdch_manager()->ClearBlacklistings();
115
116  int exponential = 1;
117  for (int i = 1; i < 100; ++i) {
118    sdch_manager()->BlacklistDomain(gurl);
119    EXPECT_EQ(sdch_manager()->BlacklistDomainExponential(domain), exponential);
120
121    EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), exponential);
122    EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(gurl));
123    EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), exponential - 1);
124
125    // Simulate a large number of domain checks (which eventually remove the
126    // blacklisting).
127    sdch_manager()->ClearDomainBlacklisting(domain);
128    EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 0);
129    EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(gurl));
130
131    // Predict what exponential backoff will be.
132    exponential = 1 + 2 * exponential;
133    if (exponential < 0)
134      exponential = INT_MAX;  // We don't wrap.
135  }
136}
137
138TEST_F(SdchManagerTest, CanSetExactMatchDictionary) {
139  std::string dictionary_domain("x.y.z.google.com");
140  std::string dictionary_text(NewSdchDictionary(dictionary_domain));
141
142  // Perfect match should work.
143  EXPECT_TRUE(sdch_manager()->AddSdchDictionary(dictionary_text,
144              GURL("http://" + dictionary_domain)));
145}
146
147TEST_F(SdchManagerTest, CanAdvertiseDictionaryOverHTTP) {
148  std::string dictionary_domain("x.y.z.google.com");
149  std::string dictionary_text(NewSdchDictionary(dictionary_domain));
150
151  EXPECT_TRUE(sdch_manager()->AddSdchDictionary(dictionary_text,
152              GURL("http://" + dictionary_domain)));
153
154  std::string dictionary_list;
155  // HTTP target URL can advertise dictionary.
156  sdch_manager()->GetAvailDictionaryList(
157      GURL("http://" + dictionary_domain + "/test"),
158      &dictionary_list);
159  EXPECT_FALSE(dictionary_list.empty());
160}
161
162TEST_F(SdchManagerTest, CanNotAdvertiseDictionaryOverHTTPS) {
163  std::string dictionary_domain("x.y.z.google.com");
164  std::string dictionary_text(NewSdchDictionary(dictionary_domain));
165
166  EXPECT_TRUE(sdch_manager()->AddSdchDictionary(dictionary_text,
167              GURL("http://" + dictionary_domain)));
168
169  std::string dictionary_list;
170  // HTTPS target URL should NOT advertise dictionary.
171  sdch_manager()->GetAvailDictionaryList(
172      GURL("https://" + dictionary_domain + "/test"),
173      &dictionary_list);
174  EXPECT_TRUE(dictionary_list.empty());
175}
176
177TEST_F(SdchManagerTest, CanUseHTTPSDictionaryOverHTTPSIfEnabled) {
178  std::string dictionary_domain("x.y.z.google.com");
179  std::string dictionary_text(NewSdchDictionary(dictionary_domain));
180
181  EXPECT_FALSE(sdch_manager()->AddSdchDictionary(
182      dictionary_text, GURL("https://" + dictionary_domain)));
183  SdchManager::EnableSecureSchemeSupport(true);
184  EXPECT_TRUE(sdch_manager()->AddSdchDictionary(
185      dictionary_text, GURL("https://" + dictionary_domain)));
186
187  GURL target_url("https://" + dictionary_domain + "/test");
188  std::string dictionary_list;
189  // HTTPS target URL should advertise dictionary if secure scheme support is
190  // enabled.
191  sdch_manager()->GetAvailDictionaryList(target_url, &dictionary_list);
192  EXPECT_FALSE(dictionary_list.empty());
193
194  // Dictionary should be available.
195  scoped_refptr<SdchManager::Dictionary> dictionary;
196  std::string client_hash;
197  std::string server_hash;
198  sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash);
199  sdch_manager()->GetVcdiffDictionary(server_hash, target_url, &dictionary);
200  EXPECT_TRUE(dictionary != NULL);
201}
202
203TEST_F(SdchManagerTest, CanNotUseHTTPDictionaryOverHTTPS) {
204  std::string dictionary_domain("x.y.z.google.com");
205  std::string dictionary_text(NewSdchDictionary(dictionary_domain));
206
207  EXPECT_TRUE(sdch_manager()->AddSdchDictionary(dictionary_text,
208              GURL("http://" + dictionary_domain)));
209
210  GURL target_url("https://" + dictionary_domain + "/test");
211  std::string dictionary_list;
212  // HTTPS target URL should not advertise dictionary acquired over HTTP even if
213  // secure scheme support is enabled.
214  SdchManager::EnableSecureSchemeSupport(true);
215  sdch_manager()->GetAvailDictionaryList(target_url, &dictionary_list);
216  EXPECT_TRUE(dictionary_list.empty());
217
218  scoped_refptr<SdchManager::Dictionary> dictionary;
219  std::string client_hash;
220  std::string server_hash;
221  sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash);
222  sdch_manager()->GetVcdiffDictionary(server_hash, target_url, &dictionary);
223  EXPECT_TRUE(dictionary == NULL);
224}
225
226TEST_F(SdchManagerTest, CanNotUseHTTPSDictionaryOverHTTP) {
227  std::string dictionary_domain("x.y.z.google.com");
228  std::string dictionary_text(NewSdchDictionary(dictionary_domain));
229
230  SdchManager::EnableSecureSchemeSupport(true);
231  EXPECT_TRUE(sdch_manager()->AddSdchDictionary(dictionary_text,
232              GURL("https://" + dictionary_domain)));
233
234  GURL target_url("http://" + dictionary_domain + "/test");
235  std::string dictionary_list;
236  // HTTP target URL should not advertise dictionary acquired over HTTPS even if
237  // secure scheme support is enabled.
238  sdch_manager()->GetAvailDictionaryList(target_url, &dictionary_list);
239  EXPECT_TRUE(dictionary_list.empty());
240
241  scoped_refptr<SdchManager::Dictionary> dictionary;
242  std::string client_hash;
243  std::string server_hash;
244  sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash);
245  sdch_manager()->GetVcdiffDictionary(server_hash, target_url, &dictionary);
246  EXPECT_TRUE(dictionary == NULL);
247}
248
249TEST_F(SdchManagerTest, FailToSetDomainMismatchDictionary) {
250  std::string dictionary_domain("x.y.z.google.com");
251  std::string dictionary_text(NewSdchDictionary(dictionary_domain));
252
253  // Fail the "domain match" requirement.
254  EXPECT_FALSE(sdch_manager()->AddSdchDictionary(dictionary_text,
255               GURL("http://y.z.google.com")));
256}
257
258TEST_F(SdchManagerTest, FailToSetDotHostPrefixDomainDictionary) {
259  std::string dictionary_domain("x.y.z.google.com");
260  std::string dictionary_text(NewSdchDictionary(dictionary_domain));
261
262  // Fail the HD with D being the domain and H having a dot requirement.
263  EXPECT_FALSE(sdch_manager()->AddSdchDictionary(dictionary_text,
264               GURL("http://w.x.y.z.google.com")));
265}
266
267TEST_F(SdchManagerTest, FailToSetRepeatPrefixWithDotDictionary) {
268  // Make sure that a prefix that matches the domain postfix won't confuse
269  // the validation checks.
270  std::string dictionary_domain("www.google.com");
271  std::string dictionary_text(NewSdchDictionary(dictionary_domain));
272
273  // Fail the HD with D being the domain and H having a dot requirement.
274  EXPECT_FALSE(sdch_manager()->AddSdchDictionary(dictionary_text,
275               GURL("http://www.google.com.www.google.com")));
276}
277
278TEST_F(SdchManagerTest, CanSetLeadingDotDomainDictionary) {
279  // Make sure that a prefix that matches the domain postfix won't confuse
280  // the validation checks.
281  std::string dictionary_domain(".google.com");
282  std::string dictionary_text(NewSdchDictionary(dictionary_domain));
283
284  // Verify that a leading dot in the domain is acceptable, as long as the host
285  // name does not contain any dots preceding the matched domain name.
286  EXPECT_TRUE(sdch_manager()->AddSdchDictionary(dictionary_text,
287               GURL("http://www.google.com")));
288}
289
290// Make sure the order of the tests is not helping us or confusing things.
291// See test CanSetExactMatchDictionary above for first try.
292TEST_F(SdchManagerTest, CanStillSetExactMatchDictionary) {
293  std::string dictionary_domain("x.y.z.google.com");
294  std::string dictionary_text(NewSdchDictionary(dictionary_domain));
295
296  // Perfect match should *STILL* work.
297  EXPECT_TRUE(sdch_manager()->AddSdchDictionary(dictionary_text,
298              GURL("http://" + dictionary_domain)));
299}
300
301// Make sure the DOS protection precludes the addition of too many dictionaries.
302TEST_F(SdchManagerTest, TooManyDictionaries) {
303  std::string dictionary_domain(".google.com");
304  std::string dictionary_text(NewSdchDictionary(dictionary_domain));
305
306  size_t count = 0;
307  while (count <= SdchManager::kMaxDictionaryCount + 1) {
308    if (!sdch_manager()->AddSdchDictionary(dictionary_text,
309                                          GURL("http://www.google.com")))
310      break;
311
312    dictionary_text += " ";  // Create dictionary with different SHA signature.
313    ++count;
314  }
315  EXPECT_EQ(SdchManager::kMaxDictionaryCount, count);
316}
317
318TEST_F(SdchManagerTest, DictionaryNotTooLarge) {
319  std::string dictionary_domain(".google.com");
320  std::string dictionary_text(NewSdchDictionary(dictionary_domain));
321
322  dictionary_text.append(
323      SdchManager::kMaxDictionarySize  - dictionary_text.size(), ' ');
324  EXPECT_TRUE(sdch_manager()->AddSdchDictionary(dictionary_text,
325              GURL("http://" + dictionary_domain)));
326}
327
328TEST_F(SdchManagerTest, DictionaryTooLarge) {
329  std::string dictionary_domain(".google.com");
330  std::string dictionary_text(NewSdchDictionary(dictionary_domain));
331
332  dictionary_text.append(
333      SdchManager::kMaxDictionarySize + 1 - dictionary_text.size(), ' ');
334  EXPECT_FALSE(sdch_manager()->AddSdchDictionary(dictionary_text,
335              GURL("http://" + dictionary_domain)));
336}
337
338TEST_F(SdchManagerTest, PathMatch) {
339  bool (*PathMatch)(const std::string& path, const std::string& restriction) =
340      SdchManager::Dictionary::PathMatch;
341  // Perfect match is supported.
342  EXPECT_TRUE(PathMatch("/search", "/search"));
343  EXPECT_TRUE(PathMatch("/search/", "/search/"));
344
345  // Prefix only works if last character of restriction is a slash, or first
346  // character in path after a match is a slash.  Validate each case separately.
347
348  // Rely on the slash in the path (not at the end of the restriction).
349  EXPECT_TRUE(PathMatch("/search/something", "/search"));
350  EXPECT_TRUE(PathMatch("/search/s", "/search"));
351  EXPECT_TRUE(PathMatch("/search/other", "/search"));
352  EXPECT_TRUE(PathMatch("/search/something", "/search"));
353
354  // Rely on the slash at the end of the restriction.
355  EXPECT_TRUE(PathMatch("/search/something", "/search/"));
356  EXPECT_TRUE(PathMatch("/search/s", "/search/"));
357  EXPECT_TRUE(PathMatch("/search/other", "/search/"));
358  EXPECT_TRUE(PathMatch("/search/something", "/search/"));
359
360  // Make sure less that sufficient prefix match is false.
361  EXPECT_FALSE(PathMatch("/sear", "/search"));
362  EXPECT_FALSE(PathMatch("/", "/search"));
363  EXPECT_FALSE(PathMatch(std::string(), "/search"));
364
365  // Add examples with several levels of direcories in the restriction.
366  EXPECT_FALSE(PathMatch("/search/something", "search/s"));
367  EXPECT_FALSE(PathMatch("/search/", "/search/s"));
368
369  // Make sure adding characters to path will also fail.
370  EXPECT_FALSE(PathMatch("/searching", "/search/"));
371  EXPECT_FALSE(PathMatch("/searching", "/search"));
372
373  // Make sure we're case sensitive.
374  EXPECT_FALSE(PathMatch("/ABC", "/abc"));
375  EXPECT_FALSE(PathMatch("/abc", "/ABC"));
376}
377
378// The following are only applicable while we have a latency test in the code,
379// and can be removed when that functionality is stripped.
380TEST_F(SdchManagerTest, LatencyTestControls) {
381  GURL url("http://www.google.com");
382  GURL url2("http://www.google2.com");
383
384  // First make sure we default to false.
385  EXPECT_FALSE(sdch_manager()->AllowLatencyExperiment(url));
386  EXPECT_FALSE(sdch_manager()->AllowLatencyExperiment(url2));
387
388  // That we can set each to true.
389  sdch_manager()->SetAllowLatencyExperiment(url, true);
390  EXPECT_TRUE(sdch_manager()->AllowLatencyExperiment(url));
391  EXPECT_FALSE(sdch_manager()->AllowLatencyExperiment(url2));
392
393  sdch_manager()->SetAllowLatencyExperiment(url2, true);
394  EXPECT_TRUE(sdch_manager()->AllowLatencyExperiment(url));
395  EXPECT_TRUE(sdch_manager()->AllowLatencyExperiment(url2));
396
397  // And can reset them to false.
398  sdch_manager()->SetAllowLatencyExperiment(url, false);
399  EXPECT_FALSE(sdch_manager()->AllowLatencyExperiment(url));
400  EXPECT_TRUE(sdch_manager()->AllowLatencyExperiment(url2));
401
402  sdch_manager()->SetAllowLatencyExperiment(url2, false);
403  EXPECT_FALSE(sdch_manager()->AllowLatencyExperiment(url));
404  EXPECT_FALSE(sdch_manager()->AllowLatencyExperiment(url2));
405}
406
407TEST_F(SdchManagerTest, CanUseMultipleManagers) {
408  SdchManager second_manager;
409
410  std::string dictionary_domain_1("x.y.z.google.com");
411  std::string dictionary_domain_2("x.y.z.chromium.org");
412
413  std::string dictionary_text_1(NewSdchDictionary(dictionary_domain_1));
414  std::string dictionary_text_2(NewSdchDictionary(dictionary_domain_2));
415
416  std::string tmp_hash;
417  std::string server_hash_1;
418  std::string server_hash_2;
419
420  SdchManager::GenerateHash(dictionary_text_1, &tmp_hash, &server_hash_1);
421  SdchManager::GenerateHash(dictionary_text_2, &tmp_hash, &server_hash_2);
422
423  // Confirm that if you add directories to one manager, you
424  // can't get them from the other.
425  EXPECT_TRUE(sdch_manager()->AddSdchDictionary(
426      dictionary_text_1, GURL("http://" + dictionary_domain_1)));
427  scoped_refptr<SdchManager::Dictionary> dictionary;
428  sdch_manager()->GetVcdiffDictionary(
429      server_hash_1,
430      GURL("http://" + dictionary_domain_1 + "/random_url"),
431      &dictionary);
432  EXPECT_TRUE(dictionary);
433
434  EXPECT_TRUE(second_manager.AddSdchDictionary(
435      dictionary_text_2, GURL("http://" + dictionary_domain_2)));
436  second_manager.GetVcdiffDictionary(
437      server_hash_2,
438      GURL("http://" + dictionary_domain_2 + "/random_url"),
439      &dictionary);
440  EXPECT_TRUE(dictionary);
441
442  sdch_manager()->GetVcdiffDictionary(
443      server_hash_2,
444      GURL("http://" + dictionary_domain_2 + "/random_url"),
445      &dictionary);
446  EXPECT_FALSE(dictionary);
447
448  second_manager.GetVcdiffDictionary(
449      server_hash_1,
450      GURL("http://" + dictionary_domain_1 + "/random_url"),
451      &dictionary);
452  EXPECT_FALSE(dictionary);
453}
454
455TEST_F(SdchManagerTest, HttpsCorrectlySupported) {
456  GURL url("http://www.google.com");
457  GURL secure_url("https://www.google.com");
458
459  EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(url));
460  EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(secure_url));
461
462  SdchManager::EnableSecureSchemeSupport(true);
463  EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(url));
464  EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(secure_url));
465}
466
467TEST_F(SdchManagerTest, ClearDictionaryData) {
468  std::string dictionary_domain("x.y.z.google.com");
469  GURL blacklist_url("http://bad.chromium.org");
470
471  std::string dictionary_text(NewSdchDictionary(dictionary_domain));
472  std::string tmp_hash;
473  std::string server_hash;
474
475  SdchManager::GenerateHash(dictionary_text, &tmp_hash, &server_hash);
476
477  EXPECT_TRUE(sdch_manager()->AddSdchDictionary(
478      dictionary_text, GURL("http://" + dictionary_domain)));
479  scoped_refptr<SdchManager::Dictionary> dictionary;
480  sdch_manager()->GetVcdiffDictionary(
481      server_hash,
482      GURL("http://" + dictionary_domain + "/random_url"),
483      &dictionary);
484  EXPECT_TRUE(dictionary);
485
486  sdch_manager()->BlacklistDomain(GURL(blacklist_url));
487  EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(blacklist_url));
488
489  sdch_manager()->ClearData();
490
491  dictionary = NULL;
492  sdch_manager()->GetVcdiffDictionary(
493      server_hash,
494      GURL("http://" + dictionary_domain + "/random_url"),
495      &dictionary);
496  EXPECT_FALSE(dictionary);
497  EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(blacklist_url));
498}
499
500}  // namespace net
501
502