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/format_macros.h" | |
9 #include "base/logging.h" | 10 #include "base/logging.h" |
10 #include "base/memory/ref_counted.h" | 11 #include "base/memory/ref_counted.h" |
11 #include "base/stl_util.h" | 12 #include "base/stl_util.h" |
13 #include "base/strings/stringprintf.h" | |
12 #include "base/values.h" | 14 #include "base/values.h" |
13 #include "components/safe_json/safe_json_parser.h" | 15 #include "components/safe_json/safe_json_parser.h" |
14 #include "net/base/io_buffer.h" | 16 #include "net/base/io_buffer.h" |
15 #include "net/base/load_flags.h" | 17 #include "net/base/load_flags.h" |
16 #include "net/base/net_errors.h" | 18 #include "net/base/net_errors.h" |
17 #include "net/base/request_priority.h" | 19 #include "net/base/request_priority.h" |
18 #include "net/cert/ct_log_response_parser.h" | 20 #include "net/cert/ct_log_response_parser.h" |
19 #include "net/cert/signed_tree_head.h" | 21 #include "net/cert/signed_tree_head.h" |
20 #include "net/http/http_status_code.h" | 22 #include "net/http/http_status_code.h" |
21 #include "net/url_request/url_request_context.h" | 23 #include "net/url_request/url_request_context.h" |
(...skipping 11 matching lines...) Expand all Loading... | |
33 case net::URLRequestStatus::CANCELED: | 35 case net::URLRequestStatus::CANCELED: |
34 return net::ERR_ABORTED; | 36 return net::ERR_ABORTED; |
35 case net::URLRequestStatus::FAILED: | 37 case net::URLRequestStatus::FAILED: |
36 return status.error(); | 38 return status.error(); |
37 default: | 39 default: |
38 NOTREACHED(); | 40 NOTREACHED(); |
39 return net::ERR_FAILED; | 41 return net::ERR_FAILED; |
40 } | 42 } |
41 } | 43 } |
42 | 44 |
45 class LogRequest { | |
46 public: | |
47 LogRequest(const LogProofFetcher::FetchFailedCallback& failure_callback); | |
mmenke
2015/12/01 16:23:49
explicit
Eran Messeri
2015/12/04 11:41:44
N/A anymore.
| |
48 virtual ~LogRequest(); | |
49 | |
50 virtual void HandleParsedJson(const std::string& log_id, | |
51 const base::Value& parsed_json) = 0; | |
52 | |
53 virtual void HandleFailure(const std::string& log_id, | |
54 int net_error, | |
55 int http_response_code); | |
56 | |
57 virtual const std::string& RequestSuffix() = 0; | |
58 | |
59 protected: | |
60 LogProofFetcher::FetchFailedCallback failure_callback_; | |
mmenke
2015/12/01 16:23:49
const?
Eran Messeri
2015/12/04 11:41:44
Done.
| |
61 }; | |
62 | |
63 LogRequest::LogRequest( | |
64 const LogProofFetcher::FetchFailedCallback& failure_callback) | |
65 : failure_callback_(failure_callback) { | |
66 DCHECK(!failure_callback_.is_null()); | |
67 } | |
68 | |
69 LogRequest::~LogRequest() {} | |
70 | |
71 void LogRequest::HandleFailure(const std::string& log_id, | |
72 int net_error, | |
73 int http_response_code) { | |
74 failure_callback_.Run(log_id, net_error, http_response_code); | |
75 } | |
76 | |
77 class GetSTHLogRequest : public LogRequest { | |
78 public: | |
79 GetSTHLogRequest( | |
80 const LogProofFetcher::SignedTreeHeadFetchedCallback& sth_fetch_callback, | |
81 const LogProofFetcher::FetchFailedCallback& failure_callback) | |
82 : LogRequest(failure_callback), sth_fetched_(sth_fetch_callback) {} | |
83 | |
84 void HandleParsedJson(const std::string& log_id, | |
85 const base::Value& parsed_json) override { | |
86 net::ct::SignedTreeHead signed_tree_head; | |
87 if (net::ct::FillSignedTreeHead(parsed_json, &signed_tree_head)) { | |
88 sth_fetched_.Run(log_id, signed_tree_head); | |
89 } else { | |
90 failure_callback_.Run(log_id, net::ERR_CT_STH_INCOMPLETE, net::HTTP_OK); | |
91 } | |
92 } | |
93 | |
94 const std::string& RequestSuffix() override { | |
95 static const std::string get_sth("ct/v1/get-sth"); | |
96 return get_sth; | |
97 } | |
98 | |
99 private: | |
100 LogProofFetcher::SignedTreeHeadFetchedCallback sth_fetched_; | |
101 }; | |
102 | |
103 class GetConsistencyProofLogRequest : public LogRequest { | |
104 public: | |
105 GetConsistencyProofLogRequest( | |
106 uint64_t first_tree_size, | |
107 uint64_t second_tree_size, | |
108 const LogProofFetcher::ConsistencyProofFetchedCallback& | |
109 proof_fetch_callback, | |
110 const LogProofFetcher::FetchFailedCallback& failure_callback) | |
111 : LogRequest(failure_callback), proof_fetched_(proof_fetch_callback) { | |
112 fetch_suffix_ = | |
113 base::StringPrintf("ct/v1/get-sth-consistency?first=%lu&second=%lu", | |
114 first_tree_size, second_tree_size); | |
115 } | |
116 | |
117 void HandleParsedJson(const std::string& log_id, | |
118 const base::Value& parsed_json) override { | |
119 std::vector<std::string> consistency_proof; | |
120 if (net::ct::FillConsistencyProof(parsed_json, &consistency_proof)) { | |
121 proof_fetched_.Run(log_id, consistency_proof); | |
122 } else { | |
123 failure_callback_.Run( | |
124 log_id, net::ERR_CT_CONSISTENCY_PROOF_PARSING_FAILED, net::HTTP_OK); | |
125 } | |
126 } | |
127 | |
128 const std::string& RequestSuffix() override { return fetch_suffix_; } | |
129 | |
130 private: | |
131 LogProofFetcher::ConsistencyProofFetchedCallback proof_fetched_; | |
132 std::string fetch_suffix_; | |
133 }; | |
134 | |
43 } // namespace | 135 } // namespace |
44 | 136 |
45 struct LogProofFetcher::FetchState { | 137 struct LogProofFetcher::FetchState { |
46 FetchState(const std::string& log_id, | 138 // Takes ownership of the |request_handler| |
47 const SignedTreeHeadFetchedCallback& fetched_callback, | 139 FetchState(const std::string& log_id, LogRequest* request_handler); |
mmenke
2015/12/01 16:23:49
Do we really need both a FetchState and a LogReque
Eran Messeri
2015/12/04 11:41:44
As discussed offline, I think the separation betwe
| |
48 const FetchFailedCallback& failed_callback); | |
49 ~FetchState(); | 140 ~FetchState(); |
50 | 141 |
51 std::string log_id; | 142 std::string log_id; |
52 SignedTreeHeadFetchedCallback fetched_callback; | 143 scoped_ptr<LogRequest> request_handler; |
53 FetchFailedCallback failed_callback; | |
54 scoped_refptr<net::IOBufferWithSize> response_buffer; | 144 scoped_refptr<net::IOBufferWithSize> response_buffer; |
55 std::string assembled_response; | 145 std::string assembled_response; |
56 }; | 146 }; |
57 | 147 |
58 LogProofFetcher::FetchState::FetchState( | 148 LogProofFetcher::FetchState::FetchState(const std::string& log_id, |
59 const std::string& log_id, | 149 LogRequest* request_handler) |
60 const SignedTreeHeadFetchedCallback& fetched_callback, | |
61 const FetchFailedCallback& failed_callback) | |
62 : log_id(log_id), | 150 : log_id(log_id), |
63 fetched_callback(fetched_callback), | 151 request_handler(request_handler), |
64 failed_callback(failed_callback), | |
65 response_buffer(new net::IOBufferWithSize(kMaxLogResponseSizeInBytes)) {} | 152 response_buffer(new net::IOBufferWithSize(kMaxLogResponseSizeInBytes)) {} |
66 | 153 |
67 LogProofFetcher::FetchState::~FetchState() {} | 154 LogProofFetcher::FetchState::~FetchState() {} |
68 | 155 |
69 LogProofFetcher::LogProofFetcher(net::URLRequestContext* request_context) | 156 LogProofFetcher::LogProofFetcher(net::URLRequestContext* request_context) |
70 : request_context_(request_context), weak_factory_(this) { | 157 : request_context_(request_context), weak_factory_(this) { |
71 DCHECK(request_context); | 158 DCHECK(request_context); |
72 } | 159 } |
73 | 160 |
74 LogProofFetcher::~LogProofFetcher() { | 161 LogProofFetcher::~LogProofFetcher() { |
75 STLDeleteContainerPairPointers(inflight_requests_.begin(), | 162 STLDeleteContainerPairPointers(inflight_requests_.begin(), |
76 inflight_requests_.end()); | 163 inflight_requests_.end()); |
77 } | 164 } |
78 | 165 |
79 void LogProofFetcher::FetchSignedTreeHead( | 166 void LogProofFetcher::FetchSignedTreeHead( |
80 const GURL& base_log_url, | 167 const GURL& base_log_url, |
81 const std::string& log_id, | 168 const std::string& log_id, |
82 const SignedTreeHeadFetchedCallback& fetched_callback, | 169 const SignedTreeHeadFetchedCallback& fetched_callback, |
83 const FetchFailedCallback& failed_callback) { | 170 const FetchFailedCallback& failed_callback) { |
171 FetchState* fetch_state = new FetchState( | |
172 log_id, new GetSTHLogRequest(fetched_callback, failed_callback)); | |
173 FetchFromLog(base_log_url, log_id, fetch_state); | |
174 } | |
175 | |
176 void LogProofFetcher::FetchConsistencyProof( | |
177 const GURL& base_log_url, | |
178 const std::string& log_id, | |
179 uint64_t old_tree_size, | |
180 uint64_t new_tree_size, | |
181 const ConsistencyProofFetchedCallback& fetched_callback, | |
182 const FetchFailedCallback& failed_callback) { | |
183 FetchState* fetch_state = new FetchState( | |
184 log_id, | |
185 new GetConsistencyProofLogRequest(old_tree_size, new_tree_size, | |
186 fetched_callback, failed_callback)); | |
187 FetchFromLog(base_log_url, log_id, fetch_state); | |
188 } | |
189 | |
190 void LogProofFetcher::FetchFromLog(const GURL& base_log_url, | |
191 const std::string& log_id, | |
192 FetchState* fetch_state) { | |
84 DCHECK(base_log_url.SchemeIsHTTPOrHTTPS()); | 193 DCHECK(base_log_url.SchemeIsHTTPOrHTTPS()); |
85 GURL fetch_url(base_log_url.Resolve("ct/v1/get-sth")); | 194 |
195 GURL request_url = | |
196 base_log_url.Resolve(fetch_state->request_handler->RequestSuffix()); | |
197 | |
86 scoped_ptr<net::URLRequest> request = | 198 scoped_ptr<net::URLRequest> request = |
87 request_context_->CreateRequest(fetch_url, net::DEFAULT_PRIORITY, this); | 199 request_context_->CreateRequest(request_url, net::DEFAULT_PRIORITY, this); |
88 request->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | 200 request->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
89 net::LOAD_DO_NOT_SAVE_COOKIES | | 201 net::LOAD_DO_NOT_SAVE_COOKIES | |
90 net::LOAD_DO_NOT_SEND_AUTH_DATA); | 202 net::LOAD_DO_NOT_SEND_AUTH_DATA); |
91 | 203 |
92 FetchState* fetch_state = | |
93 new FetchState(log_id, fetched_callback, failed_callback); | |
94 request->Start(); | 204 request->Start(); |
95 inflight_requests_.insert(std::make_pair(request.release(), fetch_state)); | 205 inflight_requests_.insert(std::make_pair(request.release(), fetch_state)); |
96 } | 206 } |
97 | 207 |
98 void LogProofFetcher::OnResponseStarted(net::URLRequest* request) { | 208 void LogProofFetcher::OnResponseStarted(net::URLRequest* request) { |
99 net::URLRequestStatus status(request->status()); | 209 net::URLRequestStatus status(request->status()); |
100 DCHECK(inflight_requests_.count(request)); | 210 DCHECK(inflight_requests_.count(request)); |
101 FetchState* fetch_state = inflight_requests_.find(request)->second; | 211 FetchState* fetch_state = inflight_requests_.find(request)->second; |
102 | 212 |
103 if (!status.is_success() || request->GetResponseCode() != net::HTTP_OK) { | 213 if (!status.is_success() || request->GetResponseCode() != net::HTTP_OK) { |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
180 | 290 |
181 void LogProofFetcher::RequestComplete(net::URLRequest* request) { | 291 void LogProofFetcher::RequestComplete(net::URLRequest* request) { |
182 DCHECK(inflight_requests_.count(request)); | 292 DCHECK(inflight_requests_.count(request)); |
183 | 293 |
184 FetchState* fetch_state = inflight_requests_.find(request)->second; | 294 FetchState* fetch_state = inflight_requests_.find(request)->second; |
185 | 295 |
186 // Get rid of the buffer as it really isn't necessary. | 296 // Get rid of the buffer as it really isn't necessary. |
187 fetch_state->response_buffer = nullptr; | 297 fetch_state->response_buffer = nullptr; |
188 safe_json::SafeJsonParser::Parse( | 298 safe_json::SafeJsonParser::Parse( |
189 fetch_state->assembled_response, | 299 fetch_state->assembled_response, |
190 base::Bind(&LogProofFetcher::OnSTHJsonParseSuccess, | 300 base::Bind(&LogProofFetcher::OnJsonParseSuccess, |
191 weak_factory_.GetWeakPtr(), request), | 301 weak_factory_.GetWeakPtr(), request), |
192 base::Bind(&LogProofFetcher::OnSTHJsonParseError, | 302 base::Bind(&LogProofFetcher::OnJsonParseError, weak_factory_.GetWeakPtr(), |
193 weak_factory_.GetWeakPtr(), request)); | 303 request)); |
194 } | 304 } |
195 | 305 |
196 void LogProofFetcher::CleanupRequest(net::URLRequest* request) { | 306 void LogProofFetcher::CleanupRequest(net::URLRequest* request) { |
197 DVLOG(1) << "Cleaning up request to " << request->original_url(); | 307 DVLOG(1) << "Cleaning up request to " << request->original_url(); |
198 auto it = inflight_requests_.find(request); | 308 auto it = inflight_requests_.find(request); |
199 DCHECK(it != inflight_requests_.end()); | 309 DCHECK(it != inflight_requests_.end()); |
200 auto next_it = it; | 310 auto next_it = it; |
201 std::advance(next_it, 1); | 311 std::advance(next_it, 1); |
202 | 312 |
203 // Delete FetchState and URLRequest, then the entry from inflight_requests_. | 313 // Delete FetchState and URLRequest, then the entry from inflight_requests_. |
204 STLDeleteContainerPairPointers(it, next_it); | 314 STLDeleteContainerPairPointers(it, next_it); |
205 inflight_requests_.erase(it); | 315 inflight_requests_.erase(it); |
206 } | 316 } |
207 | 317 |
208 void LogProofFetcher::InvokeFailureCallback(net::URLRequest* request, | 318 void LogProofFetcher::InvokeFailureCallback(net::URLRequest* request, |
209 int net_error, | 319 int net_error, |
210 int http_response_code) { | 320 int http_response_code) { |
211 DCHECK(inflight_requests_.count(request)); | 321 DCHECK(inflight_requests_.count(request)); |
212 auto it = inflight_requests_.find(request); | 322 auto it = inflight_requests_.find(request); |
213 FetchState* fetch_state = it->second; | 323 FetchState* fetch_state = it->second; |
214 | 324 |
215 fetch_state->failed_callback.Run(fetch_state->log_id, net_error, | 325 fetch_state->request_handler->HandleFailure(fetch_state->log_id, net_error, |
216 http_response_code); | 326 http_response_code); |
217 CleanupRequest(request); | 327 CleanupRequest(request); |
218 } | 328 } |
219 | 329 |
220 void LogProofFetcher::OnSTHJsonParseSuccess( | 330 void LogProofFetcher::OnJsonParseSuccess(net::URLRequest* request, |
221 net::URLRequest* request, | 331 scoped_ptr<base::Value> parsed_json) { |
222 scoped_ptr<base::Value> parsed_json) { | |
223 DCHECK(inflight_requests_.count(request)); | 332 DCHECK(inflight_requests_.count(request)); |
224 | 333 |
225 FetchState* fetch_state = inflight_requests_.find(request)->second; | 334 FetchState* fetch_state = inflight_requests_.find(request)->second; |
226 net::ct::SignedTreeHead signed_tree_head; | 335 fetch_state->request_handler->HandleParsedJson(fetch_state->log_id, |
227 if (net::ct::FillSignedTreeHead(*parsed_json.get(), &signed_tree_head)) { | 336 *parsed_json); |
228 fetch_state->fetched_callback.Run(fetch_state->log_id, signed_tree_head); | |
229 } else { | |
230 fetch_state->failed_callback.Run(fetch_state->log_id, | |
231 net::ERR_CT_STH_INCOMPLETE, net::HTTP_OK); | |
232 } | |
233 | 337 |
234 CleanupRequest(request); | 338 CleanupRequest(request); |
235 } | 339 } |
236 | 340 |
237 void LogProofFetcher::OnSTHJsonParseError(net::URLRequest* request, | 341 void LogProofFetcher::OnJsonParseError(net::URLRequest* request, |
238 const std::string& error) { | 342 const std::string& error) { |
239 InvokeFailureCallback(request, net::ERR_CT_STH_PARSING_FAILED, net::HTTP_OK); | 343 InvokeFailureCallback(request, net::ERR_CT_STH_PARSING_FAILED, net::HTTP_OK); |
240 } | 344 } |
241 | 345 |
242 } // namespace certificate_transparency | 346 } // namespace certificate_transparency |
OLD | NEW |