1558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "remoting/host/setup/service_client.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
73551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/json/json_reader.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_writer.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_status_code.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_fetcher.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_fetcher_delegate.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context_getter.h"
157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace remoting {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ServiceClient::Core
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public base::RefCountedThreadSafe<ServiceClient::Core>,
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      public net::URLFetcherDelegate {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Core(const std::string& chromoting_hosts_url,
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       net::URLRequestContextGetter* request_context_getter)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           : request_context_getter_(request_context_getter),
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             delegate_(NULL),
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             pending_request_type_(PENDING_REQUEST_NONE),
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             chromoting_hosts_url_(chromoting_hosts_url) {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RegisterHost(const std::string& host_id,
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const std::string& host_name,
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const std::string& public_key,
343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    const std::string& host_client_id,
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const std::string& oauth_access_token,
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    ServiceClient::Delegate* delegate);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void UnregisterHost(const std::string& host_id,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      const std::string& oauth_access_token,
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      ServiceClient::Delegate* delegate);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // net::URLFetcherDelegate implementation.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class base::RefCountedThreadSafe<Core>;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~Core() {}
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum PendingRequestType {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PENDING_REQUEST_NONE,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PENDING_REQUEST_REGISTER_HOST,
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PENDING_REQUEST_UNREGISTER_HOST
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  void MakeChromotingRequest(net::URLFetcher::RequestType request_type,
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const std::string& post_body,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const std::string& url_suffix,
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const std::string& oauth_access_token,
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       ServiceClient::Delegate* delegate);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void HandleResponse(const net::URLFetcher* source);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ServiceClient::Delegate* delegate_;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<net::URLFetcher> request_;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PendingRequestType pending_request_type_;
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string chromoting_hosts_url_;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ServiceClient::Core::RegisterHost(
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& host_id,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& host_name,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& public_key,
733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& host_client_id,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& oauth_access_token,
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Delegate* delegate) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(pending_request_type_ == PENDING_REQUEST_NONE);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_request_type_ = PENDING_REQUEST_REGISTER_HOST;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::DictionaryValue post_body;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  post_body.SetString("data.hostId", host_id);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  post_body.SetString("data.hostName", host_name);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  post_body.SetString("data.publicKey", public_key);
823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::string url_suffix;
833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!host_client_id.empty())
843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    url_suffix = "?hostClientId=" + host_client_id;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string post_body_str;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::JSONWriter::Write(&post_body, &post_body_str);
873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  MakeChromotingRequest(net::URLFetcher::POST,
883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                        url_suffix,
893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                        post_body_str,
903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                        oauth_access_token,
913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                        delegate);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ServiceClient::Core::UnregisterHost(
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& host_id,
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& oauth_access_token,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Delegate* delegate) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(pending_request_type_ == PENDING_REQUEST_NONE);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_request_type_ = PENDING_REQUEST_UNREGISTER_HOST;
1003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  MakeChromotingRequest(net::URLFetcher::DELETE_REQUEST,
1013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                        host_id,
1023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                        std::string(),
1033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                        oauth_access_token,
1043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                        delegate);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ServiceClient::Core::MakeChromotingRequest(
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::URLFetcher::RequestType request_type,
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& url_suffix,
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& request_body,
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& oauth_access_token,
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ServiceClient::Delegate* delegate) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_ = delegate;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_.reset(net::URLFetcher::Create(
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      0, GURL(chromoting_hosts_url_ + url_suffix), request_type, this));
116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  request_->SetRequestContext(request_context_getter_.get());
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_->SetUploadData("application/json; charset=UTF-8", request_body);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_->AddExtraRequestHeader("Authorization: OAuth " + oauth_access_token);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_->Start();
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// URLFetcher::Delegate implementation.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ServiceClient::Core::OnURLFetchComplete(
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::URLFetcher* source) {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HandleResponse(source);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_.reset();
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ServiceClient::Core::HandleResponse(const net::URLFetcher* source) {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(pending_request_type_ != PENDING_REQUEST_NONE);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PendingRequestType old_type = pending_request_type_;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_request_type_ = PENDING_REQUEST_NONE;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (source->GetResponseCode() == net::HTTP_BAD_REQUEST) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->OnOAuthError();
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
137424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
138424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Treat codes 2xx as successful; for example, HTTP_NO_CONTENT (204) can be
139424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // returned from a DELETE_REQUEST.
140424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (source->GetResponseCode() / 100 == 2) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (old_type) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PENDING_REQUEST_NONE:
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PENDING_REQUEST_REGISTER_HOST:
1453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        {
1463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          std::string data;
1473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          source->GetResponseAsString(&data);
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          scoped_ptr<base::Value> message_value(base::JSONReader::Read(data));
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::DictionaryValue *dict;
1503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          std::string code;
1513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          if (message_value.get() &&
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              message_value->IsType(base::Value::TYPE_DICTIONARY) &&
1533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)              message_value->GetAsDictionary(&dict) &&
1543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)              dict->GetString("data.authorizationCode", &code)) {
1553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            delegate_->OnHostRegistered(code);
1563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          } else {
1573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            delegate_->OnHostRegistered(std::string());
1583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          }
1593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PENDING_REQUEST_UNREGISTER_HOST:
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        delegate_->OnHostUnregistered();
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_->OnNetworkError(source->GetResponseCode());
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ServiceClient::ServiceClient(const std::string& chromoting_hosts_url,
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             net::URLRequestContextGetter* context_getter) {
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  core_ = new Core(chromoting_hosts_url, context_getter);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ServiceClient::~ServiceClient() {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ServiceClient::RegisterHost(
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& host_id,
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& host_name,
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& public_key,
1823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& host_client_id,
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& oauth_access_token,
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Delegate* delegate) {
1853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return core_->RegisterHost(host_id, host_name, public_key, host_client_id,
1863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                             oauth_access_token, delegate);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ServiceClient::UnregisterHost(
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& host_id,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& oauth_access_token,
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Delegate* delegate) {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return core_->UnregisterHost(host_id, oauth_access_token, delegate);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace gaia
197