OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/certificate_transparency/log_proof_fetcher.h" | 5 #include "components/certificate_transparency/log_proof_fetcher.h" |
6 | 6 |
7 #include <iterator> | 7 #include <iterator> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/memory/ref_counted.h" | 10 #include "base/memory/ref_counted.h" |
11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
12 #include "base/strings/stringprintf.h" | |
12 #include "base/values.h" | 13 #include "base/values.h" |
13 #include "components/safe_json/safe_json_parser.h" | 14 #include "components/safe_json/safe_json_parser.h" |
14 #include "net/base/io_buffer.h" | 15 #include "net/base/io_buffer.h" |
15 #include "net/base/load_flags.h" | 16 #include "net/base/load_flags.h" |
16 #include "net/base/net_errors.h" | 17 #include "net/base/net_errors.h" |
17 #include "net/base/request_priority.h" | 18 #include "net/base/request_priority.h" |
18 #include "net/cert/ct_log_response_parser.h" | 19 #include "net/cert/ct_log_response_parser.h" |
19 #include "net/cert/signed_tree_head.h" | 20 #include "net/cert/signed_tree_head.h" |
20 #include "net/http/http_status_code.h" | 21 #include "net/http/http_status_code.h" |
21 #include "net/url_request/url_request_context.h" | 22 #include "net/url_request/url_request_context.h" |
(...skipping 11 matching lines...) Expand all Loading... | |
33 case net::URLRequestStatus::CANCELED: | 34 case net::URLRequestStatus::CANCELED: |
34 return net::ERR_ABORTED; | 35 return net::ERR_ABORTED; |
35 case net::URLRequestStatus::FAILED: | 36 case net::URLRequestStatus::FAILED: |
36 return status.error(); | 37 return status.error(); |
37 default: | 38 default: |
38 NOTREACHED(); | 39 NOTREACHED(); |
39 return net::ERR_FAILED; | 40 return net::ERR_FAILED; |
40 } | 41 } |
41 } | 42 } |
42 | 43 |
44 enum LogRequestType { SIGNED_TREE_HEAD, CONSISTENCY_PROOF }; | |
45 | |
46 template <typename T> | |
47 size_t InsertCallbackToMap(std::map<size_t, T>* callbacks_map, T callback) { | |
48 size_t callback_id = callbacks_map->size(); | |
49 while (callbacks_map->find(callback_id) != callbacks_map->end()) | |
50 ++callback_id; | |
51 | |
52 callbacks_map->insert(std::make_pair(callback_id, callback)); | |
53 return callback_id; | |
54 } | |
55 | |
56 template <typename T> | |
57 T FindCallback(const std::map<size_t, T>& callbacks_map, size_t callback_id) { | |
58 auto callback_position = callbacks_map.find(callback_id); | |
59 CHECK(callback_position != callbacks_map.end()); | |
60 return callback_position->second; | |
61 } | |
62 | |
43 } // namespace | 63 } // namespace |
44 | 64 |
45 struct LogProofFetcher::FetchState { | 65 struct LogProofFetcher::FetchState { |
46 FetchState(const std::string& log_id, | 66 FetchState(const std::string& log_id, |
47 const SignedTreeHeadFetchedCallback& fetched_callback, | 67 LogRequestType request_type, |
68 size_t callback_id, | |
48 const FetchFailedCallback& failed_callback); | 69 const FetchFailedCallback& failed_callback); |
49 ~FetchState(); | 70 ~FetchState(); |
50 | 71 |
51 std::string log_id; | 72 std::string log_id; |
52 SignedTreeHeadFetchedCallback fetched_callback; | 73 LogRequestType request_type; |
74 size_t callback_id; | |
53 FetchFailedCallback failed_callback; | 75 FetchFailedCallback failed_callback; |
svaldez
2015/11/12 20:11:03
Can't you just add:
SignedTreeHeadFetchedCallback
Eran Messeri
2015/11/16 13:39:46
Done - it does simplify the design.
| |
54 scoped_refptr<net::IOBufferWithSize> response_buffer; | 76 scoped_refptr<net::IOBufferWithSize> response_buffer; |
55 std::string assembled_response; | 77 std::string assembled_response; |
56 }; | 78 }; |
57 | 79 |
58 LogProofFetcher::FetchState::FetchState( | 80 LogProofFetcher::FetchState::FetchState( |
59 const std::string& log_id, | 81 const std::string& log_id, |
60 const SignedTreeHeadFetchedCallback& fetched_callback, | 82 LogRequestType request_type, |
83 size_t callback_id, | |
61 const FetchFailedCallback& failed_callback) | 84 const FetchFailedCallback& failed_callback) |
62 : log_id(log_id), | 85 : log_id(log_id), |
63 fetched_callback(fetched_callback), | 86 request_type(request_type), |
87 callback_id(callback_id), | |
64 failed_callback(failed_callback), | 88 failed_callback(failed_callback), |
65 response_buffer(new net::IOBufferWithSize(kMaxLogResponseSizeInBytes)) {} | 89 response_buffer(new net::IOBufferWithSize(kMaxLogResponseSizeInBytes)) {} |
66 | 90 |
67 LogProofFetcher::FetchState::~FetchState() {} | 91 LogProofFetcher::FetchState::~FetchState() {} |
68 | 92 |
69 LogProofFetcher::LogProofFetcher(net::URLRequestContext* request_context) | 93 LogProofFetcher::LogProofFetcher(net::URLRequestContext* request_context) |
70 : request_context_(request_context), weak_factory_(this) { | 94 : request_context_(request_context), weak_factory_(this) { |
71 DCHECK(request_context); | 95 DCHECK(request_context); |
72 } | 96 } |
73 | 97 |
74 LogProofFetcher::~LogProofFetcher() { | 98 LogProofFetcher::~LogProofFetcher() { |
75 STLDeleteContainerPairPointers(inflight_requests_.begin(), | 99 STLDeleteContainerPairPointers(inflight_requests_.begin(), |
76 inflight_requests_.end()); | 100 inflight_requests_.end()); |
77 } | 101 } |
78 | 102 |
79 void LogProofFetcher::FetchSignedTreeHead( | 103 void LogProofFetcher::FetchSignedTreeHead( |
80 const GURL& base_log_url, | 104 const GURL& base_log_url, |
81 const std::string& log_id, | 105 const std::string& log_id, |
82 const SignedTreeHeadFetchedCallback& fetched_callback, | 106 const SignedTreeHeadFetchedCallback& fetched_callback, |
83 const FetchFailedCallback& failed_callback) { | 107 const FetchFailedCallback& failed_callback) { |
84 DCHECK(base_log_url.SchemeIsHTTPOrHTTPS()); | 108 DCHECK(base_log_url.SchemeIsHTTPOrHTTPS()); |
85 GURL fetch_url(base_log_url.Resolve("ct/v1/get-sth")); | 109 GURL fetch_url(base_log_url.Resolve("ct/v1/get-sth")); |
86 scoped_ptr<net::URLRequest> request = | 110 net::URLRequest* request = CreateRequest(fetch_url); |
87 request_context_->CreateRequest(fetch_url, net::DEFAULT_PRIORITY, this); | |
88 request->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | |
89 net::LOAD_DO_NOT_SAVE_COOKIES | | |
90 net::LOAD_DO_NOT_SEND_AUTH_DATA); | |
91 | 111 |
92 FetchState* fetch_state = | 112 size_t callback_id = |
93 new FetchState(log_id, fetched_callback, failed_callback); | 113 InsertCallbackToMap(&sth_fetch_callbacks_, fetched_callback); |
114 FetchState* fetch_state = new FetchState( | |
115 log_id, LogRequestType::SIGNED_TREE_HEAD, callback_id, failed_callback); | |
94 request->Start(); | 116 request->Start(); |
95 inflight_requests_.insert(std::make_pair(request.release(), fetch_state)); | 117 inflight_requests_.insert(std::make_pair(request, fetch_state)); |
118 } | |
119 | |
120 void LogProofFetcher::FetchConsistencyProof( | |
121 const GURL& base_log_url, | |
122 const std::string& log_id, | |
123 size_t old_tree_size, | |
124 size_t new_tree_size, | |
125 const ConsistencyProofFetchedCallback& fetched_callback, | |
126 const FetchFailedCallback& failed_callback) { | |
127 DCHECK(base_log_url.SchemeIsHTTPOrHTTPS()); | |
128 std::string query = | |
129 base::StringPrintf("first=%lu&second=%lu", old_tree_size, new_tree_size); | |
130 GURL::Replacements replacements; | |
131 replacements.SetQueryStr(query); | |
132 GURL fetch_url = base_log_url.Resolve("ct/v1/get-sth-consistency") | |
133 .ReplaceComponents(replacements); | |
svaldez
2015/11/12 20:11:03
Can't you just do:
std::string relative = StringP
Eran Messeri
2015/11/16 13:39:46
Done.
| |
134 | |
135 net::URLRequest* request = CreateRequest(fetch_url); | |
136 | |
137 size_t callback_id = | |
138 InsertCallbackToMap(&consistency_fetch_callbacks_, fetched_callback); | |
139 FetchState* fetch_state = new FetchState( | |
140 log_id, LogRequestType::CONSISTENCY_PROOF, callback_id, failed_callback); | |
141 request->Start(); | |
142 inflight_requests_.insert(std::make_pair(request, fetch_state)); | |
96 } | 143 } |
97 | 144 |
98 void LogProofFetcher::OnResponseStarted(net::URLRequest* request) { | 145 void LogProofFetcher::OnResponseStarted(net::URLRequest* request) { |
99 net::URLRequestStatus status(request->status()); | 146 net::URLRequestStatus status(request->status()); |
100 DCHECK(inflight_requests_.count(request)); | 147 DCHECK(inflight_requests_.count(request)); |
101 FetchState* fetch_state = inflight_requests_.find(request)->second; | 148 FetchState* fetch_state = inflight_requests_.find(request)->second; |
102 | 149 |
103 if (!status.is_success() || request->GetResponseCode() != net::HTTP_OK) { | 150 if (!status.is_success() || request->GetResponseCode() != net::HTTP_OK) { |
104 int net_error = net::OK; | 151 int net_error = net::OK; |
105 int http_response_code = request->GetResponseCode(); | 152 int http_response_code = request->GetResponseCode(); |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
178 } | 225 } |
179 } | 226 } |
180 | 227 |
181 void LogProofFetcher::RequestComplete(net::URLRequest* request) { | 228 void LogProofFetcher::RequestComplete(net::URLRequest* request) { |
182 DCHECK(inflight_requests_.count(request)); | 229 DCHECK(inflight_requests_.count(request)); |
183 | 230 |
184 FetchState* fetch_state = inflight_requests_.find(request)->second; | 231 FetchState* fetch_state = inflight_requests_.find(request)->second; |
185 | 232 |
186 // Get rid of the buffer as it really isn't necessary. | 233 // Get rid of the buffer as it really isn't necessary. |
187 fetch_state->response_buffer = nullptr; | 234 fetch_state->response_buffer = nullptr; |
188 safe_json::SafeJsonParser::Parse( | 235 if (fetch_state->request_type == LogRequestType::SIGNED_TREE_HEAD) { |
189 fetch_state->assembled_response, | 236 safe_json::SafeJsonParser::Parse( |
190 base::Bind(&LogProofFetcher::OnSTHJsonParseSuccess, | 237 fetch_state->assembled_response, |
191 weak_factory_.GetWeakPtr(), request), | 238 base::Bind(&LogProofFetcher::OnSTHJsonParseSuccess, |
192 base::Bind(&LogProofFetcher::OnSTHJsonParseError, | 239 weak_factory_.GetWeakPtr(), request), |
193 weak_factory_.GetWeakPtr(), request)); | 240 base::Bind(&LogProofFetcher::OnSTHJsonParseError, |
241 weak_factory_.GetWeakPtr(), request)); | |
242 } else if (fetch_state->request_type == LogRequestType::CONSISTENCY_PROOF) { | |
243 safe_json::SafeJsonParser::Parse( | |
244 fetch_state->assembled_response, | |
245 base::Bind(&LogProofFetcher::OnConsistencyProofJsonParseSuccess, | |
246 weak_factory_.GetWeakPtr(), request), | |
247 base::Bind(&LogProofFetcher::OnConsistencyProofJsonParseError, | |
248 weak_factory_.GetWeakPtr(), request)); | |
249 } else { | |
250 NOTREACHED(); | |
251 } | |
194 } | 252 } |
195 | 253 |
196 void LogProofFetcher::CleanupRequest(net::URLRequest* request) { | 254 void LogProofFetcher::CleanupRequest(net::URLRequest* request) { |
197 DVLOG(1) << "Cleaning up request to " << request->original_url(); | 255 DVLOG(1) << "Cleaning up request to " << request->original_url(); |
198 auto it = inflight_requests_.find(request); | 256 auto it = inflight_requests_.find(request); |
199 DCHECK(it != inflight_requests_.end()); | 257 DCHECK(it != inflight_requests_.end()); |
258 | |
259 LogRequestType request_type = it->second->request_type; | |
260 size_t callback_id = it->second->callback_id; | |
261 if (request_type == SIGNED_TREE_HEAD) { | |
262 sth_fetch_callbacks_.erase(callback_id); | |
263 } else if (request_type == CONSISTENCY_PROOF) { | |
264 consistency_fetch_callbacks_.erase(callback_id); | |
265 } | |
200 auto next_it = it; | 266 auto next_it = it; |
201 std::advance(next_it, 1); | 267 std::advance(next_it, 1); |
202 | 268 |
203 // Delete FetchState and URLRequest, then the entry from inflight_requests_. | 269 // Delete FetchState and URLRequest, then the entry from inflight_requests_. |
204 STLDeleteContainerPairPointers(it, next_it); | 270 STLDeleteContainerPairPointers(it, next_it); |
205 inflight_requests_.erase(it); | 271 inflight_requests_.erase(it); |
206 } | 272 } |
207 | 273 |
208 void LogProofFetcher::InvokeFailureCallback(net::URLRequest* request, | 274 void LogProofFetcher::InvokeFailureCallback(net::URLRequest* request, |
209 int net_error, | 275 int net_error, |
210 int http_response_code) { | 276 int http_response_code) { |
211 DCHECK(inflight_requests_.count(request)); | 277 DCHECK(inflight_requests_.count(request)); |
212 auto it = inflight_requests_.find(request); | 278 auto it = inflight_requests_.find(request); |
213 FetchState* fetch_state = it->second; | 279 FetchState* fetch_state = it->second; |
214 | 280 |
215 fetch_state->failed_callback.Run(fetch_state->log_id, net_error, | 281 fetch_state->failed_callback.Run(fetch_state->log_id, net_error, |
216 http_response_code); | 282 http_response_code); |
217 CleanupRequest(request); | 283 CleanupRequest(request); |
218 } | 284 } |
219 | 285 |
220 void LogProofFetcher::OnSTHJsonParseSuccess( | 286 void LogProofFetcher::OnSTHJsonParseSuccess( |
221 net::URLRequest* request, | 287 net::URLRequest* request, |
222 scoped_ptr<base::Value> parsed_json) { | 288 scoped_ptr<base::Value> parsed_json) { |
223 DCHECK(inflight_requests_.count(request)); | 289 DCHECK(inflight_requests_.count(request)); |
224 | 290 |
225 FetchState* fetch_state = inflight_requests_.find(request)->second; | 291 FetchState* fetch_state = inflight_requests_.find(request)->second; |
226 net::ct::SignedTreeHead signed_tree_head; | 292 net::ct::SignedTreeHead signed_tree_head; |
227 if (net::ct::FillSignedTreeHead(*parsed_json.get(), &signed_tree_head)) { | 293 if (net::ct::FillSignedTreeHead(*parsed_json.get(), &signed_tree_head)) { |
228 fetch_state->fetched_callback.Run(fetch_state->log_id, signed_tree_head); | 294 SignedTreeHeadFetchedCallback fetched_callback = |
295 FindCallback(sth_fetch_callbacks_, fetch_state->callback_id); | |
296 fetched_callback.Run(fetch_state->log_id, signed_tree_head); | |
229 } else { | 297 } else { |
230 fetch_state->failed_callback.Run(fetch_state->log_id, | 298 fetch_state->failed_callback.Run(fetch_state->log_id, |
231 net::ERR_CT_STH_INCOMPLETE, net::HTTP_OK); | 299 net::ERR_CT_STH_INCOMPLETE, net::HTTP_OK); |
232 } | 300 } |
233 | 301 |
234 CleanupRequest(request); | 302 CleanupRequest(request); |
235 } | 303 } |
236 | 304 |
237 void LogProofFetcher::OnSTHJsonParseError(net::URLRequest* request, | 305 void LogProofFetcher::OnSTHJsonParseError(net::URLRequest* request, |
238 const std::string& error) { | 306 const std::string& error) { |
239 InvokeFailureCallback(request, net::ERR_CT_STH_PARSING_FAILED, net::HTTP_OK); | 307 InvokeFailureCallback(request, net::ERR_CT_STH_PARSING_FAILED, net::HTTP_OK); |
240 } | 308 } |
241 | 309 |
310 void LogProofFetcher::OnConsistencyProofJsonParseSuccess( | |
311 net::URLRequest* request, | |
312 scoped_ptr<base::Value> parsed_json) { | |
313 DCHECK(inflight_requests_.count(request)); | |
314 FetchState* fetch_state = inflight_requests_.find(request)->second; | |
315 std::vector<std::string> consistency_proof; | |
316 if (net::ct::FillConsistencyProof(*parsed_json.get(), &consistency_proof)) { | |
317 ConsistencyProofFetchedCallback fetched_callback = | |
318 FindCallback(consistency_fetch_callbacks_, fetch_state->callback_id); | |
319 fetched_callback.Run(fetch_state->log_id, consistency_proof); | |
320 } else { | |
321 fetch_state->failed_callback.Run( | |
322 fetch_state->log_id, net::ERR_CT_CONSISTENCY_PROOF_PARSING_FAILED, | |
323 net::HTTP_OK); | |
324 } | |
325 | |
326 CleanupRequest(request); | |
327 } | |
328 | |
329 void LogProofFetcher::OnConsistencyProofJsonParseError( | |
330 net::URLRequest* request, | |
331 const std::string& error) { | |
332 InvokeFailureCallback(request, net::ERR_CT_CONSISTENCY_PROOF_PARSING_FAILED, | |
333 net::HTTP_OK); | |
334 } | |
335 | |
336 net::URLRequest* LogProofFetcher::CreateRequest(const GURL& url) { | |
337 scoped_ptr<net::URLRequest> request = | |
338 request_context_->CreateRequest(url, net::DEFAULT_PRIORITY, this); | |
339 request->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | |
340 net::LOAD_DO_NOT_SAVE_COOKIES | | |
341 net::LOAD_DO_NOT_SEND_AUTH_DATA); | |
342 return request.release(); | |
343 } | |
344 | |
242 } // namespace certificate_transparency | 345 } // namespace certificate_transparency |
OLD | NEW |