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

Side by Side Diff: blimp/client/core/session/assignment_source.cc

Issue 2624903006: Remove all blimp client code. (Closed)
Patch Set: Update buildbot configuration Created 3 years, 11 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 "blimp/client/core/session/assignment_source.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/callback_helpers.h"
12 #include "base/command_line.h"
13 #include "base/files/file_util.h"
14 #include "base/json/json_reader.h"
15 #include "base/json/json_writer.h"
16 #include "base/location.h"
17 #include "base/memory/ref_counted.h"
18 #include "base/numerics/safe_conversions.h"
19 #include "base/single_thread_task_runner.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/task_runner_util.h"
22 #include "base/threading/thread_restrictions.h"
23 #include "base/values.h"
24 #include "blimp/client/core/switches/blimp_client_switches.h"
25 #include "blimp/common/get_client_auth_token.h"
26 #include "blimp/common/protocol_version.h"
27 #include "components/safe_json/safe_json_parser.h"
28 #include "net/base/ip_address.h"
29 #include "net/base/ip_endpoint.h"
30 #include "net/base/load_flags.h"
31 #include "net/base/net_errors.h"
32 #include "net/http/http_status_code.h"
33 #include "net/proxy/proxy_config_service.h"
34 #include "net/proxy/proxy_service.h"
35 #include "net/url_request/url_fetcher.h"
36 #include "net/url_request/url_request_context.h"
37 #include "net/url_request/url_request_context_builder.h"
38 #include "net/url_request/url_request_context_getter.h"
39
40 namespace blimp {
41 namespace client {
42
43 namespace {
44
45 // Assignment request JSON keys.
46 const char kProtocolVersionKey[] = "protocol_version";
47
48 // Assignment response JSON keys.
49 const char kClientAuthTokenKey[] = "clientToken";
50 const char kHostKey[] = "host";
51 const char kPortKey[] = "port";
52 const char kCertificateKey[] = "certificate";
53
54 // Possible arguments for the "--engine-transport" command line parameter.
55 const char kGrpcTransportValue[] = "grpc";
56 const char kSSLTransportValue[] = "ssl";
57 const char kTCPTransportValue[] = "tcp";
58
59 class SimpleURLRequestContextGetter : public net::URLRequestContextGetter {
60 public:
61 SimpleURLRequestContextGetter(
62 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
63 const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner)
64 : io_task_runner_(io_task_runner), file_task_runner_(file_task_runner) {}
65
66 // net::URLRequestContextGetter implementation.
67 net::URLRequestContext* GetURLRequestContext() override {
68 DCHECK(io_task_runner_->BelongsToCurrentThread());
69
70 if (!proxy_config_service_) {
71 proxy_config_service_ = net::ProxyService::CreateSystemProxyConfigService(
72 io_task_runner_, file_task_runner_);
73 }
74
75 if (!url_request_context_) {
76 net::URLRequestContextBuilder builder;
77 builder.set_proxy_config_service(std::move(proxy_config_service_));
78 builder.DisableHttpCache();
79 url_request_context_ = builder.Build();
80 }
81
82 return url_request_context_.get();
83 }
84
85 scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
86 const override {
87 return io_task_runner_;
88 }
89
90 private:
91 ~SimpleURLRequestContextGetter() override {
92 DCHECK(io_task_runner_->BelongsToCurrentThread());
93 }
94
95 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
96 scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
97 std::unique_ptr<net::URLRequestContext> url_request_context_;
98
99 // Constructed lazily on the IO thread by GetURLRequestContext().
100 std::unique_ptr<net::ProxyConfigService> proxy_config_service_;
101
102 DISALLOW_COPY_AND_ASSIGN(SimpleURLRequestContextGetter);
103 };
104
105 bool IsValidIpPortNumber(unsigned port) {
106 return port > 0 && port <= 65535;
107 }
108
109 // Populates an Assignment using command-line parameters, if provided.
110 // Returns a null Assignment if no parameters were set.
111 // Must be called on a thread suitable for file IO.
112 Assignment GetAssignmentFromCommandLine() {
113 Assignment assignment;
114
115 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
116 assignment.client_auth_token = GetClientAuthToken(*cmd_line);
117 CHECK(!assignment.client_auth_token.empty())
118 << "No client auth token provided.";
119
120 unsigned port_parsed = 0;
121 if (!base::StringToUint(
122 cmd_line->GetSwitchValueASCII(switches::kEnginePort),
123 &port_parsed) || !IsValidIpPortNumber(port_parsed)) {
124 DLOG(FATAL) << "--engine-port must be a value between 1 and 65535.";
125 return Assignment();
126 }
127
128 net::IPAddress ip_address;
129 std::string ip_str = cmd_line->GetSwitchValueASCII(switches::kEngineIP);
130 if (!ip_address.AssignFromIPLiteral(ip_str)) {
131 DLOG(FATAL) << "Invalid engine IP " << ip_str;
132 return Assignment();
133 }
134 assignment.engine_endpoint =
135 net::IPEndPoint(ip_address, base::checked_cast<uint16_t>(port_parsed));
136
137 std::string transport_str =
138 cmd_line->GetSwitchValueASCII(switches::kEngineTransport);
139 if (transport_str == kSSLTransportValue) {
140 assignment.transport_protocol = Assignment::TransportProtocol::SSL;
141 } else if (transport_str == kTCPTransportValue) {
142 assignment.transport_protocol = Assignment::TransportProtocol::TCP;
143 } else if (transport_str == kGrpcTransportValue) {
144 assignment.transport_protocol = Assignment::TransportProtocol::GRPC;
145 } else {
146 DLOG(FATAL) << "Invalid engine transport " << transport_str;
147 return Assignment();
148 }
149
150 scoped_refptr<net::X509Certificate> cert;
151 if (assignment.transport_protocol == Assignment::TransportProtocol::SSL) {
152 base::FilePath cert_path =
153 cmd_line->GetSwitchValuePath(switches::kEngineCertPath);
154 if (cert_path.empty()) {
155 DLOG(FATAL) << "Missing required parameter --"
156 << switches::kEngineCertPath << ".";
157 return Assignment();
158 }
159 std::string cert_str;
160 if (!base::ReadFileToString(cert_path, &cert_str)) {
161 DLOG(FATAL) << "Couldn't read from file: "
162 << cert_path.LossyDisplayName();
163 return Assignment();
164 }
165 net::CertificateList cert_list =
166 net::X509Certificate::CreateCertificateListFromBytes(
167 cert_str.data(), cert_str.size(),
168 net::X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
169 DLOG_IF(FATAL, (cert_list.size() != 1u))
170 << "Only one cert is allowed in PEM cert list.";
171 assignment.cert = std::move(cert_list[0]);
172 }
173
174 if (!assignment.IsValid()) {
175 DLOG(FATAL) << "Invalid command-line assignment.";
176 return Assignment();
177 }
178
179 return assignment;
180 }
181
182 } // namespace
183
184 AssignmentSource::AssignmentSource(
185 const GURL& assigner_endpoint,
186 const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner,
187 const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner)
188 : assigner_endpoint_(assigner_endpoint),
189 file_task_runner_(file_task_runner),
190 url_request_context_(
191 new SimpleURLRequestContextGetter(network_task_runner,
192 file_task_runner)),
193 weak_factory_(this) {
194 DCHECK(assigner_endpoint_.is_valid());
195 }
196
197 AssignmentSource::~AssignmentSource() {}
198
199 void AssignmentSource::GetAssignment(const std::string& client_auth_token,
200 const AssignmentCallback& callback) {
201 DCHECK(callback_.is_null());
202 callback_ = AssignmentCallback(callback);
203
204 if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kEngineIP)) {
205 base::PostTaskAndReplyWithResult(
206 file_task_runner_.get(), FROM_HERE,
207 base::Bind(&GetAssignmentFromCommandLine),
208 base::Bind(&AssignmentSource::OnGetAssignmentFromCommandLineDone,
209 weak_factory_.GetWeakPtr(), client_auth_token));
210 } else {
211 QueryAssigner(client_auth_token);
212 }
213 }
214
215 void AssignmentSource::OnGetAssignmentFromCommandLineDone(
216 const std::string& client_auth_token,
217 Assignment parsed_assignment) {
218 // If GetAssignmentFromCommandLine succeeded, then return its output.
219 if (parsed_assignment.IsValid()) {
220 base::ResetAndReturn(&callback_)
221 .Run(ASSIGNMENT_REQUEST_RESULT_OK, parsed_assignment);
222 return;
223 }
224
225 // If no assignment was passed via the command line, then fall back on
226 // querying the Assigner service.
227 QueryAssigner(client_auth_token);
228 }
229
230 void AssignmentSource::QueryAssigner(const std::string& client_auth_token) {
231 // Call out to the network for a real assignment. Build the network request
232 // to hit the assigner.
233 url_fetcher_ =
234 net::URLFetcher::Create(assigner_endpoint_, net::URLFetcher::POST, this);
235 url_fetcher_->SetRequestContext(url_request_context_.get());
236 url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
237 net::LOAD_DO_NOT_SEND_COOKIES);
238 url_fetcher_->AddExtraRequestHeader("Authorization: Bearer " +
239 client_auth_token);
240
241 // Write the JSON for the request data.
242 base::DictionaryValue dictionary;
243 dictionary.SetString(kProtocolVersionKey,
244 base::IntToString(kProtocolVersion));
245 std::string json;
246 base::JSONWriter::Write(dictionary, &json);
247 url_fetcher_->SetUploadData("application/json", json);
248 url_fetcher_->Start();
249 }
250
251 void AssignmentSource::OnURLFetchComplete(const net::URLFetcher* source) {
252 DCHECK(!callback_.is_null());
253 DCHECK_EQ(url_fetcher_.get(), source);
254
255 if (!source->GetStatus().is_success()) {
256 DVLOG(1) << "Assignment request failed due to network error: "
257 << net::ErrorToString(source->GetStatus().error());
258 base::ResetAndReturn(&callback_)
259 .Run(ASSIGNMENT_REQUEST_RESULT_NETWORK_FAILURE, Assignment());
260 return;
261 }
262
263 switch (source->GetResponseCode()) {
264 case net::HTTP_OK:
265 ParseAssignerResponse();
266 break;
267 case net::HTTP_BAD_REQUEST:
268 base::ResetAndReturn(&callback_)
269 .Run(ASSIGNMENT_REQUEST_RESULT_BAD_REQUEST, Assignment());
270 break;
271 case net::HTTP_UNAUTHORIZED:
272 base::ResetAndReturn(&callback_)
273 .Run(ASSIGNMENT_REQUEST_RESULT_EXPIRED_ACCESS_TOKEN, Assignment());
274 break;
275 case net::HTTP_FORBIDDEN:
276 base::ResetAndReturn(&callback_)
277 .Run(ASSIGNMENT_REQUEST_RESULT_USER_INVALID, Assignment());
278 break;
279 case 429: // Too Many Requests
280 base::ResetAndReturn(&callback_)
281 .Run(ASSIGNMENT_REQUEST_RESULT_OUT_OF_VMS, Assignment());
282 break;
283 case net::HTTP_INTERNAL_SERVER_ERROR:
284 base::ResetAndReturn(&callback_)
285 .Run(ASSIGNMENT_REQUEST_RESULT_SERVER_ERROR, Assignment());
286 break;
287 default:
288 LOG(WARNING) << "Defaulting to BAD_RESPONSE for HTTP response code "
289 << source->GetResponseCode();
290 base::ResetAndReturn(&callback_)
291 .Run(ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE, Assignment());
292 break;
293 }
294 }
295
296 void AssignmentSource::ParseAssignerResponse() {
297 DCHECK(url_fetcher_.get());
298 DCHECK(url_fetcher_->GetStatus().is_success());
299 DCHECK_EQ(net::HTTP_OK, url_fetcher_->GetResponseCode());
300
301 // Grab the response from the assigner request.
302 std::string response;
303 if (!url_fetcher_->GetResponseAsString(&response)) {
304 LOG(WARNING) << "Unable to retrieve response as string from URLFetcher.";
305 base::ResetAndReturn(&callback_)
306 .Run(ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE, Assignment());
307 return;
308 }
309
310 safe_json::SafeJsonParser::Parse(
311 response,
312 base::Bind(&AssignmentSource::OnJsonParsed, weak_factory_.GetWeakPtr()),
313 base::Bind(&AssignmentSource::OnJsonParseError,
314 weak_factory_.GetWeakPtr()));
315 }
316
317 void AssignmentSource::OnJsonParsed(std::unique_ptr<base::Value> json) {
318 const base::DictionaryValue* dict;
319 if (!json->GetAsDictionary(&dict)) {
320 LOG(WARNING) << "Unable to parse JSON data as a dictionary.";
321 base::ResetAndReturn(&callback_)
322 .Run(ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE, Assignment());
323 return;
324 }
325
326 // Validate that all the expected fields are present.
327 std::string client_auth_token;
328 std::string host;
329 int port;
330 std::string cert_str;
331 if (!(dict->GetString(kClientAuthTokenKey, &client_auth_token) &&
332 dict->GetString(kHostKey, &host) && dict->GetInteger(kPortKey, &port) &&
333 dict->GetString(kCertificateKey, &cert_str))) {
334 LOG(WARNING) << "Not all fields present in assignment JSON data.";
335 base::ResetAndReturn(&callback_)
336 .Run(ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE, Assignment());
337 return;
338 }
339
340 net::IPAddress ip_address;
341 if (!ip_address.AssignFromIPLiteral(host)) {
342 LOG(WARNING) << "Unable to assign IP address from string literal " << host;
343 base::ResetAndReturn(&callback_)
344 .Run(ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE, Assignment());
345 return;
346 }
347
348 if (!base::IsValueInRangeForNumericType<uint16_t>(port)) {
349 LOG(WARNING) << "Assignment port number not in range for uint16_t";
350 base::ResetAndReturn(&callback_)
351 .Run(ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE, Assignment());
352 return;
353 }
354
355 net::CertificateList cert_list =
356 net::X509Certificate::CreateCertificateListFromBytes(
357 cert_str.data(), cert_str.size(),
358 net::X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
359 if (cert_list.size() != 1) {
360 base::ResetAndReturn(&callback_)
361 .Run(ASSIGNMENT_REQUEST_RESULT_INVALID_CERT, Assignment());
362 return;
363 }
364
365 // The assigner assumes SSL-only and all engines it assigns only communicate
366 // over SSL.
367 Assignment assignment;
368 assignment.transport_protocol = Assignment::TransportProtocol::SSL;
369 assignment.engine_endpoint = net::IPEndPoint(ip_address, port);
370 assignment.client_auth_token = client_auth_token;
371 assignment.cert = std::move(cert_list[0]);
372
373 base::ResetAndReturn(&callback_)
374 .Run(ASSIGNMENT_REQUEST_RESULT_OK, assignment);
375 }
376
377 void AssignmentSource::OnJsonParseError(const std::string& error) {
378 DLOG(ERROR) << "Error while parsing assigner JSON: " << error;
379 base::ResetAndReturn(&callback_)
380 .Run(ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE, Assignment());
381 }
382
383 } // namespace client
384 } // namespace blimp
OLDNEW
« no previous file with comments | « blimp/client/core/session/assignment_source.h ('k') | blimp/client/core/session/assignment_source_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698