1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
|
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file contains the SdchManager class and the DictionarySet
// nested class. The manager is responsible for storing all
// SdchDictionarys, and provides access to them through DictionarySet
// objects. A DictionarySet is an object whose lifetime is under the
// control of the consumer. It is a reference to a set of
// dictionaries, and guarantees that none of those dictionaries will
// be destroyed while the DictionarySet reference is alive.
#ifndef NET_BASE_SDCH_MANAGER_H_
#define NET_BASE_SDCH_MANAGER_H_
#include <map>
#include <set>
#include <string>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "base/threading/thread_checker.h"
#include "net/base/net_export.h"
#include "net/base/sdch_dictionary.h"
#include "net/base/sdch_problem_codes.h"
class GURL;
namespace base {
class Value;
}
namespace net {
class SdchObserver;
// Provides global database of differential decompression dictionaries for the
// SDCH filter (processes sdch enconded content).
//
// The SdchManager maintains a collection of memory resident dictionaries. It
// can find a dictionary (based on a server specification of a hash), store a
// dictionary, and make judgements about what URLs can use, set, etc. a
// dictionary.
// These dictionaries are acquired over the net, and include a header
// (containing metadata) as well as a VCDIFF dictionary (for use by a VCDIFF
// module) to decompress data.
//
// A dictionary held by the manager may nonetheless outlive the manager if
// a DictionarySet object refers to it; see below.
class NET_EXPORT SdchManager {
public:
typedef std::map<std::string,
scoped_refptr<base::RefCountedData<SdchDictionary>>>
DictionaryMap;
// A handle for one or more dictionaries which will keep the dictionaries
// alive and accessible for the handle's lifetime.
class NET_EXPORT_PRIVATE DictionarySet {
public:
~DictionarySet();
// Return a comma separated list of client hashes.
std::string GetDictionaryClientHashList() const;
bool Empty() const;
// Lookup the dictionary contents based on the server hash. Returns
// a null pointer if the specified hash is not present in the dictionary
// set.
// The pointer is guaranteed to be valid as long as the DictionarySet
// is alive.
const std::string* GetDictionaryText(const std::string& server_hash) const;
private:
// A DictionarySet may only be constructed by the SdchManager.
friend class SdchManager;
DictionarySet();
void AddDictionary(
const std::string& server_hash,
const scoped_refptr<base::RefCountedData<SdchDictionary>>& dictionary);
DictionaryMap dictionaries_;
DISALLOW_COPY_AND_ASSIGN(DictionarySet);
};
SdchManager();
~SdchManager();
// Clear data (for browser data removal).
void ClearData();
// Record stats on various errors.
static void SdchErrorRecovery(SdchProblemCode problem);
// Enables or disables SDCH compression.
static void EnableSdchSupport(bool enabled);
static bool sdch_enabled() { return g_sdch_enabled_; }
// Enables or disables SDCH compression over secure connection.
static void EnableSecureSchemeSupport(bool enabled);
static bool secure_scheme_supported() { return g_secure_scheme_supported_; }
// Briefly prevent further advertising of SDCH on this domain (if SDCH is
// enabled). After enough calls to IsInSupportedDomain() the blacklisting
// will be removed. Additional blacklists take exponentially more calls
// to IsInSupportedDomain() before the blacklisting is undone.
// Used when filter errors are found from a given domain, but it is plausible
// that the cause is temporary (such as application startup, where cached
// entries are used, but a dictionary is not yet loaded).
void BlacklistDomain(const GURL& url, SdchProblemCode blacklist_reason);
// Used when SEVERE filter errors are found from a given domain, to prevent
// further use of SDCH on that domain.
void BlacklistDomainForever(const GURL& url,
SdchProblemCode blacklist_reason);
// Unit test only, this function resets enabling of sdch, and clears the
// blacklist.
void ClearBlacklistings();
// Unit test only, this function resets the blacklisting count for a domain.
void ClearDomainBlacklisting(const std::string& domain);
// Unit test only: indicate how many more times a domain will be blacklisted.
int BlackListDomainCount(const std::string& domain);
// Unit test only: Indicate what current blacklist increment is for a domain.
int BlacklistDomainExponential(const std::string& domain);
// Check to see if SDCH is enabled (globally), and the given URL is in a
// supported domain (i.e., not blacklisted, and either the specific supported
// domain, or all domains were assumed supported). If it is blacklist, reduce
// by 1 the number of times it will be reported as blacklisted.
SdchProblemCode IsInSupportedDomain(const GURL& url);
// Send out appropriate events notifying observers that a Get-Dictionary
// header has been seen.
SdchProblemCode OnGetDictionary(const GURL& request_url,
const GURL& dictionary_url);
// Send out appropriate events notifying observers that a dictionary
// was successfully used to decode a request. Note that this can happen
// after a dictionary has been deleted from the SdchManager (because
// DictionarySets retain references to deleted dictionaries).
void OnDictionaryUsed(const std::string& server_hash);
// Get a handle to the available dictionaries that might be used
// for encoding responses for the given URL. The return set will not
// include expired dictionaries. If no dictionaries
// are appropriate to use with the target_url, NULL is returned.
scoped_ptr<DictionarySet> GetDictionarySet(const GURL& target_url);
// Get a handle to a specific dictionary, by its server hash, confirming
// that that specific dictionary is appropriate to use with |target_url|.
// Expired dictionaries will be returned. If no dictionary with that
// hash exists that is usable with |target_url|, NULL is returned.
// If there is a usability problem, |*error_code| is set to the
// appropriate problem code.
scoped_ptr<DictionarySet> GetDictionarySetByHash(
const GURL& target_url,
const std::string& server_hash,
SdchProblemCode* problem_code);
// Construct the pair of hashes for client and server to identify an SDCH
// dictionary. This is only made public to facilitate unit testing, but is
// otherwise private
static void GenerateHash(const std::string& dictionary_text,
std::string* client_hash, std::string* server_hash);
// For Latency testing only, we need to know if we've succeeded in doing a
// round trip before starting our comparative tests. If ever we encounter
// problems with SDCH, we opt-out of the test unless/until we perform a
// complete SDCH decoding.
bool AllowLatencyExperiment(const GURL& url) const;
void SetAllowLatencyExperiment(const GURL& url, bool enable);
scoped_ptr<base::Value> SdchInfoToValue() const;
// Add an SDCH dictionary to our list of availible
// dictionaries. This addition will fail if addition is illegal
// (data in the dictionary is not acceptable from the
// dictionary_url; dictionary already added, etc.).
// If |server_hash| is non-null, returns the server hash that may be
// used as an argument to GetDictionarySetByHash.
// Returns SDCH_OK if the addition was successfull, and corresponding error
// code otherwise.
SdchProblemCode AddSdchDictionary(const std::string& dictionary_text,
const GURL& dictionary_url,
std::string* server_hash_p);
// Remove an SDCH dictionary
SdchProblemCode RemoveSdchDictionary(const std::string& server_hash);
// Registration for events generated by the SDCH subsystem.
void AddObserver(SdchObserver* observer);
void RemoveObserver(SdchObserver* observer);
static scoped_ptr<DictionarySet> CreateEmptyDictionarySetForTesting();
private:
struct BlacklistInfo {
BlacklistInfo() : count(0), exponential_count(0), reason(SDCH_OK) {}
int count; // # of times to refuse SDCH advertisement.
int exponential_count; // Current exponential backoff ratchet.
SdchProblemCode reason; // Why domain was blacklisted.
};
typedef std::map<std::string, BlacklistInfo> DomainBlacklistInfo;
typedef std::set<std::string> ExperimentSet;
// Determines whether a "Get-Dictionary" header is legal (dictionary
// url has appropriate relationship to referrer url) in the SDCH
// protocol. Return SDCH_OK if fetch is legal.
SdchProblemCode CanFetchDictionary(const GURL& referring_url,
const GURL& dictionary_url) const;
// Support SDCH compression, by advertising in headers.
static bool g_sdch_enabled_;
// Support SDCH compression for HTTPS requests and responses. When supported,
// HTTPS applicable dictionaries MUST have been acquired securely via HTTPS.
static bool g_secure_scheme_supported_;
// A simple implementation of a RFC 3548 "URL safe" base64 encoder.
static void UrlSafeBase64Encode(const std::string& input,
std::string* output);
DictionaryMap dictionaries_;
// List domains where decode failures have required disabling sdch.
DomainBlacklistInfo blacklisted_domains_;
// List of hostnames for which a latency experiment is allowed (because a
// round trip test has recently passed).
ExperimentSet allow_latency_experiment_;
// Observers that want to be notified of SDCH events.
// Assert list is empty on destruction since if there is an observer
// that hasn't removed itself from the list, that observer probably
// has a reference to the SdchManager.
base::ObserverList<SdchObserver, true> observers_;
base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(SdchManager);
};
} // namespace net
#endif // NET_BASE_SDCH_MANAGER_H_
|