// 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<Value> message_value(base::JSONReader::Read(data));
DictionaryValue *dict;
std::string code;
if (message_value.get() &&
message_value->IsType(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