// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "remoting/host/setup/service_client.h" #include "base/json/json_reader.h" #include "base/json/json_writer.h" #include "base/memory/scoped_ptr.h" #include "base/values.h" #include "net/http/http_status_code.h" #include "net/url_request/url_fetcher.h" #include "net/url_request/url_fetcher_delegate.h" #include "net/url_request/url_request_context_getter.h" #include "url/gurl.h" namespace remoting { class ServiceClient::Core : public base::RefCountedThreadSafe<ServiceClient::Core>, public net::URLFetcherDelegate { public: Core(const std::string& chromoting_hosts_url, net::URLRequestContextGetter* request_context_getter) : request_context_getter_(request_context_getter), delegate_(NULL), pending_request_type_(PENDING_REQUEST_NONE), chromoting_hosts_url_(chromoting_hosts_url) { } void 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, ServiceClient::Delegate* delegate); void UnregisterHost(const std::string& host_id, const std::string& oauth_access_token, ServiceClient::Delegate* delegate); // net::URLFetcherDelegate implementation. virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; private: friend class base::RefCountedThreadSafe<Core>; virtual ~Core() {} enum PendingRequestType { PENDING_REQUEST_NONE, PENDING_REQUEST_REGISTER_HOST, PENDING_REQUEST_UNREGISTER_HOST }; void MakeChromotingRequest(net::URLFetcher::RequestType request_type, const std::string& post_body, const std::string& url_suffix, const std::string& oauth_access_token, ServiceClient::Delegate* delegate); void HandleResponse(const net::URLFetcher* source); scoped_refptr<net::URLRequestContextGetter> request_context_getter_; ServiceClient::Delegate* delegate_; scoped_ptr<net::URLFetcher> request_; PendingRequestType pending_request_type_; std::string chromoting_hosts_url_; }; void ServiceClient::Core::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) { DCHECK(pending_request_type_ == PENDING_REQUEST_NONE); pending_request_type_ = PENDING_REQUEST_REGISTER_HOST; base::DictionaryValue post_body; post_body.SetString("data.hostId", host_id); post_body.SetString("data.hostName", host_name); post_body.SetString("data.publicKey", public_key); std::string url_suffix; if (!host_client_id.empty()) url_suffix = "?hostClientId=" + host_client_id; std::string post_body_str; base::JSONWriter::Write(&post_body, &post_body_str); MakeChromotingRequest(net::URLFetcher::POST, url_suffix, post_body_str, oauth_access_token, delegate); } void ServiceClient::Core::UnregisterHost( const std::string& host_id, const std::string& oauth_access_token, Delegate* delegate) { DCHECK(pending_request_type_ == PENDING_REQUEST_NONE); pending_request_type_ = PENDING_REQUEST_UNREGISTER_HOST; MakeChromotingRequest(net::URLFetcher::DELETE_REQUEST, host_id, std::string(), oauth_access_token, delegate); } void ServiceClient::Core::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) { delegate_ = delegate; request_.reset(net::URLFetcher::Create( 0, GURL(chromoting_hosts_url_ + url_suffix), request_type, this)); request_->SetRequestContext(request_context_getter_.get()); request_->SetUploadData("application/json; charset=UTF-8", request_body); request_->AddExtraRequestHeader("Authorization: OAuth " + oauth_access_token); request_->Start(); } // URLFetcher::Delegate implementation. void ServiceClient::Core::OnURLFetchComplete( const net::URLFetcher* source) { HandleResponse(source); request_.reset(); } void ServiceClient::Core::HandleResponse(const net::URLFetcher* source) { DCHECK(pending_request_type_ != PENDING_REQUEST_NONE); PendingRequestType old_type = pending_request_type_; pending_request_type_ = PENDING_REQUEST_NONE; if (source->GetResponseCode() == net::HTTP_BAD_REQUEST) { delegate_->OnOAuthError(); return; } // Treat codes 2xx as successful; for example, HTTP_NO_CONTENT (204) can be // returned from a DELETE_REQUEST. if (source->GetResponseCode() / 100 == 2) { switch (old_type) { case PENDING_REQUEST_NONE: break; case PENDING_REQUEST_REGISTER_HOST: { std::string data; source->GetResponseAsString(&data); scoped_ptr<base::Value> message_value(base::JSONReader::Read(data)); base::DictionaryValue *dict; std::string code; if (message_value.get() && message_value->IsType(base::Value::TYPE_DICTIONARY) && message_value->GetAsDictionary(&dict) && dict->GetString("data.authorizationCode", &code)) { delegate_->OnHostRegistered(code); } else { delegate_->OnHostRegistered(std::string()); } } break; case PENDING_REQUEST_UNREGISTER_HOST: delegate_->OnHostUnregistered(); break; } return; } delegate_->OnNetworkError(source->GetResponseCode()); } ServiceClient::ServiceClient(const std::string& chromoting_hosts_url, net::URLRequestContextGetter* context_getter) { core_ = new Core(chromoting_hosts_url, context_getter); } ServiceClient::~ServiceClient() { } void ServiceClient::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) { return core_->RegisterHost(host_id, host_name, public_key, host_client_id, oauth_access_token, delegate); } void ServiceClient::UnregisterHost( const std::string& host_id, const std::string& oauth_access_token, Delegate* delegate) { return core_->UnregisterHost(host_id, oauth_access_token, delegate); } } // namespace gaia