OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "components/copresence/rpc/rpc_handler.h" | |
6 | |
7 #include <stddef.h> | |
8 #include <stdint.h> | |
9 | |
10 #include <utility> | |
11 | |
12 #include "base/bind.h" | |
13 #include "base/command_line.h" | |
14 #include "base/logging.h" | |
15 #include "base/memory/ptr_util.h" | |
16 #include "base/strings/string_util.h" | |
17 #include "base/strings/stringprintf.h" | |
18 // TODO(ckehoe): time.h includes windows.h, which #defines DeviceCapabilities | |
19 // to DeviceCapabilitiesW. This breaks the pb.h headers below. For now, | |
20 // we fix this with an #undef. | |
21 #include "base/time/time.h" | |
22 #include "build/build_config.h" | |
23 #if defined(OS_WIN) | |
24 #undef DeviceCapabilities | |
25 #endif | |
26 | |
27 #include "components/audio_modem/public/audio_modem_types.h" | |
28 #include "components/copresence/copresence_state_impl.h" | |
29 #include "components/copresence/copresence_switches.h" | |
30 #include "components/copresence/handlers/directive_handler.h" | |
31 #include "components/copresence/handlers/gcm_handler.h" | |
32 #include "components/copresence/proto/codes.pb.h" | |
33 #include "components/copresence/proto/data.pb.h" | |
34 #include "components/copresence/proto/rpcs.pb.h" | |
35 #include "components/copresence/public/copresence_constants.h" | |
36 #include "components/copresence/public/copresence_delegate.h" | |
37 #include "components/copresence/rpc/http_post.h" | |
38 #include "net/http/http_status_code.h" | |
39 | |
40 using google::protobuf::MessageLite; | |
41 | |
42 using audio_modem::AUDIBLE; | |
43 using audio_modem::AudioToken; | |
44 using audio_modem::INAUDIBLE; | |
45 | |
46 // TODO(ckehoe): Return error messages for bad requests. | |
47 | |
48 namespace copresence { | |
49 | |
50 const char RpcHandler::kReportRequestRpcName[] = "report"; | |
51 | |
52 namespace { | |
53 | |
54 const int kTokenLoggingSuffix = 5; | |
55 const int kInvalidTokenExpiryTimeMinutes = 10; | |
56 const int kMaxInvalidTokens = 10000; | |
57 const char kRegisterDeviceRpcName[] = "registerdevice"; | |
58 const char kDefaultCopresenceServer[] = | |
59 "https://www.googleapis.com/copresence/v2/copresence"; | |
60 | |
61 // UrlSafe is defined as: | |
62 // '/' represented by a '_' and '+' represented by a '-' | |
63 // TODO(rkc): Move this to the wrapper. | |
64 std::string ToUrlSafe(std::string token) { | |
65 base::ReplaceChars(token, "+", "-", &token); | |
66 base::ReplaceChars(token, "/", "_", &token); | |
67 return token; | |
68 } | |
69 | |
70 // Logging | |
71 | |
72 // Checks for a copresence error. If there is one, logs it and returns true. | |
73 bool IsErrorStatus(const Status& status) { | |
74 if (status.code() != OK) { | |
75 LOG(ERROR) << "Copresence error code " << status.code() | |
76 << (status.message().empty() ? "" : ": " + status.message()); | |
77 } | |
78 return status.code() != OK; | |
79 } | |
80 | |
81 void LogIfErrorStatus(const util::error::Code& code, | |
82 const std::string& context) { | |
83 LOG_IF(ERROR, code != util::error::OK) | |
84 << context << " error " << code << ". See " | |
85 << "cs/google3/util/task/codes.proto for more info."; | |
86 } | |
87 | |
88 // If any errors occurred, logs them and returns true. | |
89 bool ReportErrorLogged(const ReportResponse& response) { | |
90 bool result = IsErrorStatus(response.header().status()); | |
91 | |
92 // The Report fails or succeeds as a unit. If any responses had errors, | |
93 // the header will too. Thus we don't need to propagate individual errors. | |
94 if (response.has_update_signals_response()) | |
95 LogIfErrorStatus(response.update_signals_response().status(), "Update"); | |
96 if (response.has_manage_messages_response()) | |
97 LogIfErrorStatus(response.manage_messages_response().status(), "Publish"); | |
98 if (response.has_manage_subscriptions_response()) { | |
99 LogIfErrorStatus(response.manage_subscriptions_response().status(), | |
100 "Subscribe"); | |
101 } | |
102 | |
103 return result; | |
104 } | |
105 | |
106 const std::string LoggingStrForToken(const std::string& auth_token) { | |
107 if (auth_token.empty()) | |
108 return "anonymous"; | |
109 | |
110 std::string token_suffix = auth_token.substr( | |
111 auth_token.length() - kTokenLoggingSuffix, kTokenLoggingSuffix); | |
112 return "token ..." + token_suffix; | |
113 } | |
114 | |
115 | |
116 // Request construction | |
117 | |
118 template <typename T> | |
119 BroadcastScanConfiguration GetBroadcastScanConfig(const T& msg) { | |
120 if (msg.has_token_exchange_strategy() && | |
121 msg.token_exchange_strategy().has_broadcast_scan_configuration()) { | |
122 return msg.token_exchange_strategy().broadcast_scan_configuration(); | |
123 } | |
124 return BROADCAST_SCAN_CONFIGURATION_UNKNOWN; | |
125 } | |
126 | |
127 std::unique_ptr<DeviceState> GetDeviceCapabilities( | |
128 const ReportRequest& request) { | |
129 std::unique_ptr<DeviceState> state(new DeviceState); | |
130 | |
131 TokenTechnology* ultrasound = | |
132 state->mutable_capabilities()->add_token_technology(); | |
133 ultrasound->set_medium(AUDIO_ULTRASOUND_PASSBAND); | |
134 ultrasound->add_instruction_type(TRANSMIT); | |
135 ultrasound->add_instruction_type(RECEIVE); | |
136 | |
137 TokenTechnology* audible = | |
138 state->mutable_capabilities()->add_token_technology(); | |
139 audible->set_medium(AUDIO_AUDIBLE_DTMF); | |
140 audible->add_instruction_type(TRANSMIT); | |
141 audible->add_instruction_type(RECEIVE); | |
142 | |
143 return state; | |
144 } | |
145 | |
146 // TODO(ckehoe): We're keeping this code in a separate function for now | |
147 // because we get a version string from Chrome, but the proto expects | |
148 // an int64_t version. We should probably change the version proto | |
149 // to handle a more detailed version. | |
150 ClientVersion* CreateVersion(const std::string& client, | |
151 const std::string& version_name) { | |
152 ClientVersion* version = new ClientVersion; | |
153 version->set_client(client); | |
154 version->set_version_name(version_name); | |
155 return version; | |
156 } | |
157 | |
158 void AddTokenToRequest(const AudioToken& token, ReportRequest* request) { | |
159 TokenObservation* token_observation = | |
160 request->mutable_update_signals_request()->add_token_observation(); | |
161 token_observation->set_token_id(ToUrlSafe(token.token)); | |
162 | |
163 TokenSignals* signals = token_observation->add_signals(); | |
164 signals->set_medium(token.audible ? AUDIO_AUDIBLE_DTMF | |
165 : AUDIO_ULTRASOUND_PASSBAND); | |
166 signals->set_observed_time_millis(base::Time::Now().ToJsTime()); | |
167 } | |
168 | |
169 } // namespace | |
170 | |
171 | |
172 // Public functions. | |
173 | |
174 RpcHandler::RpcHandler(CopresenceDelegate* delegate, | |
175 DirectiveHandler* directive_handler, | |
176 CopresenceStateImpl* state, | |
177 GCMHandler* gcm_handler, | |
178 const MessagesCallback& new_messages_callback, | |
179 const PostCallback& server_post_callback) | |
180 : delegate_(delegate), | |
181 directive_handler_(directive_handler), | |
182 state_(state), | |
183 gcm_handler_(gcm_handler), | |
184 new_messages_callback_(new_messages_callback), | |
185 server_post_callback_(server_post_callback), | |
186 invalid_audio_token_cache_( | |
187 base::TimeDelta::FromMinutes(kInvalidTokenExpiryTimeMinutes), | |
188 kMaxInvalidTokens) { | |
189 DCHECK(delegate_); | |
190 DCHECK(directive_handler_); | |
191 // |gcm_handler_| is optional. | |
192 | |
193 if (server_post_callback_.is_null()) { | |
194 server_post_callback_ = | |
195 base::Bind(&RpcHandler::SendHttpPost, base::Unretained(this)); | |
196 } | |
197 | |
198 if (gcm_handler_) { | |
199 gcm_handler_->GetGcmId( | |
200 base::Bind(&RpcHandler::RegisterGcmId, base::Unretained(this))); | |
201 } | |
202 } | |
203 | |
204 RpcHandler::~RpcHandler() { | |
205 // TODO(ckehoe): Cancel the GCM callback? | |
206 for (HttpPost* post : pending_posts_) | |
207 delete post; | |
208 } | |
209 | |
210 void RpcHandler::SendReportRequest(std::unique_ptr<ReportRequest> request, | |
211 const std::string& app_id, | |
212 const std::string& auth_token, | |
213 const StatusCallback& status_callback) { | |
214 DCHECK(request.get()); | |
215 | |
216 // Check that the app, if any, has some kind of authentication token. | |
217 // Don't allow it to piggyback on Chrome's credentials. | |
218 if (!app_id.empty() && delegate_->GetAPIKey(app_id).empty() && | |
219 auth_token.empty()) { | |
220 LOG(ERROR) << "App " << app_id << " has no API key or auth token"; | |
221 status_callback.Run(FAIL); | |
222 return; | |
223 } | |
224 | |
225 // Store just one auth token since we should have only one account | |
226 // per instance of the copresence component. | |
227 // TODO(ckehoe): We may eventually need to support multiple auth tokens. | |
228 const bool authenticated = !auth_token.empty(); | |
229 if (authenticated && auth_token != auth_token_) { | |
230 LOG_IF(ERROR, !auth_token_.empty()) | |
231 << "Overwriting old auth token: " << LoggingStrForToken(auth_token); | |
232 auth_token_ = auth_token; | |
233 } | |
234 | |
235 // Check that we have a "device" registered for this authentication state. | |
236 bool queue_request; | |
237 const std::string device_id = delegate_->GetDeviceId(authenticated); | |
238 if (device_id.empty()) { | |
239 queue_request = true; | |
240 if (pending_registrations_.count(authenticated) == 0) | |
241 RegisterDevice(authenticated); | |
242 // else, registration is already in progress. | |
243 } else { | |
244 queue_request = false; | |
245 } | |
246 | |
247 // We're not registered, or registration is in progress. | |
248 if (queue_request) { | |
249 pending_requests_queue_.push_back(new PendingRequest( | |
250 std::move(request), app_id, authenticated, status_callback)); | |
251 return; | |
252 } | |
253 | |
254 DVLOG(3) << "Sending ReportRequest to server."; | |
255 | |
256 // If we are unpublishing or unsubscribing, we need to stop those publish or | |
257 // subscribes right away, we don't need to wait for the server to tell us. | |
258 ProcessRemovedOperations(*request); | |
259 | |
260 request->mutable_update_signals_request()->set_allocated_state( | |
261 GetDeviceCapabilities(*request).release()); | |
262 | |
263 AddPlayingTokens(request.get()); | |
264 | |
265 request->set_allocated_header(CreateRequestHeader(app_id, device_id)); | |
266 server_post_callback_.Run( | |
267 delegate_->GetRequestContext(), kReportRequestRpcName, | |
268 delegate_->GetAPIKey(app_id), auth_token, | |
269 base::WrapUnique<MessageLite>(request.release()), | |
270 // On destruction, this request will be cancelled. | |
271 base::Bind(&RpcHandler::ReportResponseHandler, base::Unretained(this), | |
272 status_callback)); | |
273 } | |
274 | |
275 void RpcHandler::ReportTokens(const std::vector<AudioToken>& tokens) { | |
276 DCHECK(!tokens.empty()); | |
277 | |
278 std::unique_ptr<ReportRequest> request(new ReportRequest); | |
279 for (const AudioToken& token : tokens) { | |
280 if (invalid_audio_token_cache_.HasKey(ToUrlSafe(token.token))) | |
281 continue; | |
282 DVLOG(3) << "Sending token " << token.token << " to server"; | |
283 AddTokenToRequest(token, request.get()); | |
284 } | |
285 | |
286 ReportOnAllDevices(std::move(request)); | |
287 } | |
288 | |
289 | |
290 // Private functions. | |
291 | |
292 RpcHandler::PendingRequest::PendingRequest( | |
293 std::unique_ptr<ReportRequest> report, | |
294 const std::string& app_id, | |
295 bool authenticated, | |
296 const StatusCallback& callback) | |
297 : report(std::move(report)), | |
298 app_id(app_id), | |
299 authenticated(authenticated), | |
300 callback(callback) {} | |
301 | |
302 RpcHandler::PendingRequest::~PendingRequest() {} | |
303 | |
304 void RpcHandler::RegisterDevice(const bool authenticated) { | |
305 DVLOG(2) << "Sending " << (authenticated ? "authenticated" : "anonymous") | |
306 << " registration to server."; | |
307 | |
308 std::unique_ptr<RegisterDeviceRequest> request(new RegisterDeviceRequest); | |
309 | |
310 // Add a GCM ID for authenticated registration, if we have one. | |
311 if (!authenticated || gcm_id_.empty()) { | |
312 request->mutable_push_service()->set_service(PUSH_SERVICE_NONE); | |
313 } else { | |
314 DVLOG(2) << "Registering GCM ID with " << LoggingStrForToken(auth_token_); | |
315 request->mutable_push_service()->set_service(GCM); | |
316 request->mutable_push_service()->mutable_gcm_registration() | |
317 ->set_device_token(gcm_id_); | |
318 } | |
319 | |
320 // Only identify as a Chrome device if we're in anonymous mode. | |
321 // Authenticated calls come from a "GAIA device". | |
322 if (!authenticated) { | |
323 // Make sure this isn't a duplicate anonymous registration. | |
324 // Duplicate authenticated registrations are allowed, to update the GCM ID. | |
325 DCHECK(delegate_->GetDeviceId(false).empty()) | |
326 << "Attempted anonymous re-registration"; | |
327 | |
328 Identity* identity = | |
329 request->mutable_device_identifiers()->mutable_registrant(); | |
330 identity->set_type(CHROME); | |
331 } | |
332 | |
333 bool gcm_pending = authenticated && gcm_handler_ && gcm_id_.empty(); | |
334 pending_registrations_.insert(authenticated); | |
335 request->set_allocated_header(CreateRequestHeader( | |
336 // The device is empty on first registration. | |
337 // When re-registering to pass on the GCM ID, it will be present. | |
338 std::string(), delegate_->GetDeviceId(authenticated))); | |
339 if (authenticated) | |
340 DCHECK(!auth_token_.empty()); | |
341 server_post_callback_.Run( | |
342 delegate_->GetRequestContext(), kRegisterDeviceRpcName, std::string(), | |
343 authenticated ? auth_token_ : std::string(), | |
344 base::WrapUnique<MessageLite>(request.release()), | |
345 // On destruction, this request will be cancelled. | |
346 base::Bind(&RpcHandler::RegisterResponseHandler, base::Unretained(this), | |
347 authenticated, gcm_pending)); | |
348 } | |
349 | |
350 void RpcHandler::ProcessQueuedRequests(const bool authenticated) { | |
351 // If there is no device ID for this auth state, registration failed. | |
352 bool registration_failed = delegate_->GetDeviceId(authenticated).empty(); | |
353 | |
354 // We momentarily take ownership of all the pointers in the queue. | |
355 // They are either deleted here or passed on to a new queue. | |
356 ScopedVector<PendingRequest> requests_being_processed; | |
357 std::swap(requests_being_processed, pending_requests_queue_); | |
358 for (PendingRequest* request : requests_being_processed) { | |
359 if (request->authenticated == authenticated) { | |
360 if (registration_failed) { | |
361 request->callback.Run(FAIL); | |
362 } else { | |
363 if (request->authenticated) | |
364 DCHECK(!auth_token_.empty()); | |
365 SendReportRequest(std::move(request->report), request->app_id, | |
366 request->authenticated ? auth_token_ : std::string(), | |
367 request->callback); | |
368 } | |
369 delete request; | |
370 } else { | |
371 // The request is in a different auth state. | |
372 pending_requests_queue_.push_back(request); | |
373 } | |
374 } | |
375 | |
376 // Only keep the requests that weren't processed. | |
377 // All the pointers in the queue are now spoken for. | |
378 requests_being_processed.weak_clear(); | |
379 } | |
380 | |
381 void RpcHandler::ReportOnAllDevices(std::unique_ptr<ReportRequest> request) { | |
382 std::vector<bool> auth_states; | |
383 if (!auth_token_.empty() && !delegate_->GetDeviceId(true).empty()) | |
384 auth_states.push_back(true); | |
385 if (!delegate_->GetDeviceId(false).empty()) | |
386 auth_states.push_back(false); | |
387 if (auth_states.empty()) { | |
388 VLOG(2) << "Skipping reporting because no device IDs are registered"; | |
389 return; | |
390 } | |
391 | |
392 for (bool authenticated : auth_states) { | |
393 SendReportRequest( | |
394 base::WrapUnique(new ReportRequest(*request)), std::string(), | |
395 authenticated ? auth_token_ : std::string(), StatusCallback()); | |
396 } | |
397 } | |
398 | |
399 // Store a GCM ID and send it to the server if needed. The constructor passes | |
400 // this callback to the GCMHandler to receive the ID whenever it's ready. | |
401 // It may be returned immediately, if the ID is cached, or require a server | |
402 // round-trip. This ID must then be passed along to the copresence server. | |
403 // There are a few ways this can happen: | |
404 // | |
405 // 1. The GCM ID is available when we first register, and is passed along | |
406 // with the RegisterDeviceRequest. | |
407 // | |
408 // 2. The GCM ID becomes available after the RegisterDeviceRequest has | |
409 // completed. Then this function will invoke RegisterDevice() | |
410 // again to pass on the ID. | |
411 // | |
412 // 3. The GCM ID becomes available after the RegisterDeviceRequest is sent, | |
413 // but before it completes. In this case, the gcm_pending flag is passed | |
414 // through to the RegisterResponseHandler, which invokes RegisterDevice() | |
415 // again to pass on the ID. This function must skip pending registrations, | |
416 // as the device ID will be empty. | |
417 // | |
418 // TODO(ckehoe): Add tests for these scenarios. | |
419 void RpcHandler::RegisterGcmId(const std::string& gcm_id) { | |
420 gcm_id_ = gcm_id; | |
421 if (!gcm_id.empty()) { | |
422 const std::string& device_id = delegate_->GetDeviceId(true); | |
423 if (!auth_token_.empty() && !device_id.empty()) | |
424 RegisterDevice(true); | |
425 } | |
426 } | |
427 | |
428 void RpcHandler::RegisterResponseHandler( | |
429 bool authenticated, | |
430 bool gcm_pending, | |
431 HttpPost* completed_post, | |
432 int http_status_code, | |
433 const std::string& response_data) { | |
434 if (completed_post) { | |
435 size_t elements_erased = pending_posts_.erase(completed_post); | |
436 DCHECK_GT(elements_erased, 0u); | |
437 } | |
438 | |
439 size_t registrations_completed = pending_registrations_.erase(authenticated); | |
440 DCHECK_GT(registrations_completed, 0u); | |
441 | |
442 RegisterDeviceResponse response; | |
443 const std::string token_str = | |
444 LoggingStrForToken(authenticated ? auth_token_ : std::string()); | |
445 if (http_status_code != net::HTTP_OK) { | |
446 // TODO(ckehoe): Retry registration if appropriate. | |
447 LOG(ERROR) << token_str << " device registration failed"; | |
448 } else if (!response.ParseFromString(response_data)) { | |
449 LOG(ERROR) << "Invalid RegisterDeviceResponse:\n" << response_data; | |
450 } else if (!IsErrorStatus(response.header().status())) { | |
451 const std::string& device_id = response.registered_device_id(); | |
452 DCHECK(!device_id.empty()); | |
453 delegate_->SaveDeviceId(authenticated, device_id); | |
454 DVLOG(2) << token_str << " device registration successful. Id: " | |
455 << device_id; | |
456 | |
457 // If we have a GCM ID now, and didn't before, pass it on to the server. | |
458 if (gcm_pending && !gcm_id_.empty()) | |
459 RegisterDevice(authenticated); | |
460 } | |
461 | |
462 // Send or fail requests on this auth token. | |
463 ProcessQueuedRequests(authenticated); | |
464 } | |
465 | |
466 void RpcHandler::ReportResponseHandler(const StatusCallback& status_callback, | |
467 HttpPost* completed_post, | |
468 int http_status_code, | |
469 const std::string& response_data) { | |
470 if (completed_post) { | |
471 size_t elements_erased = pending_posts_.erase(completed_post); | |
472 DCHECK_GT(elements_erased, 0u); | |
473 } | |
474 | |
475 if (http_status_code != net::HTTP_OK) { | |
476 if (!status_callback.is_null()) | |
477 status_callback.Run(FAIL); | |
478 return; | |
479 } | |
480 | |
481 DVLOG(3) << "Received ReportResponse."; | |
482 ReportResponse response; | |
483 if (!response.ParseFromString(response_data)) { | |
484 LOG(ERROR) << "Invalid ReportResponse"; | |
485 if (!status_callback.is_null()) | |
486 status_callback.Run(FAIL); | |
487 return; | |
488 } | |
489 | |
490 if (ReportErrorLogged(response)) { | |
491 if (!status_callback.is_null()) | |
492 status_callback.Run(FAIL); | |
493 return; | |
494 } | |
495 | |
496 for (const MessageResult& result : | |
497 response.manage_messages_response().published_message_result()) { | |
498 DVLOG(2) << "Published message with id " << result.published_message_id(); | |
499 } | |
500 | |
501 for (const SubscriptionResult& result : | |
502 response.manage_subscriptions_response().subscription_result()) { | |
503 DVLOG(2) << "Created subscription with id " << result.subscription_id(); | |
504 } | |
505 | |
506 if (response.has_update_signals_response()) { | |
507 const UpdateSignalsResponse& update_response = | |
508 response.update_signals_response(); | |
509 new_messages_callback_.Run(update_response.message()); | |
510 | |
511 for (const Directive& directive : update_response.directive()) | |
512 directive_handler_->AddDirective(directive); | |
513 | |
514 for (const Token& token : update_response.token()) { | |
515 if (state_) | |
516 state_->UpdateTokenStatus(token.id(), token.status()); | |
517 switch (token.status()) { | |
518 case VALID: | |
519 // TODO(rkc/ckehoe): Store the token in a |valid_token_cache_| with a | |
520 // short TTL (like 10s) and send it up with every report request. | |
521 // Then we'll still get messages while we're waiting to hear it again. | |
522 VLOG(1) << "Got valid token " << token.id(); | |
523 break; | |
524 case INVALID: | |
525 DVLOG(3) << "Discarding invalid token " << token.id(); | |
526 invalid_audio_token_cache_.Add(token.id(), true); | |
527 break; | |
528 default: | |
529 DVLOG(2) << "Token " << token.id() << " has status code " | |
530 << token.status(); | |
531 } | |
532 } | |
533 } | |
534 | |
535 // TODO(ckehoe): Return a more detailed status response. | |
536 if (!status_callback.is_null()) | |
537 status_callback.Run(SUCCESS); | |
538 } | |
539 | |
540 void RpcHandler::ProcessRemovedOperations(const ReportRequest& request) { | |
541 // Remove unpublishes. | |
542 if (request.has_manage_messages_request()) { | |
543 for (const std::string& unpublish : | |
544 request.manage_messages_request().id_to_unpublish()) { | |
545 directive_handler_->RemoveDirectives(unpublish); | |
546 } | |
547 } | |
548 | |
549 // Remove unsubscribes. | |
550 if (request.has_manage_subscriptions_request()) { | |
551 for (const std::string& unsubscribe : | |
552 request.manage_subscriptions_request().id_to_unsubscribe()) { | |
553 directive_handler_->RemoveDirectives(unsubscribe); | |
554 } | |
555 } | |
556 } | |
557 | |
558 void RpcHandler::AddPlayingTokens(ReportRequest* request) { | |
559 const std::string& audible_token = | |
560 directive_handler_->GetCurrentAudioToken(AUDIBLE); | |
561 const std::string& inaudible_token = | |
562 directive_handler_->GetCurrentAudioToken(INAUDIBLE); | |
563 | |
564 if (!audible_token.empty()) | |
565 AddTokenToRequest(AudioToken(audible_token, true), request); | |
566 if (!inaudible_token.empty()) | |
567 AddTokenToRequest(AudioToken(inaudible_token, false), request); | |
568 } | |
569 | |
570 // TODO(ckehoe): Pass in the version string and | |
571 // group this with the local functions up top. | |
572 RequestHeader* RpcHandler::CreateRequestHeader( | |
573 const std::string& app_id, | |
574 const std::string& device_id) const { | |
575 RequestHeader* header = new RequestHeader; | |
576 | |
577 header->set_allocated_framework_version(CreateVersion( | |
578 "Chrome", delegate_->GetPlatformVersionString())); | |
579 if (!app_id.empty()) | |
580 header->set_allocated_client_version(CreateVersion(app_id, std::string())); | |
581 header->set_current_time_millis(base::Time::Now().ToJsTime()); | |
582 if (!device_id.empty()) | |
583 header->set_registered_device_id(device_id); | |
584 | |
585 DeviceFingerprint* fingerprint = new DeviceFingerprint; | |
586 fingerprint->set_platform_version(delegate_->GetPlatformVersionString()); | |
587 fingerprint->set_type(CHROME_PLATFORM_TYPE); | |
588 header->set_allocated_device_fingerprint(fingerprint); | |
589 | |
590 return header; | |
591 } | |
592 | |
593 void RpcHandler::SendHttpPost(net::URLRequestContextGetter* url_context_getter, | |
594 const std::string& rpc_name, | |
595 const std::string& api_key, | |
596 const std::string& auth_token, | |
597 std::unique_ptr<MessageLite> request_proto, | |
598 const PostCleanupCallback& callback) { | |
599 // Create the base URL to call. | |
600 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | |
601 const std::string copresence_server_host = | |
602 command_line->HasSwitch(switches::kCopresenceServer) ? | |
603 command_line->GetSwitchValueASCII(switches::kCopresenceServer) : | |
604 kDefaultCopresenceServer; | |
605 | |
606 // Create the request and keep a pointer until it completes. | |
607 HttpPost* http_post = new HttpPost( | |
608 url_context_getter, | |
609 copresence_server_host, | |
610 rpc_name, | |
611 api_key, | |
612 auth_token, | |
613 command_line->GetSwitchValueASCII(switches::kCopresenceTracingToken), | |
614 *request_proto); | |
615 | |
616 http_post->Start(base::Bind(callback, http_post)); | |
617 pending_posts_.insert(http_post); | |
618 } | |
619 | |
620 } // namespace copresence | |
OLD | NEW |