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: 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>; 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 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 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 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. 123 void ServiceClient::Core::OnURLFetchComplete( 124 const net::URLFetcher* source) { 125 HandleResponse(source); 126 request_.reset(); 127 } 128 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 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 175 ServiceClient::~ServiceClient() { 176 } 177 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 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