diff options
-rw-r--r-- | chrome/browser/remoting/directory_add_request.cc | 125 | ||||
-rw-r--r-- | chrome/browser/remoting/directory_add_request.h | 75 | ||||
-rw-r--r-- | chrome/browser/remoting/directory_add_request_unittest.cc | 82 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 2 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 1 | ||||
-rw-r--r-- | chrome/common/net/http_return.h | 3 | ||||
-rw-r--r-- | chrome/service/remoting/remoting_directory_service.cc | 84 | ||||
-rw-r--r-- | chrome/service/remoting/remoting_directory_service.h | 72 |
8 files changed, 287 insertions, 157 deletions
diff --git a/chrome/browser/remoting/directory_add_request.cc b/chrome/browser/remoting/directory_add_request.cc new file mode 100644 index 0000000..c7d2645 --- /dev/null +++ b/chrome/browser/remoting/directory_add_request.cc @@ -0,0 +1,125 @@ +// Copyright (c) 2010 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 "chrome/browser/remoting/directory_add_request.h" + +#include <vector> + +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" +#include "base/values.h" +#include "chrome/common/net/http_return.h" +#include "chrome/common/net/url_request_context_getter.h" +#include "net/http/http_request_headers.h" +#include "net/url_request/url_request_status.h" + +namespace remoting { + +static const char kRemotingDirectoryUrl[] = + "https://www.googleapis.com/chromoting/v1/@me/hosts"; + +DirectoryAddRequest::DirectoryAddRequest(URLRequestContextGetter* getter) + : getter_(getter) { +} + +DirectoryAddRequest::~DirectoryAddRequest() { + DCHECK(!fetcher_.get()) << "URLFetcher not destroyed."; +} + +void DirectoryAddRequest::AddHost(const remoting::ChromotingHostInfo& host_info, + const std::string& auth_token, + DoneCallback* done_callback) { + DCHECK(done_callback); + done_callback_.reset(done_callback); + + // Prepare the parameters for the request. + DictionaryValue data; + data.SetString("hostId", host_info.host_id); + data.SetString("hostName", host_info.hostname); + data.SetString("publicKey", host_info.public_key); + + // Generate the final json query. + DictionaryValue args; + args.Set("data", data.DeepCopy()); + std::string request_content; + base::JSONWriter::Write(&args, false, &request_content); + + // Prepare the HTTP header for authentication. + net::HttpRequestHeaders headers; + headers.SetHeader("Authorization", "GoogleLogin auth=" + auth_token); + fetcher_.reset( + new URLFetcher(GURL(kRemotingDirectoryUrl), URLFetcher::POST, this)); + fetcher_->set_request_context(getter_); + fetcher_->set_upload_data("application/json", request_content); + fetcher_->set_extra_request_headers(headers.ToString()); + + // And then start the request. + fetcher_->Start(); +} + +void DirectoryAddRequest::OnURLFetchComplete( + const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data) { + DCHECK_EQ(source, fetcher_.get()); + + // Destroy the fetcher after the response has been received. + fetcher_.reset(); + + Result result; + std::string error_message; + + if (status.is_success()) { + DictionaryValue* response = NULL; + scoped_ptr<Value> response_json(base::JSONReader::Read(data, true)); + if (response_json != NULL && + response_json->IsType(Value::TYPE_DICTIONARY)) { + response = static_cast<DictionaryValue*>(response_json.get()); + response->GetString("error.message", &error_message); + } + + switch (response_code) { + case RC_REQUEST_OK: + result = SUCCESS; + break; + + case RC_BAD_REQUEST: + // TODO(sergeyu): Implement duplicate error detection that doesn't + // depend on error message. + if (error_message.find("duplicate") != std::string::npos) { + result = ERROR_EXISTS; + } else { + result = ERROR_INVALID_REQUEST; + } + break; + + case RC_UNAUTHORIZED: + result = ERROR_AUTH; + break; + + case RC_INTERNAL_SERVER_ERROR: + result = ERROR_SERVER; + break; + + default: + result = ERROR_OTHER; + } + } else { + result = ERROR_OTHER; + } + + if (result != SUCCESS) { + LOG(WARNING) << "Received error when trying to register Chromoting host. " + << "status.is_success(): " << status.is_success() + << " response_code: " << response_code + << " error_message: " << error_message; + } + + done_callback_->Run(result, error_message); +} + +} // namespace remoting diff --git a/chrome/browser/remoting/directory_add_request.h b/chrome/browser/remoting/directory_add_request.h new file mode 100644 index 0000000..2ec6ed2 --- /dev/null +++ b/chrome/browser/remoting/directory_add_request.h @@ -0,0 +1,75 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_BROWSER_REMOTING_DIRECTORY_ADD_REQUEST_H_ +#define CHROME_BROWSER_REMOTING_DIRECTORY_ADD_REQUEST_H_ + +#include <string> + +#include "base/callback.h" +#include "base/scoped_ptr.h" +#include "chrome/common/remoting/chromoting_host_info.h" +#include "chrome/common/net/url_fetcher.h" +#include "googleurl/src/gurl.h" + +namespace remoting { + +// A class implements REST API insert call for the Chromoting directory service. +class DirectoryAddRequest : public URLFetcher::Delegate { + public: + enum Result { + // Host was added successfully. + SUCCESS, + // Invalid authentication token. + ERROR_AUTH, + // Server rejected request because it was invalid (e.g. specified + // public key is invalid). + ERROR_INVALID_REQUEST, + // Host is already registered. + ERROR_EXISTS, + // Internal server error. + ERROR_SERVER, + // Timeout expired. + ERROR_TIMEOUT_EXPIRED, + // Some other error, e.g. network failure. + ERROR_OTHER, + }; + + // Callback called when request is finished. The second parameter + // contains error message in case of an error. The error message may + // not be localized, and should be used for logging, but not shown + // to the user. + typedef Callback2<Result, const std::string&>::Type DoneCallback; + + explicit DirectoryAddRequest(URLRequestContextGetter* getter); + ~DirectoryAddRequest(); + + // Add this computer as a host. Use the token for + // authentication. |done_callback| is called when the request is + // finished. Request can be cancelled by destroying this object. + void AddHost(const remoting::ChromotingHostInfo& host_info, + const std::string& auth_token, + DoneCallback* done_callback); + + // URLFetcher::Delegate implementation. + virtual void OnURLFetchComplete(const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data); + + private: + friend class DirectoryAddRequestTest; + + URLRequestContextGetter* getter_; + scoped_ptr<DoneCallback> done_callback_; + scoped_ptr<URLFetcher> fetcher_; + + DISALLOW_COPY_AND_ASSIGN(DirectoryAddRequest); +}; + +} // namespace remoting + +#endif // CHROME_BROWSER_REMOTING_DIRECTORY_ADD_REQUEST_H_ diff --git a/chrome/browser/remoting/directory_add_request_unittest.cc b/chrome/browser/remoting/directory_add_request_unittest.cc new file mode 100644 index 0000000..6389b3e8 --- /dev/null +++ b/chrome/browser/remoting/directory_add_request_unittest.cc @@ -0,0 +1,82 @@ +// Copyright (c) 2010 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 "chrome/browser/remoting/directory_add_request.h" +#include "chrome/test/testing_profile.h" +#include "net/url_request/url_request_status.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace remoting { + +namespace { +class MockDoneCallback { + public: + MOCK_METHOD2(OnDone, + void(DirectoryAddRequest::Result, + const std::string& message)); +}; +} // namespace + +class DirectoryAddRequestTest : public testing::Test { + protected: + virtual void SetUp() { + target_.reset(new DirectoryAddRequest(profile_.GetRequestContext())); + } + + void TestResult(int response_code, const std::string& data, + DirectoryAddRequest::Result expected_result, + const std::string& expected_message) { + MockDoneCallback callback; + EXPECT_CALL(callback, OnDone(expected_result, expected_message)) + .Times(1); + + target_->done_callback_.reset( + NewCallback(&callback, &MockDoneCallback::OnDone)); + + GURL url; + URLRequestStatus status_ok; + ResponseCookies cookies; + target_->OnURLFetchComplete(NULL, url, status_ok, response_code, + cookies, data); + } + + TestingProfile profile_; + scoped_ptr<DirectoryAddRequest> target_; +}; + +TEST_F(DirectoryAddRequestTest, Success) { + TestResult(200, "{\"data\":{\"kind\":\"chromoting#host\"," + "\"hostId\":\"e64906c9-fdc9-4921-80cb-563cf7f564f3\"," + "\"hostName\":\"host_name\",\"publicKey\":\"PUBLIC+KEY\"}}", + DirectoryAddRequest::SUCCESS, ""); +} + +TEST_F(DirectoryAddRequestTest, Duplicate) { + TestResult(400, "{\"error\":{\"errors\":[{\"domain\":\"global\"," + "\"reason\":\"invalid\",\"message\":\"Attempt to register " + "a duplicate host.\"}],\"code\":400,\"message\":\"Attempt to " + "register a duplicate host.\"}}", + DirectoryAddRequest::ERROR_EXISTS, + "Attempt to register a duplicate host."); +} + +TEST_F(DirectoryAddRequestTest, InvalidRequest) { + TestResult(400, "{\"error\":{\"errors\":[{\"domain\":\"global\"," + "\"reason\":\"invalid\",\"message\":\"Invalid Value\"}]," + "\"code\":400,\"message\":\"Invalid Value\"}}", + DirectoryAddRequest::ERROR_INVALID_REQUEST, + "Invalid Value"); +} + +TEST_F(DirectoryAddRequestTest, InvalidToken) { + TestResult(401, "{\"error\":{\"errors\":[{\"domain\":\"global\"," + "\"reason\":\"invalid\",\"message\":\"Token invalid\"," + "\"locationType\":\"header\",\"location\":\"Authorization\"}]," + "\"code\":401,\"message\":\"Token invalid\"}}", + DirectoryAddRequest::ERROR_AUTH, + "Token invalid"); +} + +} // namespace remoting diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 8a0dba9..1729ec8 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2106,6 +2106,8 @@ 'browser/profiles/profile_impl.h', 'browser/profiles/profile_manager.cc', 'browser/profiles/profile_manager.h', + 'browser/remoting/directory_add_request.cc', + 'browser/remoting/directory_add_request.h', 'browser/remoting/remoting_resources_source.cc', 'browser/remoting/remoting_resources_source.h', 'browser/remoting/remoting_setup_flow.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 7f0ad13..20c9705 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1293,6 +1293,7 @@ 'browser/process_info_snapshot_mac_unittest.cc', 'browser/process_singleton_mac_unittest.cc', 'browser/profiles/profile_manager_unittest.cc', + 'browser/remoting/directory_add_request_unittest.cc', 'browser/renderer_host/audio_renderer_host_unittest.cc', 'browser/renderer_host/gtk_im_context_wrapper_unittest.cc', 'browser/renderer_host/gtk_key_bindings_handler_unittest.cc', diff --git a/chrome/common/net/http_return.h b/chrome/common/net/http_return.h index 7cb7731..517a849 100644 --- a/chrome/common/net/http_return.h +++ b/chrome/common/net/http_return.h @@ -10,9 +10,10 @@ // contains a few HTTP return codes. Add more HTTP return codes. enum HTTPReturnCode { RC_REQUEST_OK = 200, + RC_BAD_REQUEST = 400, RC_UNAUTHORIZED = 401, RC_FORBIDDEN = 403, + RC_INTERNAL_SERVER_ERROR = 500, }; #endif // CHROME_COMMON_NET_HTTP_RETURN_H_ - diff --git a/chrome/service/remoting/remoting_directory_service.cc b/chrome/service/remoting/remoting_directory_service.cc deleted file mode 100644 index e61c0fd..0000000 --- a/chrome/service/remoting/remoting_directory_service.cc +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2010 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 <vector> - -#include "base/json/json_reader.h" -#include "base/json/json_writer.h" -#include "base/values.h" -#include "chrome/common/guid.h" -#include "chrome/common/net/url_request_context_getter.h" -#include "chrome/service/net/service_url_request_context.h" -#include "chrome/service/remoting/remoting_directory_service.h" -#include "net/base/net_util.h" -#include "net/http/http_request_headers.h" -#include "remoting/host/host_key_pair.h" - -static const char kRemotingDirectoryUrl[] = - "https://www.googleapis.com/chromoting/v1/@me/hosts"; - -RemotingDirectoryService::RemotingDirectoryService(Client* client) - : client_(client) { -} - -RemotingDirectoryService::~RemotingDirectoryService() { - DCHECK(!fetcher_.get()) << "URLFetcher not destroyed."; -} - -void RemotingDirectoryService::AddHost(const std::string& token) { - // TODO(hclam): This is a time consuming operation so we should run it on - // a separate thread. - host_key_pair_.reset(new remoting::HostKeyPair()); - host_key_pair_->Generate(); - - // Get a host name and generate a UUID for the request. - host_id_ = guid::GenerateGUID(); - host_name_ = net::GetHostName(); - - // Prepare the parameters for the request. - DictionaryValue data; - data.SetString("hostId", host_id_); - data.SetString("hostName", host_name_); - data.SetString("publicKey", host_key_pair_->GetPublicKey()); - - // Generate the final json query. - DictionaryValue args; - args.Set("data", data.DeepCopy()); - std::string request_content; - base::JSONWriter::Write(&args, false, &request_content); - - // Prepare the HTTP header for authentication. - net::HttpRequestHeaders headers; - headers.SetHeader("Authorization", "GoogleLogin auth=" + token); - fetcher_.reset( - new URLFetcher(GURL(kRemotingDirectoryUrl), URLFetcher::POST, this)); - fetcher_->set_request_context(new ServiceURLRequestContextGetter()); - fetcher_->set_upload_data("application/json", request_content); - fetcher_->set_extra_request_headers(headers.ToString()); - - // And then start the request. - fetcher_->Start(); -} - -void RemotingDirectoryService::CancelRequest() { - fetcher_.reset(); -} - -void RemotingDirectoryService::OnURLFetchComplete( - const URLFetcher* source, - const GURL& url, - const URLRequestStatus& status, - int response_code, - const ResponseCookies& cookies, - const std::string& data) { - // Destroy the fetcher after the response has been received. - fetcher_.reset(); - - // TODO(hclam): Simply checking 200 status is not enough. - if (response_code == 200) { - client_->OnRemotingHostAdded(); - } else { - client_->OnRemotingDirectoryError(); - } -} diff --git a/chrome/service/remoting/remoting_directory_service.h b/chrome/service/remoting/remoting_directory_service.h deleted file mode 100644 index 2c9fc0f..0000000 --- a/chrome/service/remoting/remoting_directory_service.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2010 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. - -#ifndef CHROME_SERVICE_REMOTING_REMOTING_DIRECTORY_SERVICE_H_ -#define CHROME_SERVICE_REMOTING_REMOTING_DIRECTORY_SERVICE_H_ - -#include <string> - -#include "base/scoped_ptr.h" -#include "chrome/common/net/url_fetcher.h" -#include "googleurl/src/gurl.h" - -namespace remoting { -class HostKeyPair; -} // namespace remoting - -// A class to provide access to the remoting directory service. -// TODO(hclam): Should implement this in Javascript. -class RemotingDirectoryService : public URLFetcher::Delegate { - public: - // Client to receive events from the directory service. - class Client { - public: - virtual ~Client() {} - - // Called when a remoting host was added. - virtual void OnRemotingHostAdded() {} - - // Called when the last operation has failed. - virtual void OnRemotingDirectoryError() {} - }; - - explicit RemotingDirectoryService(Client* client); - ~RemotingDirectoryService(); - - // Add this computer as host. Use the token for authentication. - // TODO(hclam): Need more information for this method call. - void AddHost(const std::string& token); - - // Cancel the last requested operation. - void CancelRequest(); - - // URLFetcher::Delegate implementation. - virtual void OnURLFetchComplete(const URLFetcher* source, - const GURL& url, - const URLRequestStatus& status, - int response_code, - const ResponseCookies& cookies, - const std::string& data); - - const std::string& host_id() const { return host_id_; } - const std::string& host_name() const { return host_name_; } - remoting::HostKeyPair* host_key_pair() const { - return host_key_pair_.get(); - } - - private: - Client* client_; - scoped_ptr<URLFetcher> fetcher_; - - // Host key generated during host registration. - scoped_ptr<remoting::HostKeyPair> host_key_pair_; - - // Host info used for registration. - std::string host_id_; - std::string host_name_; - - DISALLOW_COPY_AND_ASSIGN(RemotingDirectoryService); -}; - -#endif // CHROME_SERVICE_REMOTING_REMOTING_DIRECTORY_SERVICE_H_ |