1 // Copyright 2013 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 "remoting/host/setup/service_client.h"
6
7 #include "base/json/json_reader.h"
8 #include "base/json/json_writer.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/values.h"
11 #include "net/http/http_status_code.h"
12 #include "net/url_request/url_fetcher.h"
13 #include "net/url_request/url_fetcher_delegate.h"
14 #include "net/url_request/url_request_context_getter.h"
15 #include "url/gurl.h"
16
17 namespace remoting {
18
19 class ServiceClient::Core
20 : public base::RefCountedThreadSafe<ServiceClient::Core>,
21 public net::URLFetcherDelegate {
22 public:
Core(const std::string & chromoting_hosts_url,net::URLRequestContextGetter * request_context_getter)23 Core(const std::string& chromoting_hosts_url,
24 net::URLRequestContextGetter* request_context_getter)
25 : request_context_getter_(request_context_getter),
26 delegate_(NULL),
27 pending_request_type_(PENDING_REQUEST_NONE),
28 chromoting_hosts_url_(chromoting_hosts_url) {
29 }
30
31 void RegisterHost(const std::string& host_id,
32 const std::string& host_name,
33 const std::string& public_key,
34 const std::string& host_client_id,
35 const std::string& oauth_access_token,
36 ServiceClient::Delegate* delegate);
37
38 void UnregisterHost(const std::string& host_id,
39 const std::string& oauth_access_token,
40 ServiceClient::Delegate* delegate);
41
42 // net::URLFetcherDelegate implementation.
43 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
44
45 private:
46 friend class base::RefCountedThreadSafe<Core>;
~Core()47 virtual ~Core() {}
48
49 enum PendingRequestType {
50 PENDING_REQUEST_NONE,
51 PENDING_REQUEST_REGISTER_HOST,
52 PENDING_REQUEST_UNREGISTER_HOST
53 };
54
55 void MakeChromotingRequest(net::URLFetcher::RequestType request_type,
56 const std::string& post_body,
57 const std::string& url_suffix,
58 const std::string& oauth_access_token,
59 ServiceClient::Delegate* delegate);
60 void HandleResponse(const net::URLFetcher* source);
61
62 scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
63 ServiceClient::Delegate* delegate_;
64 scoped_ptr<net::URLFetcher> request_;
65 PendingRequestType pending_request_type_;
66 std::string chromoting_hosts_url_;
67 };
68
RegisterHost(const std::string & host_id,const std::string & host_name,const std::string & public_key,const std::string & host_client_id,const std::string & oauth_access_token,Delegate * delegate)69 void ServiceClient::Core::RegisterHost(
70 const std::string& host_id,
71 const std::string& host_name,
72 const std::string& public_key,
73 const std::string& host_client_id,
74 const std::string& oauth_access_token,
75 Delegate* delegate) {
76 DCHECK(pending_request_type_ == PENDING_REQUEST_NONE);
77 pending_request_type_ = PENDING_REQUEST_REGISTER_HOST;
78 base::DictionaryValue post_body;
79 post_body.SetString("data.hostId", host_id);
80 post_body.SetString("data.hostName", host_name);
81 post_body.SetString("data.publicKey", public_key);
82 std::string url_suffix;
83 if (!host_client_id.empty())
84 url_suffix = "?hostClientId=" + host_client_id;
85 std::string post_body_str;
86 base::JSONWriter::Write(&post_body, &post_body_str);
87 MakeChromotingRequest(net::URLFetcher::POST,
88 url_suffix,
89 post_body_str,
90 oauth_access_token,
91 delegate);
92 }
93
UnregisterHost(const std::string & host_id,const std::string & oauth_access_token,Delegate * delegate)94 void ServiceClient::Core::UnregisterHost(
95 const std::string& host_id,
96 const std::string& oauth_access_token,
97 Delegate* delegate) {
98 DCHECK(pending_request_type_ == PENDING_REQUEST_NONE);
99 pending_request_type_ = PENDING_REQUEST_UNREGISTER_HOST;
100 MakeChromotingRequest(net::URLFetcher::DELETE_REQUEST,
101 host_id,
102 std::string(),
103 oauth_access_token,
104 delegate);
105 }
106
MakeChromotingRequest(net::URLFetcher::RequestType request_type,const std::string & url_suffix,const std::string & request_body,const std::string & oauth_access_token,ServiceClient::Delegate * delegate)107 void ServiceClient::Core::MakeChromotingRequest(
108 net::URLFetcher::RequestType request_type,
109 const std::string& url_suffix,
110 const std::string& request_body,
111 const std::string& oauth_access_token,
112 ServiceClient::Delegate* delegate) {
113 delegate_ = delegate;
114 request_.reset(net::URLFetcher::Create(
115 0, GURL(chromoting_hosts_url_ + url_suffix), request_type, this));
116 request_->SetRequestContext(request_context_getter_.get());
117 request_->SetUploadData("application/json; charset=UTF-8", request_body);
118 request_->AddExtraRequestHeader("Authorization: OAuth " + oauth_access_token);
119 request_->Start();
120 }
121
122 // URLFetcher::Delegate implementation.
OnURLFetchComplete(const net::URLFetcher * source)123 void ServiceClient::Core::OnURLFetchComplete(
124 const net::URLFetcher* source) {
125 HandleResponse(source);
126 request_.reset();
127 }
128
HandleResponse(const net::URLFetcher * source)129 void ServiceClient::Core::HandleResponse(const net::URLFetcher* source) {
130 DCHECK(pending_request_type_ != PENDING_REQUEST_NONE);
131 PendingRequestType old_type = pending_request_type_;
132 pending_request_type_ = PENDING_REQUEST_NONE;
133 if (source->GetResponseCode() == net::HTTP_BAD_REQUEST) {
134 delegate_->OnOAuthError();
135 return;
136 }
137
138 // Treat codes 2xx as successful; for example, HTTP_NO_CONTENT (204) can be
139 // returned from a DELETE_REQUEST.
140 if (source->GetResponseCode() / 100 == 2) {
141 switch (old_type) {
142 case PENDING_REQUEST_NONE:
143 break;
144 case PENDING_REQUEST_REGISTER_HOST:
145 {
146 std::string data;
147 source->GetResponseAsString(&data);
148 scoped_ptr<Value> message_value(base::JSONReader::Read(data));
149 DictionaryValue *dict;
150 std::string code;
151 if (message_value.get() &&
152 message_value->IsType(Value::TYPE_DICTIONARY) &&
153 message_value->GetAsDictionary(&dict) &&
154 dict->GetString("data.authorizationCode", &code)) {
155 delegate_->OnHostRegistered(code);
156 } else {
157 delegate_->OnHostRegistered(std::string());
158 }
159 }
160 break;
161 case PENDING_REQUEST_UNREGISTER_HOST:
162 delegate_->OnHostUnregistered();
163 break;
164 }
165 return;
166 }
167 delegate_->OnNetworkError(source->GetResponseCode());
168 }
169
ServiceClient(const std::string & chromoting_hosts_url,net::URLRequestContextGetter * context_getter)170 ServiceClient::ServiceClient(const std::string& chromoting_hosts_url,
171 net::URLRequestContextGetter* context_getter) {
172 core_ = new Core(chromoting_hosts_url, context_getter);
173 }
174
~ServiceClient()175 ServiceClient::~ServiceClient() {
176 }
177
RegisterHost(const std::string & host_id,const std::string & host_name,const std::string & public_key,const std::string & host_client_id,const std::string & oauth_access_token,Delegate * delegate)178 void ServiceClient::RegisterHost(
179 const std::string& host_id,
180 const std::string& host_name,
181 const std::string& public_key,
182 const std::string& host_client_id,
183 const std::string& oauth_access_token,
184 Delegate* delegate) {
185 return core_->RegisterHost(host_id, host_name, public_key, host_client_id,
186 oauth_access_token, delegate);
187 }
188
UnregisterHost(const std::string & host_id,const std::string & oauth_access_token,Delegate * delegate)189 void ServiceClient::UnregisterHost(
190 const std::string& host_id,
191 const std::string& oauth_access_token,
192 Delegate* delegate) {
193 return core_->UnregisterHost(host_id, oauth_access_token, delegate);
194 }
195
196 } // namespace gaia
197