Roll src/third_party/WebKit b41a10f:afd8afd (svn 202201:202202)
[chromium-blink-merge.git] / remoting / host / gcd_rest_client.cc
blob0a4ac48c498fc43deffe72ed827917796ab2132c
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.
5 #include "remoting/host/gcd_rest_client.h"
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/json/json_writer.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "base/time/default_clock.h"
13 #include "base/values.h"
14 #include "net/url_request/url_fetcher.h"
15 #include "remoting/base/logging.h"
17 namespace remoting {
19 GcdRestClient::GcdRestClient(const std::string& gcd_base_url,
20 const std::string& gcd_device_id,
21 const scoped_refptr<net::URLRequestContextGetter>&
22 url_request_context_getter,
23 OAuthTokenGetter* token_getter)
24 : gcd_base_url_(gcd_base_url),
25 gcd_device_id_(gcd_device_id),
26 url_request_context_getter_(url_request_context_getter),
27 token_getter_(token_getter),
28 clock_(new base::DefaultClock) {
31 GcdRestClient::~GcdRestClient() {
34 void GcdRestClient::PatchState(
35 scoped_ptr<base::DictionaryValue> patch_details,
36 const GcdRestClient::ResultCallback& callback) {
37 DCHECK(!HasPendingRequest());
39 // Construct a status update message in the format GCD expects. The
40 // message looks like this, where "..." is filled in from
41 // |patch_details|:
43 // {
44 // requestTimeMs: T,
45 // patches: [{
46 // timeMs: T,
47 // patch: {...}
48 // }]
49 // }
51 // Note that |now| is deliberately using a double to hold an integer
52 // value because |DictionaryValue| doesn't support int64 values, and
53 // GCD doesn't accept fractional values.
54 double now = clock_->Now().ToJavaTime();
55 scoped_ptr<base::DictionaryValue> patch_dict(new base::DictionaryValue);
56 patch_dict->SetDouble("requestTimeMs", now);
57 scoped_ptr<base::ListValue> patch_list(new base::ListValue);
58 base::DictionaryValue* patch_item = new base::DictionaryValue;
59 patch_list->Append(patch_item);
60 patch_item->Set("patch", patch_details.Pass());
61 patch_item->SetDouble("timeMs", now);
62 patch_dict->Set("patches", patch_list.Pass());
64 // Stringify the message.
65 std::string patch_string;
66 if (!base::JSONWriter::Write(*patch_dict, &patch_string)) {
67 LOG(ERROR) << "Error building GCD device state patch.";
68 callback.Run(OTHER_ERROR);
69 return;
71 DLOG(INFO) << "sending state patch: " << patch_string;
73 std::string url =
74 gcd_base_url_ + "/devices/" + gcd_device_id_ + "/patchState";
76 // Prepare an HTTP request to issue once an auth token is available.
77 callback_ = callback;
78 url_fetcher_ =
79 net::URLFetcher::Create(GURL(url), net::URLFetcher::POST, this);
80 url_fetcher_->SetUploadData("application/json", patch_string);
81 if (url_request_context_getter_) {
82 url_fetcher_->SetRequestContext(url_request_context_getter_.get());
85 token_getter_->CallWithToken(
86 base::Bind(&GcdRestClient::OnTokenReceived, base::Unretained(this)));
89 void GcdRestClient::OnTokenReceived(OAuthTokenGetter::Status status,
90 const std::string& user_email,
91 const std::string& access_token) {
92 DCHECK(HasPendingRequest());
94 if (status != OAuthTokenGetter::SUCCESS) {
95 LOG(ERROR) << "Error getting OAuth token for GCD request: "
96 << url_fetcher_->GetOriginalURL();
97 if (status == OAuthTokenGetter::NETWORK_ERROR) {
98 FinishCurrentRequest(NETWORK_ERROR);
99 } else {
100 FinishCurrentRequest(OTHER_ERROR);
102 return;
105 url_fetcher_->SetExtraRequestHeaders(
106 "Authorization: Bearer " + access_token);
107 url_fetcher_->Start();
110 void GcdRestClient::FinishCurrentRequest(Result result) {
111 DCHECK(HasPendingRequest());
112 url_fetcher_.reset();
113 base::ResetAndReturn(&callback_).Run(result);
116 void GcdRestClient::OnURLFetchComplete(const net::URLFetcher* source) {
117 DCHECK(HasPendingRequest());
119 const GURL& request_url = url_fetcher_->GetOriginalURL();
120 Result status = OTHER_ERROR;
121 int response = source->GetResponseCode();
122 if (response >= 200 && response < 300) {
123 DLOG(INFO) << "GCD request succeeded:" << request_url;
124 status = SUCCESS;
125 } else if (response == 404) {
126 LOG(WARNING) << "Host not found (" << response
127 << ") fetching URL: " << request_url;
128 status = NO_SUCH_HOST;
129 } else if (response == 0) {
130 LOG(ERROR) << "Network error (" << response
131 << ") fetching URL: " << request_url;
132 status = NETWORK_ERROR;
133 } else {
134 LOG(ERROR) << "Error (" << response << ") fetching URL: " << request_url;
137 FinishCurrentRequest(status);
140 } // namespace remoting