Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(41)

Side by Side Diff: components/safe_browsing_db/v4_update_protocol_manager.cc

Issue 1719883003: Ignore: v4_update_protocol_manager: Basic implementation with TODOs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@v4_01_prot_mgr
Patch Set: Basic implementation of the update protocol manager with histograms and TODOs. No tests yet. Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 "components/safe_browsing_db/v4_update_protocol_manager.h"
6
7 #include <utility>
8
9 #include "base/base64.h"
10 #include "base/macros.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "base/timer/timer.h"
13 #include "components/safe_browsing_db/safebrowsing.pb.h"
14 #include "net/base/load_flags.h"
15 #include "net/http/http_response_headers.h"
16 #include "net/http/http_status_code.h"
17 #include "net/url_request/url_fetcher.h"
18 #include "net/url_request/url_request_context_getter.h"
19
20 using base::Time;
21 using base::TimeDelta;
22
23 namespace {
24
25 // Enumerate parsing failures for histogramming purposes. DO NOT CHANGE
26 // THE ORDERING OF THESE VALUES.
27 enum ParseResultType {
28 // Error parsing the protocol buffer from a string.
29 PARSE_FROM_STRING_ERROR = 0,
30
31 // Memory space for histograms is determined by the max. ALWAYS
32 // ADD NEW VALUES BEFORE THIS ONE.
33 PARSE_RESULT_TYPE_MAX = 1
34 };
35
36 // Record parsing errors of an update result.
37 void RecordParseUpdateResult(ParseResultType result_type) {
38 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.ParseV4UpdateResult", result_type,
39 PARSE_RESULT_TYPE_MAX);
40 }
41
42 } // namespace
43
44 namespace safe_browsing {
45
46 const char kUmaV4UpdateResponseMetricName[] =
47 "SafeBrowsing.V4UpdateHttpResponseOrErrorCode";
48
49 // The default V4UpdateProtocolManagerFactory.
50 class V4UpdateProtocolManagerFactoryImpl
51 : public V4UpdateProtocolManagerFactory {
52 public:
53 V4UpdateProtocolManagerFactoryImpl() {}
54 ~V4UpdateProtocolManagerFactoryImpl() override {}
55 V4UpdateProtocolManager* CreateProtocolManager(
56 net::URLRequestContextGetter* request_context_getter,
57 const V4ProtocolConfig& config) override {
58 return new V4UpdateProtocolManager(request_context_getter, config);
59 }
60
61 private:
62 DISALLOW_COPY_AND_ASSIGN(V4UpdateProtocolManagerFactoryImpl);
63 };
64
65 // V4UpdateProtocolManager implementation --------------------------------
66
67 // static
68 V4UpdateProtocolManagerFactory* V4UpdateProtocolManager::factory_ = NULL;
69
70 // static
71 V4UpdateProtocolManager* V4UpdateProtocolManager::Create(
72 net::URLRequestContextGetter* request_context_getter,
73 const V4ProtocolConfig& config) {
74 if (!factory_)
75 factory_ = new V4UpdateProtocolManagerFactoryImpl();
76 return factory_->CreateProtocolManager(request_context_getter, config);
77 }
78
79 void V4UpdateProtocolManager::ResetUpdateErrors() {
80 update_error_count_ = 0;
81 update_back_off_mult_ = 1;
82 }
83
84 V4UpdateProtocolManager::V4UpdateProtocolManager(
85 net::URLRequestContextGetter* request_context_getter,
86 const V4ProtocolConfig& config)
87 : update_error_count_(0),
88 update_back_off_mult_(1),
89 next_update_time_(Time::FromDoubleT(0)),
90 config_(config),
91 request_context_getter_(request_context_getter),
92 url_fetcher_id_(0) {
93 }
94
95 // static
96 void V4UpdateProtocolManager::RecordUpdateResult(
97 OperationResultType result_type) {
98 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4UpdateResult", result_type,
99 OPERATION_RESULT_TYPE_MAX);
100 }
101
102 V4UpdateProtocolManager::~V4UpdateProtocolManager() {
103 // Delete in-progress SafeBrowsing requests.
104 STLDeleteContainerPairFirstPointers(update_requests_.begin(),
105 update_requests_.end());
106 update_requests_.clear();
107 }
108
109 std::string V4UpdateProtocolManager::GetUpdateRequest(
110 const base::hash_set<UpdateListIdentifier>& lists_to_update) {
111 // Build the request. Client info and client states are not added to the
112 // request protocol buffer. Client info is passed as params in the url.
113 FetchThreatListUpdatesRequest request;
114 for (const UpdateListIdentifier& list_to_update : lists_to_update) {
115 ListUpdateRequest* list_update_request = request.add_list_update_requests();
116 list_update_request->set_platform_type(list_to_update.platform_type);
117 list_update_request->set_threat_entry_type(
118 list_to_update.threat_entry_type);
119 list_update_request->set_threat_type(list_to_update.threat_type);
120 }
121
122 // Serialize and Base64 encode.
123 std::string req_data, req_base64;
124 request.SerializeToString(&req_data);
125 base::Base64Encode(req_data, &req_base64);
126
127 return req_base64;
128 }
129
130 bool V4UpdateProtocolManager::ParseUpdateResponse(
131 const std::string& data,
132 std::vector<ListUpdateResponse>* list_update_responses) {
133 FetchThreatListUpdatesResponse response;
134
135 if (!response.ParseFromString(data)) {
136 RecordParseUpdateResult(PARSE_FROM_STRING_ERROR);
137 return false;
138 }
139
140 if (response.has_minimum_wait_duration()) {
141 // Seconds resolution is good enough so we ignore the nanos field.
142 next_update_time_ =
143 Time::Now() + base::TimeDelta::FromSeconds(
144 response.minimum_wait_duration().seconds());
145 }
146
147 // TODO(vakh): Do something useful with this response.
148 // TODO(vakh): Update the list_states_ map correctly.
Nathan Parker 2016/02/23 18:47:06 I wonder if the client state should be passed into
vakh (use Gerrit instead) 2016/02/23 23:58:20 Done.
149 for (const ListUpdateResponse& list_update_response :
150 response.list_update_responses()) {
151 list_update_responses->push_back(list_update_response);
152 }
153 return true;
154 }
155
156 void V4UpdateProtocolManager::GetUpdates(
157 const base::hash_set<UpdateListIdentifier>& lists_to_update,
158 UpdateCallback callback) {
159 DCHECK(CalledOnValidThread());
160 // We need to wait the minimum waiting duration, and if we are in backoff,
161 // we need to check if we're past the next allowed time. If we are, we can
162 // proceed with the request. If not, we are required to return empty results
163 // (i.e. treat the page as safe).
164 if (Time::Now() <= next_update_time_) {
165 if (update_error_count_) {
166 RecordUpdateResult(ORT_BACKOFF_ERROR);
167 } else {
168 RecordUpdateResult(ORT_MIN_WAIT_DURATION_ERROR);
169 }
170 std::vector<ListUpdateResponse> list_update_responses;
171 callback.Run(list_update_responses);
172 return;
173 }
174
175 std::string req_base64 = GetUpdateRequest(lists_to_update);
176 GURL update_url = GetUpdateUrl(req_base64);
177
178 net::URLFetcher* fetcher =
179 net::URLFetcher::Create(url_fetcher_id_++, update_url,
180 net::URLFetcher::GET, this)
181 .release();
182 update_requests_[fetcher] = callback;
183
184 fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE);
185 fetcher->SetRequestContext(request_context_getter_.get());
186 fetcher->Start();
187 }
188
189 // net::URLFetcherDelegate implementation ----------------------------------
190
191 // SafeBrowsing request responses are handled here.
192 void V4UpdateProtocolManager::OnURLFetchComplete(
193 const net::URLFetcher* source) {
194 DCHECK(CalledOnValidThread());
195
196 UpdateRequests::iterator it = update_requests_.find(source);
197 DCHECK(it != update_requests_.end()) << "Request not found";
198
199 // FetchThreatListUpdatesResponse response.
200 // Reset the scoped pointer so the fetcher gets destroyed properly.
201 scoped_ptr<const net::URLFetcher> fetcher(it->first);
202
203 int response_code = source->GetResponseCode();
204 net::URLRequestStatus status = source->GetStatus();
205 V4ProtocolManagerUtil::RecordHttpResponseOrErrorCode(
206 kUmaV4UpdateResponseMetricName, status, response_code);
207
208 const UpdateCallback& callback = it->second;
209 std::vector<FetchThreatListUpdatesResponse::ListUpdateResponse>
210 list_update_responses;
211 if (status.is_success() && response_code == net::HTTP_OK) {
212 RecordUpdateResult(ORT_STATUS_200);
213 ResetUpdateErrors();
214 std::string data;
215 source->GetResponseAsString(&data);
216 if (!ParseUpdateResponse(data, &list_update_responses)) {
217 list_update_responses.clear();
218 RecordUpdateResult(ORT_PARSE_ERROR);
219 }
220 } else {
221 HandleUpdateError(Time::Now());
222
223 DVLOG(1) << "SafeBrowsing GetEncodedUpdates request for: "
224 << source->GetURL() << " failed with error: " << status.error()
225 << " and response code: " << response_code;
226
227 if (status.status() == net::URLRequestStatus::FAILED) {
228 RecordUpdateResult(ORT_NETWORK_ERROR);
229 } else {
230 RecordUpdateResult(ORT_HTTP_ERROR);
231 }
232 }
233
234 // Invoke the callback with list_update_responses, even if there was a parse
235 // error or an error response code (in which case list_update_responses will
236 // be empty). The caller can't be blocked indefinitely.
237 callback.Run(list_update_responses);
238
239 update_requests_.erase(it);
240 }
241
242 void V4UpdateProtocolManager::HandleUpdateError(const Time& now) {
243 DCHECK(CalledOnValidThread());
244 base::TimeDelta next = V4ProtocolManagerUtil::GetNextBackOffInterval(
245 &update_error_count_, &update_back_off_mult_);
246 next_update_time_ = now + next;
247 }
248
249 GURL V4UpdateProtocolManager::GetUpdateUrl(
250 const std::string& req_base64) const {
251 return V4ProtocolManagerUtil::GetRequestUrl(req_base64, "encodedUpdates",
252 config_);
253 }
254
255 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698