summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/extensions/api/instance_id/instance_id_api.cc3
-rw-r--r--chrome/browser/extensions/api/instance_id/instance_id_api.h2
-rw-r--r--chrome/test/data/extensions/api_test/instance_id/delete_token/delete_token.js44
-rw-r--r--chrome/test/data/extensions/api_test/instance_id/get_token/get_token.js5
-rw-r--r--components/gcm_driver.gypi2
-rw-r--r--components/gcm_driver/BUILD.gn2
-rw-r--r--components/gcm_driver/fake_gcm_client.cc40
-rw-r--r--components/gcm_driver/fake_gcm_client.h21
-rw-r--r--components/gcm_driver/fake_gcm_driver.cc2
-rw-r--r--components/gcm_driver/fake_gcm_driver.h2
-rw-r--r--components/gcm_driver/gcm_client.h53
-rw-r--r--components/gcm_driver/gcm_client_impl.cc284
-rw-r--r--components/gcm_driver/gcm_client_impl.h54
-rw-r--r--components/gcm_driver/gcm_client_impl_unittest.cc61
-rw-r--r--components/gcm_driver/gcm_driver.cc10
-rw-r--r--components/gcm_driver/gcm_driver.h37
-rw-r--r--components/gcm_driver/gcm_driver_android.cc2
-rw-r--r--components/gcm_driver/gcm_driver_android.h2
-rw-r--r--components/gcm_driver/gcm_driver_desktop.cc265
-rw-r--r--components/gcm_driver/gcm_driver_desktop.h42
-rw-r--r--components/gcm_driver/gcm_stats_recorder_impl.cc12
-rw-r--r--components/gcm_driver/gcm_stats_recorder_impl.h6
-rw-r--r--components/gcm_driver/gcm_stats_recorder_impl_unittest.cc5
-rw-r--r--components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.cc56
-rw-r--r--components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h26
-rw-r--r--components/gcm_driver/instance_id/instance_id.h2
-rw-r--r--components/gcm_driver/instance_id/instance_id_driver_unittest.cc121
-rw-r--r--components/gcm_driver/instance_id/instance_id_impl.cc195
-rw-r--r--components/gcm_driver/instance_id/instance_id_impl.h28
-rw-r--r--components/gcm_driver/registration_info.cc251
-rw-r--r--components/gcm_driver/registration_info.h130
-rw-r--r--google_apis/gcm/BUILD.gn12
-rw-r--r--google_apis/gcm/base/gcm_util.cc19
-rw-r--r--google_apis/gcm/base/gcm_util.h21
-rw-r--r--google_apis/gcm/engine/gcm_registration_request_handler.cc29
-rw-r--r--google_apis/gcm/engine/gcm_registration_request_handler.h30
-rw-r--r--google_apis/gcm/engine/gcm_store.h15
-rw-r--r--google_apis/gcm/engine/gcm_store_impl.cc69
-rw-r--r--google_apis/gcm/engine/gcm_store_impl.h6
-rw-r--r--google_apis/gcm/engine/gcm_store_impl_unittest.cc43
-rw-r--r--google_apis/gcm/engine/gcm_unregistration_request_handler.cc68
-rw-r--r--google_apis/gcm/engine/gcm_unregistration_request_handler.h33
-rw-r--r--google_apis/gcm/engine/gservices_settings_unittest.cc1
-rw-r--r--google_apis/gcm/engine/instance_id_delete_token_request_handler.cc65
-rw-r--r--google_apis/gcm/engine/instance_id_delete_token_request_handler.h41
-rw-r--r--google_apis/gcm/engine/instance_id_get_token_request_handler.cc52
-rw-r--r--google_apis/gcm/engine/instance_id_get_token_request_handler.h42
-rw-r--r--google_apis/gcm/engine/registration_info.cc62
-rw-r--r--google_apis/gcm/engine/registration_info.h35
-rw-r--r--google_apis/gcm/engine/registration_request.cc92
-rw-r--r--google_apis/gcm/engine/registration_request.h35
-rw-r--r--google_apis/gcm/engine/registration_request_unittest.cc213
-rw-r--r--google_apis/gcm/engine/unregistration_request.cc141
-rw-r--r--google_apis/gcm/engine/unregistration_request.h34
-rw-r--r--google_apis/gcm/engine/unregistration_request_unittest.cc181
-rw-r--r--google_apis/gcm/gcm.gyp12
-rw-r--r--google_apis/gcm/monitoring/fake_gcm_stats_recorder.cc6
-rw-r--r--google_apis/gcm/monitoring/fake_gcm_stats_recorder.h6
-rw-r--r--google_apis/gcm/monitoring/gcm_stats_recorder.h8
59 files changed, 2463 insertions, 673 deletions
diff --git a/chrome/browser/extensions/api/instance_id/instance_id_api.cc b/chrome/browser/extensions/api/instance_id/instance_id_api.cc
index c57b4ed..6707f4c 100644
--- a/chrome/browser/extensions/api/instance_id/instance_id_api.cc
+++ b/chrome/browser/extensions/api/instance_id/instance_id_api.cc
@@ -19,6 +19,7 @@ namespace {
// Error messages.
const char kInvalidParameter[] = "Function was called with invalid parameters.";
const char kDisabled[] = "Instance ID is currently disabled.";
+const char kAsyncOperationPending[] = "Asynchronous operation is pending.";
const char kNetworkError[] = "Network error occurred.";
const char kServerError[] = "Server error occurred.";
const char kUnknownError[] = "Unknown error occurred.";
@@ -29,6 +30,8 @@ const char* InstanceIDResultToError(instance_id::InstanceID::Result result) {
return kInvalidParameter;
case instance_id::InstanceID::DISABLED:
return kDisabled;
+ case instance_id::InstanceID::ASYNC_OPERATION_PENDING:
+ return kAsyncOperationPending;
case instance_id::InstanceID::NETWORK_ERROR:
return kNetworkError;
case instance_id::InstanceID::SERVER_ERROR:
diff --git a/chrome/browser/extensions/api/instance_id/instance_id_api.h b/chrome/browser/extensions/api/instance_id/instance_id_api.h
index 6ae1f9d0..4665b47 100644
--- a/chrome/browser/extensions/api/instance_id/instance_id_api.h
+++ b/chrome/browser/extensions/api/instance_id/instance_id_api.h
@@ -92,7 +92,7 @@ class InstanceIDGetTokenFunction : public InstanceIDApiFunction {
class InstanceIDDeleteTokenFunction : public InstanceIDApiFunction {
public:
- DECLARE_EXTENSION_FUNCTION("instanceID.DeleteToken", INSTANCEID_DELETETOKEN);
+ DECLARE_EXTENSION_FUNCTION("instanceID.deleteToken", INSTANCEID_DELETETOKEN);
InstanceIDDeleteTokenFunction();
diff --git a/chrome/test/data/extensions/api_test/instance_id/delete_token/delete_token.js b/chrome/test/data/extensions/api_test/instance_id/delete_token/delete_token.js
index cd3db4a..dbf1719 100644
--- a/chrome/test/data/extensions/api_test/instance_id/delete_token/delete_token.js
+++ b/chrome/test/data/extensions/api_test/instance_id/delete_token/delete_token.js
@@ -110,6 +110,43 @@ function deleteTokenAfterGetToken() {
);
}
+var oldToken;
+function getTokenDeleteTokeAndGetToken() {
+ chrome.instanceID.getToken(
+ {"authorizedEntity": "1", "scope": "GCM"},
+ function(token) {
+ if (chrome.runtime.lastError || !token) {
+ chrome.test.fail(
+ "chrome.runtime.lastError was set or token was empty.");
+ return;
+ }
+ oldToken = token;
+ chrome.instanceID.deleteToken(
+ {"authorizedEntity": "1", "scope": "GCM"},
+ function() {
+ if (chrome.runtime.lastError) {
+ chrome.test.fail("chrome.runtime.lastError: " +
+ chrome.runtime.lastError.message);
+ return;
+ }
+
+ chrome.instanceID.getToken(
+ {"authorizedEntity": "1", "scope": "GCM"},
+ function(token) {
+ if (!token || token == oldToken) {
+ chrome.test.fail(
+ "Different token should be returned after deleteToken.");
+ return;
+ }
+ chrome.test.succeed();
+ }
+ );
+ }
+ );
+ }
+ );
+}
+
chrome.test.runTests([
deleteTokenWithoutParameters,
deleteTokenWithoutCallback,
@@ -117,8 +154,7 @@ chrome.test.runTests([
deleteTokenWithInvalidAuthorizedEntity,
deleteTokenWithoutScope,
deleteTokenWithInvalidScope,
- // TODO(jianli): To be enabled when deleteToken is implemented.
- //deleteTokenBeforeGetToken,
- //deleteTokenAfterGetToken,
- //getTokenDeleteTokeAndGetToken,
+ deleteTokenBeforeGetToken,
+ deleteTokenAfterGetToken,
+ getTokenDeleteTokeAndGetToken,
]);
diff --git a/chrome/test/data/extensions/api_test/instance_id/get_token/get_token.js b/chrome/test/data/extensions/api_test/instance_id/get_token/get_token.js
index 7a0a1c9..a679564 100644
--- a/chrome/test/data/extensions/api_test/instance_id/get_token/get_token.js
+++ b/chrome/test/data/extensions/api_test/instance_id/get_token/get_token.js
@@ -127,7 +127,6 @@ chrome.test.runTests([
getTokenWithoutScope,
getTokenWithInvalidScope,
getTokenWithInvalidOptionValue,
- // TODO(jianli): To be enabled when GetToken is implemented.
- //getTokenWithoutOptions,
- //getTokenWithValidOptions,
+ getTokenWithoutOptions,
+ getTokenWithValidOptions,
]);
diff --git a/components/gcm_driver.gypi b/components/gcm_driver.gypi
index b0c90b7..a52086c 100644
--- a/components/gcm_driver.gypi
+++ b/components/gcm_driver.gypi
@@ -54,6 +54,8 @@
'gcm_driver/gcm_driver_desktop.h',
'gcm_driver/gcm_stats_recorder_impl.cc',
'gcm_driver/gcm_stats_recorder_impl.h',
+ 'gcm_driver/registration_info.cc',
+ 'gcm_driver/registration_info.h',
'gcm_driver/system_encryptor.cc',
'gcm_driver/system_encryptor.h',
],
diff --git a/components/gcm_driver/BUILD.gn b/components/gcm_driver/BUILD.gn
index e8c9a17..a75c3d5 100644
--- a/components/gcm_driver/BUILD.gn
+++ b/components/gcm_driver/BUILD.gn
@@ -39,6 +39,8 @@ static_library("gcm_driver") {
"gcm_driver_desktop.h",
"gcm_stats_recorder_impl.cc",
"gcm_stats_recorder_impl.h",
+ "registration_info.cc",
+ "registration_info.h",
"system_encryptor.cc",
"system_encryptor.h",
]
diff --git a/components/gcm_driver/fake_gcm_client.cc b/components/gcm_driver/fake_gcm_client.cc
index 50a4598..b74faa5 100644
--- a/components/gcm_driver/fake_gcm_client.cc
+++ b/components/gcm_driver/fake_gcm_client.cc
@@ -74,27 +74,33 @@ void FakeGCMClient::Stop() {
delegate_->OnDisconnected();
}
-void FakeGCMClient::Register(const std::string& app_id,
- const std::vector<std::string>& sender_ids) {
+void FakeGCMClient::Register(
+ const linked_ptr<RegistrationInfo>& registration_info) {
DCHECK(io_thread_->RunsTasksOnCurrentThread());
- std::string registration_id = GetRegistrationIdFromSenderIds(sender_ids);
+ GCMRegistrationInfo* gcm_registration_info =
+ GCMRegistrationInfo::FromRegistrationInfo(registration_info.get());
+ DCHECK(gcm_registration_info);
+
+ std::string registration_id = GetRegistrationIdFromSenderIds(
+ gcm_registration_info->sender_ids);
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&FakeGCMClient::RegisterFinished,
weak_ptr_factory_.GetWeakPtr(),
- app_id,
+ registration_info,
registration_id));
}
-void FakeGCMClient::Unregister(const std::string& app_id) {
+void FakeGCMClient::Unregister(
+ const linked_ptr<RegistrationInfo>& registration_info) {
DCHECK(io_thread_->RunsTasksOnCurrentThread());
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&FakeGCMClient::UnregisterFinished,
weak_ptr_factory_.GetWeakPtr(),
- app_id));
+ registration_info));
}
void FakeGCMClient::Send(const std::string& app_id,
@@ -138,14 +144,16 @@ void FakeGCMClient::UpdateHeartbeatTimer(scoped_ptr<base::Timer> timer) {
}
void FakeGCMClient::AddInstanceIDData(const std::string& app_id,
- const std::string& instance_id_data) {
+ const std::string& instance_id,
+ const std::string& extra_data) {
}
void FakeGCMClient::RemoveInstanceIDData(const std::string& app_id) {
}
-std::string FakeGCMClient::GetInstanceIDData(const std::string& app_id) {
- return std::string();
+void FakeGCMClient::GetInstanceIDData(const std::string& app_id,
+ std::string* instance_id,
+ std::string* extra_data) {
}
void FakeGCMClient::AddHeartbeatInterval(const std::string& scope,
@@ -211,14 +219,18 @@ void FakeGCMClient::Started() {
delegate_->OnConnected(net::IPEndPoint());
}
-void FakeGCMClient::RegisterFinished(const std::string& app_id,
- const std::string& registrion_id) {
+void FakeGCMClient::RegisterFinished(
+ const linked_ptr<RegistrationInfo>& registration_info,
+ const std::string& registrion_id) {
delegate_->OnRegisterFinished(
- app_id, registrion_id, registrion_id.empty() ? SERVER_ERROR : SUCCESS);
+ registration_info,
+ registrion_id,
+ registrion_id.empty() ? SERVER_ERROR : SUCCESS);
}
-void FakeGCMClient::UnregisterFinished(const std::string& app_id) {
- delegate_->OnUnregisterFinished(app_id, GCMClient::SUCCESS);
+void FakeGCMClient::UnregisterFinished(
+ const linked_ptr<RegistrationInfo>& registration_info) {
+ delegate_->OnUnregisterFinished(registration_info, GCMClient::SUCCESS);
}
void FakeGCMClient::SendFinished(const std::string& app_id,
diff --git a/components/gcm_driver/fake_gcm_client.h b/components/gcm_driver/fake_gcm_client.h
index 155c342..73fa6b9 100644
--- a/components/gcm_driver/fake_gcm_client.h
+++ b/components/gcm_driver/fake_gcm_client.h
@@ -41,9 +41,9 @@ class FakeGCMClient : public GCMClient {
Delegate* delegate) override;
void Start(StartMode start_mode) override;
void Stop() override;
- void Register(const std::string& app_id,
- const std::vector<std::string>& sender_ids) override;
- void Unregister(const std::string& app_id) override;
+ void Register(const linked_ptr<RegistrationInfo>& registration_info) override;
+ void Unregister(
+ const linked_ptr<RegistrationInfo>& registration_info) override;
void Send(const std::string& app_id,
const std::string& receiver_id,
const OutgoingMessage& message) override;
@@ -57,9 +57,12 @@ class FakeGCMClient : public GCMClient {
void SetLastTokenFetchTime(const base::Time& time) override;
void UpdateHeartbeatTimer(scoped_ptr<base::Timer> timer) override;
void AddInstanceIDData(const std::string& app_id,
- const std::string& instance_id_data) override;
+ const std::string& instance_id,
+ const std::string& extra_data) override;
void RemoveInstanceIDData(const std::string& app_id) override;
- std::string GetInstanceIDData(const std::string& app_id) override;
+ void GetInstanceIDData(const std::string& app_id,
+ std::string* instance_id,
+ std::string* extra_data) override;
void AddHeartbeatInterval(const std::string& scope, int interval_ms) override;
void RemoveHeartbeatInterval(const std::string& scope) override;
@@ -84,9 +87,11 @@ class FakeGCMClient : public GCMClient {
// Called on IO thread.
void DoStart();
void Started();
- void RegisterFinished(const std::string& app_id,
- const std::string& registrion_id);
- void UnregisterFinished(const std::string& app_id);
+ void RegisterFinished(
+ const linked_ptr<RegistrationInfo>& registration_info,
+ const std::string& registrion_id);
+ void UnregisterFinished(
+ const linked_ptr<RegistrationInfo>& registration_info);
void SendFinished(const std::string& app_id, const OutgoingMessage& message);
void MessageReceived(const std::string& app_id,
const IncomingMessage& message);
diff --git a/components/gcm_driver/fake_gcm_driver.cc b/components/gcm_driver/fake_gcm_driver.cc
index 15b41fd..dfdd918 100644
--- a/components/gcm_driver/fake_gcm_driver.cc
+++ b/components/gcm_driver/fake_gcm_driver.cc
@@ -98,7 +98,7 @@ void FakeGCMDriver::SetLastTokenFetchTime(const base::Time& time) {
void FakeGCMDriver::WakeFromSuspendForHeartbeat(bool wake) {
}
-InstanceIDStore* FakeGCMDriver::GetInstanceIDStore() {
+InstanceIDHandler* FakeGCMDriver::GetInstanceIDHandler() {
return NULL;
}
diff --git a/components/gcm_driver/fake_gcm_driver.h b/components/gcm_driver/fake_gcm_driver.h
index 0c289f0..96bad7a 100644
--- a/components/gcm_driver/fake_gcm_driver.h
+++ b/components/gcm_driver/fake_gcm_driver.h
@@ -41,7 +41,7 @@ class FakeGCMDriver : public GCMDriver {
base::Time GetLastTokenFetchTime() override;
void SetLastTokenFetchTime(const base::Time& time) override;
void WakeFromSuspendForHeartbeat(bool wake) override;
- InstanceIDStore* GetInstanceIDStore() override;
+ InstanceIDHandler* GetInstanceIDHandler() override;
void AddHeartbeatInterval(const std::string& scope, int interval_ms) override;
void RemoveHeartbeatInterval(const std::string& scope) override;
diff --git a/components/gcm_driver/gcm_client.h b/components/gcm_driver/gcm_client.h
index 8672233..cb6042f 100644
--- a/components/gcm_driver/gcm_client.h
+++ b/components/gcm_driver/gcm_client.h
@@ -10,8 +10,10 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/memory/linked_ptr.h"
#include "base/memory/scoped_ptr.h"
#include "components/gcm_driver/gcm_activity.h"
+#include "components/gcm_driver/registration_info.h"
template <class T> class scoped_refptr;
@@ -163,18 +165,22 @@ class GCMClient {
class Delegate {
public:
// Called when the registration completed successfully or an error occurs.
- // |app_id|: application ID.
+ // |registration_info|: the specific information required for the
+ // registration.
// |registration_id|: non-empty if the registration completed successfully.
// |result|: the type of the error if an error occured, success otherwise.
- virtual void OnRegisterFinished(const std::string& app_id,
- const std::string& registration_id,
- Result result) = 0;
+ virtual void OnRegisterFinished(
+ const linked_ptr<RegistrationInfo>& registration_info,
+ const std::string& registration_id,
+ Result result) = 0;
// Called when the unregistration completed.
- // |app_id|: application ID.
+ // |registration_info|: the specific information required for the
+ // registration.
// |result|: result of the unregistration.
- virtual void OnUnregisterFinished(const std::string& app_id,
- GCMClient::Result result) = 0;
+ virtual void OnUnregisterFinished(
+ const linked_ptr<RegistrationInfo>& registration_info,
+ GCMClient::Result result) = 0;
// Called when the message is scheduled to send successfully or an error
// occurs.
@@ -258,20 +264,24 @@ class GCMClient {
// Stops using the GCM service. This will not erase the persisted data.
virtual void Stop() = 0;
- // Registers the application for GCM. Delegate::OnRegisterFinished will be
- // called asynchronously upon completion.
- // |app_id|: application ID.
- // |sender_ids|: list of IDs of the servers that are allowed to send the
- // messages to the application. These IDs are assigned by the
- // Google API Console.
- virtual void Register(const std::string& app_id,
- const std::vector<std::string>& sender_ids) = 0;
+ // Registers with the server to access the provided service.
+ // Delegate::OnRegisterFinished will be called asynchronously upon completion.
+ // |registration_info|: the specific information required for the
+ // registration. For GCM, it will contain app id and
+ // sender IDs. For InstanceID, it will contain app_id,
+ // authorized entity and scope.
+ virtual void Register(
+ const linked_ptr<RegistrationInfo>& registration_info) = 0;
- // Unregisters the application from GCM when it is uninstalled.
+ // Unregisters from the server to stop accessing the provided service.
// Delegate::OnUnregisterFinished will be called asynchronously upon
// completion.
- // |app_id|: application ID.
- virtual void Unregister(const std::string& app_id) = 0;
+ // |registration_info|: the specific information required for the
+ // registration. For GCM, it will contain app id (sender
+ // IDs can be ingored). For InstanceID, it will contain
+ // app id, authorized entity and scope.
+ virtual void Unregister(
+ const linked_ptr<RegistrationInfo>& registration_info) = 0;
// Sends a message to a given receiver. Delegate::OnSendFinished will be
// called asynchronously upon completion.
@@ -312,14 +322,17 @@ class GCMClient {
// Adds the Instance ID data for a specific app to the persistent store.
virtual void AddInstanceIDData(const std::string& app_id,
- const std::string& instance_id_data) = 0;
+ const std::string& instance_id,
+ const std::string& extra_data) = 0;
// Removes the Instance ID data for a specific app from the persistent store.
virtual void RemoveInstanceIDData(const std::string& app_id) = 0;
// Retrieves the Instance ID data for a specific app from the persistent
// store.
- virtual std::string GetInstanceIDData(const std::string& app_id) = 0;
+ virtual void GetInstanceIDData(const std::string& app_id,
+ std::string* instance_id,
+ std::string* extra_data) = 0;
// Gets and sets custom heartbeat interval for the MCS connection.
// |scope| is used to identify the component that requests a custom interval
diff --git a/components/gcm_driver/gcm_client_impl.cc b/components/gcm_driver/gcm_client_impl.cc
index 448e416..13d7b62 100644
--- a/components/gcm_driver/gcm_client_impl.cc
+++ b/components/gcm_driver/gcm_client_impl.cc
@@ -23,7 +23,11 @@
#include "google_apis/gcm/base/mcs_util.h"
#include "google_apis/gcm/engine/checkin_request.h"
#include "google_apis/gcm/engine/connection_factory_impl.h"
+#include "google_apis/gcm/engine/gcm_registration_request_handler.h"
#include "google_apis/gcm/engine/gcm_store_impl.h"
+#include "google_apis/gcm/engine/gcm_unregistration_request_handler.h"
+#include "google_apis/gcm/engine/instance_id_delete_token_request_handler.h"
+#include "google_apis/gcm/engine/instance_id_get_token_request_handler.h"
#include "google_apis/gcm/monitoring/gcm_stats_recorder.h"
#include "google_apis/gcm/protocol/checkin.pb.h"
#include "google_apis/gcm/protocol/mcs.pb.h"
@@ -67,6 +71,7 @@ enum ResetStoreError {
RESET_STORE_ERROR_COUNT
};
+const char kGCMScope[] = "GCM";
const int kMaxRegistrationRetries = 5;
const char kMessageTypeDataMessage[] = "gcm";
const char kMessageTypeDeletedMessagesKey[] = "deleted_messages";
@@ -169,6 +174,39 @@ MessageType DecodeMessageType(const std::string& value) {
return UNKNOWN;
}
+int ConstructGCMVersion(const std::string& chrome_version) {
+ // Major Chrome version is passed as GCM version.
+ size_t pos = chrome_version.find('.');
+ if (pos == std::string::npos) {
+ NOTREACHED();
+ return 0;
+ }
+
+ int gcm_version = 0;
+ base::StringToInt(
+ base::StringPiece(chrome_version.c_str(), pos), &gcm_version);
+ return gcm_version;
+}
+
+std::string SerializeInstanceIDData(const std::string& instance_id,
+ const std::string& extra_data) {
+ DCHECK(!instance_id.empty() && !extra_data.empty());
+ DCHECK(instance_id.find(',') == std::string::npos);
+ return instance_id + "," + extra_data;
+}
+
+bool DeserializeInstanceIDData(const std::string& serialized_data,
+ std::string* instance_id,
+ std::string* extra_data) {
+ DCHECK(instance_id && extra_data);
+ std::size_t pos = serialized_data.find(',');
+ if (pos == std::string::npos)
+ return false;
+ *instance_id = serialized_data.substr(0, pos);
+ *extra_data = serialized_data.substr(pos + 1);
+ return !instance_id->empty() && !extra_data->empty();
+}
+
void RecordOutgoingMessageToUMA(
const gcm::GCMClient::OutgoingMessage& message) {
OutgoingMessageTTLCategory ttl_category;
@@ -335,7 +373,6 @@ void GCMClientImpl::OnLoadCompleted(scoped_ptr<GCMStore::LoadResult> result) {
}
gcm_store_reset_ = false;
- registrations_ = result->registrations;
device_checkin_info_.android_id = result->device_android_id;
device_checkin_info_.secret = result->device_security_token;
device_checkin_info_.last_checkin_accounts = result->last_checkin_accounts;
@@ -348,7 +385,28 @@ void GCMClientImpl::OnLoadCompleted(scoped_ptr<GCMStore::LoadResult> result) {
device_checkin_info_.accounts_set = true;
last_checkin_time_ = result->last_checkin_time;
gservices_settings_.UpdateFromLoadResult(*result);
- instance_id_data_ = result->instance_id_data;
+
+ for (auto iter = result->registrations.begin();
+ iter != result->registrations.end();
+ ++iter) {
+ std::string registration_id;
+ scoped_ptr<RegistrationInfo> registration =
+ RegistrationInfo::BuildFromString(
+ iter->first, iter->second, &registration_id);
+ // TODO(jianli): Add UMA to track the error case.
+ if (registration.get())
+ registrations_[make_linked_ptr(registration.release())] = registration_id;
+ }
+
+ for (auto iter = result->instance_id_data.begin();
+ iter != result->instance_id_data.end();
+ ++iter) {
+ std::string instance_id;
+ std::string extra_data;
+ if (DeserializeInstanceIDData(iter->second, &instance_id, &extra_data))
+ instance_id_data_[iter->first] = std::make_pair(instance_id, extra_data);
+ }
+
load_result_ = result.Pass();
state_ = LOADED;
@@ -532,11 +590,12 @@ void GCMClientImpl::UpdateHeartbeatTimer(scoped_ptr<base::Timer> timer) {
}
void GCMClientImpl::AddInstanceIDData(const std::string& app_id,
- const std::string& instance_id_data) {
- instance_id_data_[app_id] = instance_id_data;
+ const std::string& instance_id,
+ const std::string& extra_data) {
+ instance_id_data_[app_id] = std::make_pair(instance_id, extra_data);
gcm_store_->AddInstanceIDData(
app_id,
- instance_id_data,
+ SerializeInstanceIDData(instance_id, extra_data),
base::Bind(&GCMClientImpl::IgnoreWriteResultCallback,
weak_ptr_factory_.GetWeakPtr()));
}
@@ -549,11 +608,16 @@ void GCMClientImpl::RemoveInstanceIDData(const std::string& app_id) {
weak_ptr_factory_.GetWeakPtr()));
}
-std::string GCMClientImpl::GetInstanceIDData(const std::string& app_id) {
+void GCMClientImpl::GetInstanceIDData(const std::string& app_id,
+ std::string* instance_id,
+ std::string* extra_data) {
+ DCHECK(instance_id && extra_data);
+
auto iter = instance_id_data_.find(app_id);
if (iter == instance_id_data_.end())
- return std::string();
- return iter->second;
+ return;
+ *instance_id = iter->second.first;
+ *extra_data = iter->second.second;
}
void GCMClientImpl::AddHeartbeatInterval(const std::string& scope,
@@ -721,53 +785,105 @@ void GCMClientImpl::Stop() {
gcm_store_->Close();
}
-void GCMClientImpl::Register(const std::string& app_id,
- const std::vector<std::string>& sender_ids) {
+void GCMClientImpl::Register(
+ const linked_ptr<RegistrationInfo>& registration_info) {
DCHECK_EQ(state_, READY);
- // If the same sender ids is provided, return the cached registration ID
- // directly.
+ // Find and use the cached registration ID.
RegistrationInfoMap::const_iterator registrations_iter =
- registrations_.find(app_id);
- if (registrations_iter != registrations_.end() &&
- registrations_iter->second->sender_ids == sender_ids) {
- delegate_->OnRegisterFinished(
- app_id, registrations_iter->second->registration_id, SUCCESS);
- return;
+ registrations_.find(registration_info);
+ if (registrations_iter != registrations_.end()) {
+ bool matched = true;
+
+ // For GCM registration, we also match the sender IDs since multiple
+ // registrations are not supported.
+ const GCMRegistrationInfo* gcm_registration_info =
+ GCMRegistrationInfo::FromRegistrationInfo(registration_info.get());
+ if (gcm_registration_info) {
+ const GCMRegistrationInfo* cached_gcm_registration_info =
+ GCMRegistrationInfo::FromRegistrationInfo(
+ registrations_iter->first.get());
+ DCHECK(cached_gcm_registration_info);
+ if (cached_gcm_registration_info &&
+ gcm_registration_info->sender_ids !=
+ cached_gcm_registration_info->sender_ids) {
+ matched = false;
+ }
+ }
+
+ if (matched) {
+ delegate_->OnRegisterFinished(
+ registration_info, registrations_iter->second, SUCCESS);
+ return;
+ }
+ }
+
+ scoped_ptr<RegistrationRequest::CustomRequestHandler> request_handler;
+ std::string source_to_record;
+
+ const GCMRegistrationInfo* gcm_registration_info =
+ GCMRegistrationInfo::FromRegistrationInfo(registration_info.get());
+ if (gcm_registration_info) {
+ std::string senders;
+ for (auto iter = gcm_registration_info->sender_ids.begin();
+ iter != gcm_registration_info->sender_ids.end();
+ ++iter) {
+ if (!senders.empty())
+ senders.append(",");
+ senders.append(*iter);
+ }
+ UMA_HISTOGRAM_COUNTS("GCM.RegistrationSenderIdCount",
+ gcm_registration_info->sender_ids.size());
+
+ request_handler.reset(new GCMRegistrationRequestHandler(senders));
+ source_to_record = senders;
+ }
+
+ const InstanceIDTokenInfo* instance_id_token_info =
+ InstanceIDTokenInfo::FromRegistrationInfo(registration_info.get());
+ if (instance_id_token_info) {
+ auto instance_id_iter = instance_id_data_.find(registration_info->app_id);
+ DCHECK(instance_id_iter != instance_id_data_.end());
+
+ request_handler.reset(new InstanceIDGetTokenRequestHandler(
+ instance_id_iter->second.first,
+ instance_id_token_info->authorized_entity,
+ instance_id_token_info->scope,
+ ConstructGCMVersion(chrome_build_info_.version),
+ instance_id_token_info->options));
+ source_to_record = instance_id_token_info->authorized_entity;
}
RegistrationRequest::RequestInfo request_info(
device_checkin_info_.android_id,
device_checkin_info_.secret,
- app_id,
- sender_ids);
- DCHECK_EQ(0u, pending_registration_requests_.count(app_id));
+ registration_info->app_id);
RegistrationRequest* registration_request =
new RegistrationRequest(gservices_settings_.GetRegistrationURL(),
request_info,
+ request_handler.Pass(),
GetGCMBackoffPolicy(),
base::Bind(&GCMClientImpl::OnRegisterCompleted,
- weak_ptr_factory_.GetWeakPtr(),
- app_id,
- sender_ids),
+ weak_ptr_factory_.GetWeakPtr(),
+ registration_info),
kMaxRegistrationRetries,
url_request_context_getter_,
- &recorder_);
- pending_registration_requests_[app_id] = registration_request;
+ &recorder_,
+ source_to_record);
+ pending_registration_requests_[registration_info] = registration_request;
registration_request->Start();
}
void GCMClientImpl::OnRegisterCompleted(
- const std::string& app_id,
- const std::vector<std::string>& sender_ids,
+ const linked_ptr<RegistrationInfo>& registration_info,
RegistrationRequest::Status status,
const std::string& registration_id) {
DCHECK(delegate_);
Result result;
PendingRegistrationRequests::iterator iter =
- pending_registration_requests_.find(app_id);
+ pending_registration_requests_.find(registration_info);
if (iter == pending_registration_requests_.end())
result = UNKNOWN_ERROR;
else if (status == RegistrationRequest::INVALID_SENDER)
@@ -779,21 +895,20 @@ void GCMClientImpl::OnRegisterCompleted(
if (result == SUCCESS) {
// Cache it.
- linked_ptr<RegistrationInfo> registration(new RegistrationInfo);
- registration->sender_ids = sender_ids;
- registration->registration_id = registration_id;
- registrations_[app_id] = registration;
+ registrations_[registration_info] = registration_id;
// Save it in the persistent store.
gcm_store_->AddRegistration(
- app_id,
- registration,
+ registration_info->GetSerializedKey(),
+ registration_info->GetSerializedValue(registration_id),
base::Bind(&GCMClientImpl::UpdateRegistrationCallback,
weak_ptr_factory_.GetWeakPtr()));
}
delegate_->OnRegisterFinished(
- app_id, result == SUCCESS ? registration_id : std::string(), result);
+ registration_info,
+ result == SUCCESS ? registration_id : std::string(),
+ result);
if (iter != pending_registration_requests_.end()) {
delete iter->second;
@@ -801,47 +916,71 @@ void GCMClientImpl::OnRegisterCompleted(
}
}
-void GCMClientImpl::Unregister(const std::string& app_id) {
+void GCMClientImpl::Unregister(
+ const linked_ptr<RegistrationInfo>& registration_info) {
DCHECK_EQ(state_, READY);
- if (pending_unregistration_requests_.count(app_id) == 1)
+ if (pending_unregistration_requests_.count(registration_info) == 1)
return;
// Remove from the cache and persistent store.
- registrations_.erase(app_id);
+ registrations_.erase(registration_info);
gcm_store_->RemoveRegistration(
- app_id,
+ registration_info->GetSerializedKey(),
base::Bind(&GCMClientImpl::UpdateRegistrationCallback,
weak_ptr_factory_.GetWeakPtr()));
+ scoped_ptr<UnregistrationRequest::CustomRequestHandler> request_handler;
+
+ const GCMRegistrationInfo* gcm_registration_info =
+ GCMRegistrationInfo::FromRegistrationInfo(registration_info.get());
+ if (gcm_registration_info) {
+ request_handler.reset(
+ new GCMUnregistrationRequestHandler(registration_info->app_id));
+ }
+
+ const InstanceIDTokenInfo* instance_id_token_info =
+ InstanceIDTokenInfo::FromRegistrationInfo(registration_info.get());
+ if (instance_id_token_info) {
+ auto instance_id_iter = instance_id_data_.find(registration_info->app_id);
+ DCHECK(instance_id_iter != instance_id_data_.end());
+
+ request_handler.reset(new InstanceIDDeleteTokenRequestHandler(
+ instance_id_iter->second.first,
+ instance_id_token_info->authorized_entity,
+ instance_id_token_info->scope,
+ ConstructGCMVersion(chrome_build_info_.version)));
+ }
+
UnregistrationRequest::RequestInfo request_info(
device_checkin_info_.android_id,
device_checkin_info_.secret,
- app_id);
+ registration_info->app_id);
UnregistrationRequest* unregistration_request = new UnregistrationRequest(
gservices_settings_.GetRegistrationURL(),
request_info,
+ request_handler.Pass(),
GetGCMBackoffPolicy(),
base::Bind(&GCMClientImpl::OnUnregisterCompleted,
- weak_ptr_factory_.GetWeakPtr(),
- app_id),
+ weak_ptr_factory_.GetWeakPtr(),
+ registration_info),
url_request_context_getter_,
&recorder_);
- pending_unregistration_requests_[app_id] = unregistration_request;
+ pending_unregistration_requests_[registration_info] = unregistration_request;
unregistration_request->Start();
}
void GCMClientImpl::OnUnregisterCompleted(
- const std::string& app_id,
+ const linked_ptr<RegistrationInfo>& registration_info,
UnregistrationRequest::Status status) {
- DVLOG(1) << "Unregister completed for app: " << app_id
+ DVLOG(1) << "Unregister completed for app: " << registration_info->app_id
<< " with " << (status ? "success." : "failure.");
delegate_->OnUnregisterFinished(
- app_id,
+ registration_info,
status == UnregistrationRequest::SUCCESS ? SUCCESS : SERVER_ERROR);
PendingUnregistrationRequests::iterator iter =
- pending_unregistration_requests_.find(app_id);
+ pending_unregistration_requests_.find(registration_info);
if (iter == pending_unregistration_requests_.end())
return;
@@ -929,7 +1068,7 @@ GCMClient::GCMStatistics GCMClientImpl::GetStatistics() const {
for (RegistrationInfoMap::const_iterator it = registrations_.begin();
it != registrations_.end(); ++it) {
- stats.registered_app_ids.push_back(it->first);
+ stats.registered_app_ids.push_back(it->first->app_id);
}
return stats;
}
@@ -1047,21 +1186,46 @@ void GCMClientImpl::HandleIncomingDataMessage(
const mcs_proto::DataMessageStanza& data_message_stanza,
MessageData& message_data) {
std::string app_id = data_message_stanza.category();
+ std::string sender = data_message_stanza.from();
// Drop the message when the app is not registered for the sender of the
// message.
- RegistrationInfoMap::iterator iter = registrations_.find(app_id);
- bool not_registered =
- iter == registrations_.end() ||
- std::find(iter->second->sender_ids.begin(),
- iter->second->sender_ids.end(),
- data_message_stanza.from()) == iter->second->sender_ids.end();
- recorder_.RecordDataMessageReceived(app_id, data_message_stanza.from(),
- data_message_stanza.ByteSize(), !not_registered,
+ bool registered = false;
+
+ // First, find among all GCM registrations.
+ scoped_ptr<GCMRegistrationInfo> gcm_registration(new GCMRegistrationInfo);
+ gcm_registration->app_id = app_id;
+ auto gcm_registration_iter = registrations_.find(
+ make_linked_ptr<RegistrationInfo>(gcm_registration.release()));
+ if (gcm_registration_iter != registrations_.end()) {
+ GCMRegistrationInfo* cached_gcm_registration =
+ GCMRegistrationInfo::FromRegistrationInfo(
+ gcm_registration_iter->first.get());
+ if (cached_gcm_registration &&
+ std::find(cached_gcm_registration->sender_ids.begin(),
+ cached_gcm_registration->sender_ids.end(),
+ sender) != cached_gcm_registration->sender_ids.end()) {
+ registered = true;
+ }
+ }
+
+ // Then, find among all InstanceID registrations.
+ if (!registered) {
+ scoped_ptr<InstanceIDTokenInfo> instance_id_token(new InstanceIDTokenInfo);
+ instance_id_token->app_id = app_id;
+ instance_id_token->authorized_entity = sender;
+ instance_id_token->scope = kGCMScope;
+ auto instance_id_token_iter = registrations_.find(
+ make_linked_ptr<RegistrationInfo>(instance_id_token.release()));
+ if (instance_id_token_iter != registrations_.end())
+ registered = true;
+ }
+
+ recorder_.RecordDataMessageReceived(app_id, sender,
+ data_message_stanza.ByteSize(), registered,
GCMStatsRecorder::DATA_MESSAGE);
- if (not_registered) {
+ if (!registered)
return;
- }
IncomingMessage incoming_message;
incoming_message.sender_id = data_message_stanza.from();
@@ -1099,7 +1263,7 @@ bool GCMClientImpl::HasStandaloneRegisteredApp() const {
// Note that account mapper is not counted as a standalone app since it is
// automatically started when other app uses GCM.
return registrations_.size() > 1 ||
- !registrations_.count(kGCMAccountMapperAppId);
+ !ExistsGCMRegistrationInMap(registrations_, kGCMAccountMapperAppId);
}
} // namespace gcm
diff --git a/components/gcm_driver/gcm_client_impl.h b/components/gcm_driver/gcm_client_impl.h
index e9f2f14..a39ffdd 100644
--- a/components/gcm_driver/gcm_client_impl.h
+++ b/components/gcm_driver/gcm_client_impl.h
@@ -8,6 +8,7 @@
#include <map>
#include <set>
#include <string>
+#include <utility>
#include <vector>
#include "base/compiler_specific.h"
@@ -111,9 +112,9 @@ class GCMClientImpl
GCMClient::Delegate* delegate) override;
void Start(StartMode start_mode) override;
void Stop() override;
- void Register(const std::string& app_id,
- const std::vector<std::string>& sender_ids) override;
- void Unregister(const std::string& app_id) override;
+ void Register(const linked_ptr<RegistrationInfo>& registration_info) override;
+ void Unregister(
+ const linked_ptr<RegistrationInfo>& registration_info) override;
void Send(const std::string& app_id,
const std::string& receiver_id,
const OutgoingMessage& message) override;
@@ -127,9 +128,12 @@ class GCMClientImpl
void SetLastTokenFetchTime(const base::Time& time) override;
void UpdateHeartbeatTimer(scoped_ptr<base::Timer> timer) override;
void AddInstanceIDData(const std::string& app_id,
- const std::string& instance_id_data) override;
+ const std::string& instance_id,
+ const std::string& extra_data) override;
void RemoveInstanceIDData(const std::string& app_id) override;
- std::string GetInstanceIDData(const std::string& app_id) override;
+ void GetInstanceIDData(const std::string& app_id,
+ std::string* instance_id,
+ std::string* extra_data) override;
void AddHeartbeatInterval(const std::string& scope, int interval_ms) override;
void RemoveHeartbeatInterval(const std::string& scope) override;
@@ -165,17 +169,19 @@ class GCMClientImpl
std::set<std::string> last_checkin_accounts;
};
- // Collection of pending registration requests. Keys are app IDs, while values
- // are pending registration requests to obtain a registration ID for
- // requesting application.
- typedef std::map<std::string, RegistrationRequest*>
- PendingRegistrationRequests;
+ // Collection of pending registration requests. Keys are RegistrationInfo
+ // instance, while values are pending registration requests to obtain a
+ // registration ID for requesting application.
+ typedef std::map<linked_ptr<RegistrationInfo>,
+ RegistrationRequest*,
+ RegistrationInfoComparer> PendingRegistrationRequests;
- // Collection of pending unregistration requests. Keys are app IDs, while
- // values are pending unregistration requests to disable the registration ID
- // currently assigned to the application.
- typedef std::map<std::string, UnregistrationRequest*>
- PendingUnregistrationRequests;
+ // Collection of pending unregistration requests. Keys are RegistrationInfo
+ // instance, while values are pending unregistration requests to disable the
+ // registration ID currently assigned to the application.
+ typedef std::map<linked_ptr<RegistrationInfo>,
+ UnregistrationRequest*,
+ RegistrationInfoComparer> PendingUnregistrationRequests;
friend class GCMClientImplTest;
@@ -247,14 +253,15 @@ class GCMClientImpl
void ResetStoreCallback(bool success);
// Completes the registration request.
- void OnRegisterCompleted(const std::string& app_id,
- const std::vector<std::string>& sender_ids,
- RegistrationRequest::Status status,
- const std::string& registration_id);
+ void OnRegisterCompleted(
+ const linked_ptr<RegistrationInfo>& registration_info,
+ RegistrationRequest::Status status,
+ const std::string& registration_id);
// Completes the unregistration request.
- void OnUnregisterCompleted(const std::string& app_id,
- UnregistrationRequest::Status status);
+ void OnUnregisterCompleted(
+ const linked_ptr<RegistrationInfo>& registration_info,
+ UnregistrationRequest::Status status);
// Completes the GCM store destroy request.
void OnGCMStoreDestroyed(bool success);
@@ -347,8 +354,9 @@ class GCMClientImpl
// Time of the last successful checkin.
base::Time last_checkin_time_;
- // Cached instance ID data, key is app id.
- std::map<std::string, std::string> instance_id_data_;
+ // Cached instance ID data, key is app ID and value is pair of instance ID
+ // and extra data.
+ std::map<std::string, std::pair<std::string, std::string>> instance_id_data_;
// Factory for creating references when scheduling periodic checkin.
base::WeakPtrFactory<GCMClientImpl> periodic_checkin_ptr_factory_;
diff --git a/components/gcm_driver/gcm_client_impl_unittest.cc b/components/gcm_driver/gcm_client_impl_unittest.cc
index a9a2429..54d978e 100644
--- a/components/gcm_driver/gcm_client_impl_unittest.cc
+++ b/components/gcm_driver/gcm_client_impl_unittest.cc
@@ -248,6 +248,9 @@ class GCMClientImplTest : public testing::Test,
void BuildGCMClient(base::TimeDelta clock_step);
void InitializeGCMClient();
void StartGCMClient();
+ void Register(const std::string& app_id,
+ const std::vector<std::string>& senders);
+ void Unregister(const std::string& app_id);
void ReceiveMessageFromMCS(const MCSMessage& message);
void ReceiveOnMessageSentToMCS(
const std::string& app_id,
@@ -267,11 +270,12 @@ class GCMClientImplTest : public testing::Test,
const std::string& registration_id);
// GCMClient::Delegate overrides (for verification).
- void OnRegisterFinished(const std::string& app_id,
+ void OnRegisterFinished(const linked_ptr<RegistrationInfo>& registration_info,
const std::string& registration_id,
GCMClient::Result result) override;
- void OnUnregisterFinished(const std::string& app_id,
- GCMClient::Result result) override;
+ void OnUnregisterFinished(
+ const linked_ptr<RegistrationInfo>& registration_info,
+ GCMClient::Result result) override;
void OnSendFinished(const std::string& app_id,
const std::string& message_id,
GCMClient::Result result) override {}
@@ -494,17 +498,17 @@ void GCMClientImplTest::VerifyPendingRequestFetcherDeleted() {
}
bool GCMClientImplTest::ExistsRegistration(const std::string& app_id) const {
- return gcm_client_->registrations_.count(app_id) > 0;
+ return ExistsGCMRegistrationInMap(gcm_client_->registrations_, app_id);
}
void GCMClientImplTest::AddRegistration(
const std::string& app_id,
const std::vector<std::string>& sender_ids,
const std::string& registration_id) {
- linked_ptr<RegistrationInfo> registration(new RegistrationInfo);
+ linked_ptr<GCMRegistrationInfo> registration(new GCMRegistrationInfo);
+ registration->app_id = app_id;
registration->sender_ids = sender_ids;
- registration->registration_id = registration_id;
- gcm_client_->registrations_[app_id] = registration;
+ gcm_client_->registrations_[registration] = registration_id;
}
void GCMClientImplTest::InitializeGCMClient() {
@@ -527,6 +531,21 @@ void GCMClientImplTest::StartGCMClient() {
PumpLoopUntilIdle();
}
+void GCMClientImplTest::Register(const std::string& app_id,
+ const std::vector<std::string>& senders) {
+ scoped_ptr<GCMRegistrationInfo> gcm_info(new GCMRegistrationInfo);
+ gcm_info->app_id = app_id;
+ gcm_info->sender_ids = senders;
+ gcm_client()->Register(make_linked_ptr<RegistrationInfo>(gcm_info.release()));
+}
+
+void GCMClientImplTest::Unregister(const std::string& app_id) {
+ scoped_ptr<GCMRegistrationInfo> gcm_info(new GCMRegistrationInfo);
+ gcm_info->app_id = app_id;
+ gcm_client()->Unregister(
+ make_linked_ptr<RegistrationInfo>(gcm_info.release()));
+}
+
void GCMClientImplTest::ReceiveMessageFromMCS(const MCSMessage& message) {
gcm_client_->recorder_.RecordConnectionInitiated(std::string());
gcm_client_->recorder_.RecordConnectionSuccess();
@@ -558,19 +577,21 @@ void GCMClientImplTest::OnMessageReceived(
QuitLoop();
}
-void GCMClientImplTest::OnRegisterFinished(const std::string& app_id,
- const std::string& registration_id,
- GCMClient::Result result) {
+void GCMClientImplTest::OnRegisterFinished(
+ const linked_ptr<RegistrationInfo>& registration_info,
+ const std::string& registration_id,
+ GCMClient::Result result) {
last_event_ = REGISTRATION_COMPLETED;
- last_app_id_ = app_id;
+ last_app_id_ = registration_info->app_id;
last_registration_id_ = registration_id;
last_result_ = result;
}
-void GCMClientImplTest::OnUnregisterFinished(const std::string& app_id,
- GCMClient::Result result) {
+void GCMClientImplTest::OnUnregisterFinished(
+ const linked_ptr<RegistrationInfo>& registration_info,
+ GCMClient::Result result) {
last_event_ = UNREGISTRATION_COMPLETED;
- last_app_id_ = app_id;
+ last_app_id_ = registration_info->app_id;
last_result_ = result;
}
@@ -642,7 +663,7 @@ TEST_F(GCMClientImplTest, RegisterApp) {
std::vector<std::string> senders;
senders.push_back("sender");
- gcm_client()->Register(kAppId, senders);
+ Register(kAppId, senders);
CompleteRegistration("reg_id");
EXPECT_EQ(REGISTRATION_COMPLETED, last_event());
@@ -657,7 +678,7 @@ TEST_F(GCMClientImplTest, DISABLED_RegisterAppFromCache) {
std::vector<std::string> senders;
senders.push_back("sender");
- gcm_client()->Register(kAppId, senders);
+ Register(kAppId, senders);
CompleteRegistration("reg_id");
EXPECT_TRUE(ExistsRegistration(kAppId));
@@ -679,11 +700,11 @@ TEST_F(GCMClientImplTest, UnregisterApp) {
std::vector<std::string> senders;
senders.push_back("sender");
- gcm_client()->Register(kAppId, senders);
+ Register(kAppId, senders);
CompleteRegistration("reg_id");
EXPECT_TRUE(ExistsRegistration(kAppId));
- gcm_client()->Unregister(kAppId);
+ Unregister(kAppId);
CompleteUnregistration(kAppId);
EXPECT_EQ(UNREGISTRATION_COMPLETED, last_event());
@@ -698,7 +719,7 @@ TEST_F(GCMClientImplTest, UnregisterApp) {
TEST_F(GCMClientImplTest, DeletePendingRequestsWhenStopping) {
std::vector<std::string> senders;
senders.push_back("sender");
- gcm_client()->Register(kAppId, senders);
+ Register(kAppId, senders);
gcm_client()->Stop();
VerifyPendingRequestFetcherDeleted();
@@ -1148,7 +1169,7 @@ TEST_F(GCMClientImplStartAndStopTest, DelayStart) {
// Registration.
std::vector<std::string> senders;
senders.push_back("sender");
- gcm_client()->Register(kAppId, senders);
+ Register(kAppId, senders);
CompleteRegistration("reg_id");
EXPECT_EQ(GCMClientImpl::READY, gcm_client_state());
diff --git a/components/gcm_driver/gcm_driver.cc b/components/gcm_driver/gcm_driver.cc
index 1b115c0..10adbae 100644
--- a/components/gcm_driver/gcm_driver.cc
+++ b/components/gcm_driver/gcm_driver.cc
@@ -12,10 +12,14 @@
namespace gcm {
-InstanceIDStore::InstanceIDStore() {
+namespace {
+const size_t kMaxSenders = 100;
+} // namespace
+
+InstanceIDHandler::InstanceIDHandler() {
}
-InstanceIDStore::~InstanceIDStore() {
+InstanceIDHandler::~InstanceIDHandler() {
}
GCMDriver::GCMDriver() : weak_ptr_factory_(this) {
@@ -28,7 +32,7 @@ void GCMDriver::Register(const std::string& app_id,
const std::vector<std::string>& sender_ids,
const RegisterCallback& callback) {
DCHECK(!app_id.empty());
- DCHECK(!sender_ids.empty());
+ DCHECK(!sender_ids.empty() && sender_ids.size() <= kMaxSenders);
DCHECK(!callback.is_null());
GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
diff --git a/components/gcm_driver/gcm_driver.h b/components/gcm_driver/gcm_driver.h
index caae284..689d721 100644
--- a/components/gcm_driver/gcm_driver.h
+++ b/components/gcm_driver/gcm_driver.h
@@ -22,24 +22,41 @@ class GCMAppHandler;
class GCMConnectionObserver;
struct AccountMapping;
-// Provides the capability to set/get InstanceID data in the GCM store.
-class InstanceIDStore {
+// Provides the InstanceID support via GCMDriver.
+class InstanceIDHandler {
public:
- typedef base::Callback<void(const std::string& instance_id_data)>
+ typedef base::Callback<void(const std::string& token,
+ GCMClient::Result result)> GetTokenCallback;
+ typedef base::Callback<void(GCMClient::Result result)> DeleteTokenCallback;
+ typedef base::Callback<void(const std::string& instance_id,
+ const std::string& extra_data)>
GetInstanceIDDataCallback;
- InstanceIDStore();
- virtual ~InstanceIDStore();
-
+ InstanceIDHandler();
+ virtual ~InstanceIDHandler();
+
+ // Token service.
+ virtual void GetToken(const std::string& app_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const std::map<std::string, std::string>& options,
+ const GetTokenCallback& callback) = 0;
+ virtual void DeleteToken(const std::string& app_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const DeleteTokenCallback& callback) = 0;
+
+ // Persistence support.
virtual void AddInstanceIDData(const std::string& app_id,
- const std::string& instance_id_data) = 0;
+ const std::string& instance_id,
+ const std::string& extra_data) = 0;
virtual void RemoveInstanceIDData(const std::string& app_id) = 0;
virtual void GetInstanceIDData(
const std::string& app_id,
const GetInstanceIDDataCallback& callback) = 0;
private:
- DISALLOW_COPY_AND_ASSIGN(InstanceIDStore);
+ DISALLOW_COPY_AND_ASSIGN(InstanceIDHandler);
};
// Bridge between GCM users in Chrome and the platform-specific implementation.
@@ -166,8 +183,8 @@ class GCMDriver {
// to send a heartbeat message.
virtual void WakeFromSuspendForHeartbeat(bool wake) = 0;
- // Supports saving the Instance ID data in the GCM store.
- virtual InstanceIDStore* GetInstanceIDStore() = 0;
+ // Supports InstanceID handling.
+ virtual InstanceIDHandler* GetInstanceIDHandler() = 0;
// Adds or removes a custom client requested heartbeat interval. If multiple
// components set that setting, the lowest setting will be used. If the
diff --git a/components/gcm_driver/gcm_driver_android.cc b/components/gcm_driver/gcm_driver_android.cc
index b5960fc..6f8dd59 100644
--- a/components/gcm_driver/gcm_driver_android.cc
+++ b/components/gcm_driver/gcm_driver_android.cc
@@ -162,7 +162,7 @@ void GCMDriverAndroid::SetLastTokenFetchTime(const base::Time& time) {
void GCMDriverAndroid::WakeFromSuspendForHeartbeat(bool wake) {
}
-InstanceIDStore* GCMDriverAndroid::GetInstanceIDStore() {
+InstanceIDHandler* GCMDriverAndroid::GetInstanceIDHandler() {
// Not supported for Android.
return NULL;
}
diff --git a/components/gcm_driver/gcm_driver_android.h b/components/gcm_driver/gcm_driver_android.h
index 205fb6e..2dd0e70 100644
--- a/components/gcm_driver/gcm_driver_android.h
+++ b/components/gcm_driver/gcm_driver_android.h
@@ -64,7 +64,7 @@ class GCMDriverAndroid : public GCMDriver {
base::Time GetLastTokenFetchTime() override;
void SetLastTokenFetchTime(const base::Time& time) override;
void WakeFromSuspendForHeartbeat(bool wake) override;
- InstanceIDStore* GetInstanceIDStore() override;
+ InstanceIDHandler* GetInstanceIDHandler() override;
void AddHeartbeatInterval(const std::string& scope, int interval_ms) override;
void RemoveHeartbeatInterval(const std::string& scope) override;
diff --git a/components/gcm_driver/gcm_driver_desktop.cc b/components/gcm_driver/gcm_driver_desktop.cc
index dcc5cb2..958ec13 100644
--- a/components/gcm_driver/gcm_driver_desktop.cc
+++ b/components/gcm_driver/gcm_driver_desktop.cc
@@ -20,6 +20,7 @@
#include "components/gcm_driver/gcm_channel_status_syncer.h"
#include "components/gcm_driver/gcm_client_factory.h"
#include "components/gcm_driver/gcm_delayed_task_controller.h"
+#include "components/gcm_driver/instance_id/instance_id_impl.h"
#include "components/gcm_driver/system_encryptor.h"
#include "google_apis/gcm/engine/account_mapping.h"
#include "net/base/ip_endpoint.h"
@@ -40,11 +41,12 @@ class GCMDriverDesktop::IOWorker : public GCMClient::Delegate {
// Overridden from GCMClient::Delegate:
// Called on IO thread.
- void OnRegisterFinished(const std::string& app_id,
+ void OnRegisterFinished(const linked_ptr<RegistrationInfo>& registration_info,
const std::string& registration_id,
GCMClient::Result result) override;
- void OnUnregisterFinished(const std::string& app_id,
- GCMClient::Result result) override;
+ void OnUnregisterFinished(
+ const linked_ptr<RegistrationInfo>& registration_info,
+ GCMClient::Result result) override;
void OnSendFinished(const std::string& app_id,
const std::string& message_id,
GCMClient::Result result) override;
@@ -87,12 +89,21 @@ class GCMDriverDesktop::IOWorker : public GCMClient::Delegate {
void RemoveAccountMapping(const std::string& account_id);
void SetLastTokenFetchTime(const base::Time& time);
void WakeFromSuspendForHeartbeat(bool wake);
+ void AddHeartbeatInterval(const std::string& scope, int interval_ms);
+ void RemoveHeartbeatInterval(const std::string& scope);
+
void AddInstanceIDData(const std::string& app_id,
- const std::string& instance_id_data);
+ const std::string& instance_id,
+ const std::string& extra_data);
void RemoveInstanceIDData(const std::string& app_id);
void GetInstanceIDData(const std::string& app_id);
- void AddHeartbeatInterval(const std::string& scope, int interval_ms);
- void RemoveHeartbeatInterval(const std::string& scope);
+ void GetToken(const std::string& app_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const std::map<std::string, std::string>& options);
+ void DeleteToken(const std::string& app_id,
+ const std::string& authorized_entity,
+ const std::string& scope);
// For testing purpose. Can be called from UI thread. Use with care.
GCMClient* gcm_client_for_testing() const { return gcm_client_.get(); }
@@ -143,27 +154,66 @@ void GCMDriverDesktop::IOWorker::Initialize(
}
void GCMDriverDesktop::IOWorker::OnRegisterFinished(
- const std::string& app_id,
+ const linked_ptr<RegistrationInfo>& registration_info,
const std::string& registration_id,
GCMClient::Result result) {
DCHECK(io_thread_->RunsTasksOnCurrentThread());
- ui_thread_->PostTask(
+ const GCMRegistrationInfo* gcm_registration_info =
+ GCMRegistrationInfo::FromRegistrationInfo(registration_info.get());
+ if (gcm_registration_info) {
+ ui_thread_->PostTask(
+ FROM_HERE,
+ base::Bind(&GCMDriverDesktop::RegisterFinished,
+ service_,
+ gcm_registration_info->app_id,
+ registration_id,
+ result));
+ }
+
+ const InstanceIDTokenInfo* instance_id_token_info =
+ InstanceIDTokenInfo::FromRegistrationInfo(registration_info.get());
+ if (instance_id_token_info) {
+ ui_thread_->PostTask(
FROM_HERE,
- base::Bind(&GCMDriverDesktop::RegisterFinished, service_, app_id,
- registration_id, result));
+ base::Bind(&GCMDriverDesktop::GetTokenFinished,
+ service_,
+ instance_id_token_info->app_id,
+ instance_id_token_info->authorized_entity,
+ instance_id_token_info->scope,
+ registration_id,
+ result));
+ }
}
void GCMDriverDesktop::IOWorker::OnUnregisterFinished(
- const std::string& app_id,
+ const linked_ptr<RegistrationInfo>& registration_info,
GCMClient::Result result) {
DCHECK(io_thread_->RunsTasksOnCurrentThread());
- ui_thread_->PostTask(FROM_HERE,
- base::Bind(&GCMDriverDesktop::UnregisterFinished,
- service_,
- app_id,
- result));
+ const GCMRegistrationInfo* gcm_registration_info =
+ GCMRegistrationInfo::FromRegistrationInfo(registration_info.get());
+ if (gcm_registration_info) {
+ ui_thread_->PostTask(
+ FROM_HERE,
+ base::Bind(&GCMDriverDesktop::UnregisterFinished,
+ service_,
+ gcm_registration_info->app_id,
+ result));
+ }
+
+ const InstanceIDTokenInfo* instance_id_token_info =
+ InstanceIDTokenInfo::FromRegistrationInfo(registration_info.get());
+ if (instance_id_token_info) {
+ ui_thread_->PostTask(
+ FROM_HERE,
+ base::Bind(&GCMDriverDesktop::DeleteTokenFinished,
+ service_,
+ instance_id_token_info->app_id,
+ instance_id_token_info->authorized_entity,
+ instance_id_token_info->scope,
+ result));
+ }
}
void GCMDriverDesktop::IOWorker::OnSendFinished(const std::string& app_id,
@@ -270,13 +320,19 @@ void GCMDriverDesktop::IOWorker::Register(
const std::vector<std::string>& sender_ids) {
DCHECK(io_thread_->RunsTasksOnCurrentThread());
- gcm_client_->Register(app_id, sender_ids);
+ scoped_ptr<GCMRegistrationInfo> gcm_info(new GCMRegistrationInfo);
+ gcm_info->app_id = app_id;
+ gcm_info->sender_ids = sender_ids;
+ gcm_client_->Register(make_linked_ptr<RegistrationInfo>(gcm_info.release()));
}
void GCMDriverDesktop::IOWorker::Unregister(const std::string& app_id) {
DCHECK(io_thread_->RunsTasksOnCurrentThread());
- gcm_client_->Unregister(app_id);
+ scoped_ptr<GCMRegistrationInfo> gcm_info(new GCMRegistrationInfo);
+ gcm_info->app_id = app_id;
+ gcm_client_->Unregister(
+ make_linked_ptr<RegistrationInfo>(gcm_info.release()));
}
void GCMDriverDesktop::IOWorker::Send(
@@ -351,11 +407,12 @@ void GCMDriverDesktop::IOWorker::SetLastTokenFetchTime(const base::Time& time) {
void GCMDriverDesktop::IOWorker::AddInstanceIDData(
const std::string& app_id,
- const std::string& instance_id_data) {
+ const std::string& instance_id,
+ const std::string& extra_data) {
DCHECK(io_thread_->RunsTasksOnCurrentThread());
if (gcm_client_.get())
- gcm_client_->AddInstanceIDData(app_id, instance_id_data);
+ gcm_client_->AddInstanceIDData(app_id, instance_id, extra_data);
}
void GCMDriverDesktop::IOWorker::RemoveInstanceIDData(
@@ -370,14 +427,45 @@ void GCMDriverDesktop::IOWorker::GetInstanceIDData(
const std::string& app_id) {
DCHECK(io_thread_->RunsTasksOnCurrentThread());
- std::string instance_id_data;
+ std::string instance_id;
+ std::string extra_data;
if (gcm_client_.get())
- instance_id_data = gcm_client_->GetInstanceIDData(app_id);
+ gcm_client_->GetInstanceIDData(app_id, &instance_id, &extra_data);
ui_thread_->PostTask(
FROM_HERE,
base::Bind(&GCMDriverDesktop::GetInstanceIDDataFinished,
- service_, app_id, instance_id_data));
+ service_, app_id, instance_id, extra_data));
+}
+
+void GCMDriverDesktop::IOWorker::GetToken(
+ const std::string& app_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const std::map<std::string, std::string>& options) {
+ DCHECK(io_thread_->RunsTasksOnCurrentThread());
+
+ scoped_ptr<InstanceIDTokenInfo> instance_id_token_info(
+ new InstanceIDTokenInfo);
+ instance_id_token_info->app_id = app_id;
+ instance_id_token_info->authorized_entity = authorized_entity;
+ instance_id_token_info->scope = scope;
+ instance_id_token_info->options = options;
+ gcm_client_->Register(
+ make_linked_ptr<RegistrationInfo>(instance_id_token_info.release()));
+}
+
+void GCMDriverDesktop::IOWorker::DeleteToken(
+ const std::string& app_id,
+ const std::string& authorized_entity,
+ const std::string& scope) {
+ scoped_ptr<InstanceIDTokenInfo> instance_id_token_info(
+ new InstanceIDTokenInfo);
+ instance_id_token_info->app_id = app_id;
+ instance_id_token_info->authorized_entity = authorized_entity;
+ instance_id_token_info->scope = scope;
+ gcm_client_->Unregister(
+ make_linked_ptr<RegistrationInfo>(instance_id_token_info.release()));
}
void GCMDriverDesktop::IOWorker::WakeFromSuspendForHeartbeat(bool wake) {
@@ -708,13 +796,84 @@ void GCMDriverDesktop::SetLastTokenFetchTime(const base::Time& time) {
time));
}
-InstanceIDStore* GCMDriverDesktop::GetInstanceIDStore() {
+InstanceIDHandler* GCMDriverDesktop::GetInstanceIDHandler() {
return this;
}
+void GCMDriverDesktop::GetToken(
+ const std::string& app_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const std::map<std::string, std::string>& options,
+ const GetTokenCallback& callback) {
+ DCHECK(!app_id.empty());
+ DCHECK(!authorized_entity.empty());
+ DCHECK(!scope.empty());
+ DCHECK(!callback.is_null());
+
+ GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
+ if (result != GCMClient::SUCCESS) {
+ callback.Run(std::string(), result);
+ return;
+ }
+
+ // If previous GetToken operation is still in progress, bail out.
+ TokenTuple tuple_key(app_id, authorized_entity, scope);
+ if (get_token_callbacks_.find(tuple_key) != get_token_callbacks_.end()) {
+ callback.Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING);
+ return;
+ }
+
+ get_token_callbacks_[tuple_key] = callback;
+
+ io_thread_->PostTask(
+ FROM_HERE,
+ base::Bind(&GCMDriverDesktop::IOWorker::GetToken,
+ base::Unretained(io_worker_.get()),
+ app_id,
+ authorized_entity,
+ scope,
+ options));
+}
+
+void GCMDriverDesktop::DeleteToken(const std::string& app_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const DeleteTokenCallback& callback) {
+ DCHECK(!app_id.empty());
+ DCHECK(!authorized_entity.empty());
+ DCHECK(!scope.empty());
+ DCHECK(!callback.is_null());
+
+ GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
+ if (result != GCMClient::SUCCESS) {
+ callback.Run(result);
+ return;
+ }
+
+ // If previous GetToken operation is still in progress, bail out.
+ TokenTuple tuple_key(app_id, authorized_entity, scope);
+ if (delete_token_callbacks_.find(tuple_key) !=
+ delete_token_callbacks_.end()) {
+ callback.Run(GCMClient::ASYNC_OPERATION_PENDING);
+ return;
+ }
+
+ delete_token_callbacks_[tuple_key] = callback;
+
+ io_thread_->PostTask(
+ FROM_HERE,
+ base::Bind(&GCMDriverDesktop::IOWorker::DeleteToken,
+ base::Unretained(io_worker_.get()),
+ app_id,
+ authorized_entity,
+ scope));
+}
+
void GCMDriverDesktop::AddInstanceIDData(
const std::string& app_id,
- const std::string& instance_id_data) {
+ const std::string& instance_id,
+ const std::string& extra_data) {
DCHECK(ui_thread_->RunsTasksOnCurrentThread());
io_thread_->PostTask(
@@ -722,7 +881,8 @@ void GCMDriverDesktop::AddInstanceIDData(
base::Bind(&GCMDriverDesktop::IOWorker::AddInstanceIDData,
base::Unretained(io_worker_.get()),
app_id,
- instance_id_data));
+ instance_id,
+ extra_data));
}
void GCMDriverDesktop::RemoveInstanceIDData(const std::string& app_id) {
@@ -749,12 +909,46 @@ void GCMDriverDesktop::GetInstanceIDData(
void GCMDriverDesktop::GetInstanceIDDataFinished(
const std::string& app_id,
- const std::string& instance_id_data) {
+ const std::string& instance_id,
+ const std::string& extra_data) {
DCHECK(get_instance_id_data_callbacks_.count(app_id));
- get_instance_id_data_callbacks_[app_id].Run(instance_id_data);
+ get_instance_id_data_callbacks_[app_id].Run(instance_id, extra_data);
get_instance_id_data_callbacks_.erase(app_id);
}
+void GCMDriverDesktop::GetTokenFinished(const std::string& app_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const std::string& token,
+ GCMClient::Result result) {
+ TokenTuple tuple_key(app_id, authorized_entity, scope);
+ auto callback_iter = get_token_callbacks_.find(tuple_key);
+ if (callback_iter == get_token_callbacks_.end()) {
+ // The callback could have been removed when the app is uninstalled.
+ return;
+ }
+
+ GetTokenCallback callback = callback_iter->second;
+ get_token_callbacks_.erase(callback_iter);
+ callback.Run(token, result);
+}
+
+void GCMDriverDesktop::DeleteTokenFinished(const std::string& app_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ GCMClient::Result result) {
+ TokenTuple tuple_key(app_id, authorized_entity, scope);
+ auto callback_iter = delete_token_callbacks_.find(tuple_key);
+ if (callback_iter == delete_token_callbacks_.end()) {
+ // The callback could have been removed when the app is uninstalled.
+ return;
+ }
+
+ DeleteTokenCallback callback = callback_iter->second;
+ delete_token_callbacks_.erase(callback_iter);
+ callback.Run(result);
+}
+
void GCMDriverDesktop::WakeFromSuspendForHeartbeat(bool wake) {
DCHECK(ui_thread_->RunsTasksOnCurrentThread());
@@ -986,4 +1180,19 @@ void GCMDriverDesktop::GetGCMStatisticsFinished(
LOG(WARNING) << "request_gcm_statistics_callback_ is NULL.";
}
+bool GCMDriverDesktop::TokenTupleComparer::operator()(
+ const TokenTuple& a, const TokenTuple& b) const {
+ if (get<0>(a) < get<0>(b))
+ return true;
+ if (get<0>(a) > get<0>(b))
+ return false;
+
+ if (get<1>(a) < get<1>(b))
+ return true;
+ if (get<1>(a) > get<1>(b))
+ return false;
+
+ return get<2>(a) < get<2>(b);
+}
+
} // namespace gcm
diff --git a/components/gcm_driver/gcm_driver_desktop.h b/components/gcm_driver/gcm_driver_desktop.h
index 3206a91..eba1be1 100644
--- a/components/gcm_driver/gcm_driver_desktop.h
+++ b/components/gcm_driver/gcm_driver_desktop.h
@@ -15,6 +15,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
+#include "base/tuple.h"
#include "components/gcm_driver/gcm_channel_status_syncer.h"
#include "components/gcm_driver/gcm_client.h"
#include "components/gcm_driver/gcm_connection_observer.h"
@@ -44,7 +45,7 @@ class GCMDelayedTaskController;
// GCMDriver implementation for desktop and Chrome OS, using GCMClient.
class GCMDriverDesktop : public GCMDriver,
- public InstanceIDStore {
+ public InstanceIDHandler {
public:
GCMDriverDesktop(
scoped_ptr<GCMClientFactory> gcm_client_factory,
@@ -84,13 +85,23 @@ class GCMDriverDesktop : public GCMDriver,
base::Time GetLastTokenFetchTime() override;
void SetLastTokenFetchTime(const base::Time& time) override;
void WakeFromSuspendForHeartbeat(bool wake) override;
- InstanceIDStore* GetInstanceIDStore() override;
+ InstanceIDHandler* GetInstanceIDHandler() override;
void AddHeartbeatInterval(const std::string& scope, int interval_ms) override;
void RemoveHeartbeatInterval(const std::string& scope) override;
- // InstanceIDStore overrides:
+ // InstanceIDHandler overrides:
+ void GetToken(const std::string& app_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const std::map<std::string, std::string>& options,
+ const GetTokenCallback& callback) override;
+ void DeleteToken(const std::string& app_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const DeleteTokenCallback& callback) override;
void AddInstanceIDData(const std::string& app_id,
- const std::string& instance_id_data) override;
+ const std::string& instance_id,
+ const std::string& extra_data) override;
void RemoveInstanceIDData(const std::string& app_id) override;
void GetInstanceIDData(const std::string& app_id,
const GetInstanceIDDataCallback& callback) override;
@@ -114,6 +125,11 @@ class GCMDriverDesktop : public GCMDriver,
private:
class IOWorker;
+ typedef Tuple<std::string, std::string, std::string> TokenTuple;
+ struct TokenTupleComparer {
+ bool operator()(const TokenTuple& a, const TokenTuple& b) const;
+ };
+
// Stops the GCM service. It can be restarted by calling EnsureStarted again.
void Stop();
@@ -142,7 +158,17 @@ class GCMDriverDesktop : public GCMDriver,
void GetGCMStatisticsFinished(const GCMClient::GCMStatistics& stats);
void GetInstanceIDDataFinished(const std::string& app_id,
- const std::string& instance_id_data);
+ const std::string& instance_id,
+ const std::string& extra_data);
+ void GetTokenFinished(const std::string& app_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const std::string& token,
+ GCMClient::Result result);
+ void DeleteTokenFinished(const std::string& app_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ GCMClient::Result result);
scoped_ptr<GCMChannelStatusSyncer> gcm_channel_status_syncer_;
@@ -189,6 +215,12 @@ class GCMDriverDesktop : public GCMDriver,
std::map<std::string, GetInstanceIDDataCallback>
get_instance_id_data_callbacks_;
+ // Callbacks for GetToken/DeleteToken.
+ std::map<TokenTuple, GetTokenCallback, TokenTupleComparer>
+ get_token_callbacks_;
+ std::map<TokenTuple, DeleteTokenCallback, TokenTupleComparer>
+ delete_token_callbacks_;
+
// Used to pass a weak pointer to the IO worker.
base::WeakPtrFactory<GCMDriverDesktop> weak_ptr_factory_;
diff --git a/components/gcm_driver/gcm_stats_recorder_impl.cc b/components/gcm_driver/gcm_stats_recorder_impl.cc
index 524372d..6bf6963 100644
--- a/components/gcm_driver/gcm_stats_recorder_impl.cc
+++ b/components/gcm_driver/gcm_stats_recorder_impl.cc
@@ -272,14 +272,14 @@ void GCMStatsRecorderImpl::RecordConnectionResetSignaled(
void GCMStatsRecorderImpl::RecordRegistration(
const std::string& app_id,
- const std::string& sender_ids,
+ const std::string& senders,
const std::string& event,
const std::string& details) {
RegistrationActivity data;
RegistrationActivity* inserted_data = InsertCircularBuffer(
&registration_activities_, data);
inserted_data->app_id = app_id;
- inserted_data->sender_ids = sender_ids;
+ inserted_data->sender_ids = senders;
inserted_data->event = event;
inserted_data->details = details;
NotifyActivityRecorded();
@@ -297,22 +297,22 @@ void GCMStatsRecorderImpl::RecordRegistrationSent(
void GCMStatsRecorderImpl::RecordRegistrationResponse(
const std::string& app_id,
- const std::vector<std::string>& sender_ids,
+ const std::string& senders,
RegistrationRequest::Status status) {
if (!is_recording_)
return;
- RecordRegistration(app_id, JoinString(sender_ids, ","),
+ RecordRegistration(app_id, senders,
"Registration response received",
GetRegistrationStatusString(status));
}
void GCMStatsRecorderImpl::RecordRegistrationRetryRequested(
const std::string& app_id,
- const std::vector<std::string>& sender_ids,
+ const std::string& senders,
int retries_left) {
if (!is_recording_)
return;
- RecordRegistration(app_id, JoinString(sender_ids, ","),
+ RecordRegistration(app_id, senders,
"Registration retry requested",
base::StringPrintf("Retries left: %d", retries_left));
}
diff --git a/components/gcm_driver/gcm_stats_recorder_impl.h b/components/gcm_driver/gcm_stats_recorder_impl.h
index a2836be..a8d3e3b 100644
--- a/components/gcm_driver/gcm_stats_recorder_impl.h
+++ b/components/gcm_driver/gcm_stats_recorder_impl.h
@@ -55,13 +55,13 @@ class GCMStatsRecorderImpl : public GCMStatsRecorder {
void RecordConnectionResetSignaled(
ConnectionFactory::ConnectionResetReason reason) override;
void RecordRegistrationSent(const std::string& app_id,
- const std::string& sender_ids) override;
+ const std::string& senders) override;
void RecordRegistrationResponse(const std::string& app_id,
- const std::vector<std::string>& sender_ids,
+ const std::string& senders,
RegistrationRequest::Status status) override;
void RecordRegistrationRetryRequested(
const std::string& app_id,
- const std::vector<std::string>& sender_ids,
+ const std::string& senders,
int retries_left) override;
void RecordUnregistrationSent(const std::string& app_id) override;
void RecordUnregistrationResponse(
diff --git a/components/gcm_driver/gcm_stats_recorder_impl_unittest.cc b/components/gcm_driver/gcm_stats_recorder_impl_unittest.cc
index 1223f67..e45ab59 100644
--- a/components/gcm_driver/gcm_stats_recorder_impl_unittest.cc
+++ b/components/gcm_driver/gcm_stats_recorder_impl_unittest.cc
@@ -338,7 +338,7 @@ class GCMStatsRecorderImplTest : public testing::Test {
EXPECT_EQ(details, queue.front().details) << remark;
}
- std::vector<std::string> sender_ids_;
+ std::string sender_ids_;
GCMStatsRecorderImpl recorder_;
};
@@ -348,8 +348,7 @@ GCMStatsRecorderImplTest::GCMStatsRecorderImplTest(){
GCMStatsRecorderImplTest::~GCMStatsRecorderImplTest() {}
void GCMStatsRecorderImplTest::SetUp(){
- sender_ids_.push_back("s1");
- sender_ids_.push_back("s2");
+ sender_ids_ = "s1,s2";
recorder_.SetRecording(true);
}
diff --git a/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.cc b/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.cc
index 2a50a03..6b09da0 100644
--- a/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.cc
+++ b/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.cc
@@ -6,6 +6,9 @@
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
+#include "base/rand_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "components/gcm_driver/gcm_client.h"
namespace instance_id {
@@ -15,14 +18,15 @@ FakeGCMDriverForInstanceID::FakeGCMDriverForInstanceID() {
FakeGCMDriverForInstanceID::~FakeGCMDriverForInstanceID() {
}
-gcm::InstanceIDStore* FakeGCMDriverForInstanceID::GetInstanceIDStore() {
+gcm::InstanceIDHandler* FakeGCMDriverForInstanceID::GetInstanceIDHandler() {
return this;
}
void FakeGCMDriverForInstanceID::AddInstanceIDData(
const std::string& app_id,
- const std::string& instance_id_data) {
- instance_id_data_[app_id] = instance_id_data;
+ const std::string& instance_id,
+ const std::string& extra_data) {
+ instance_id_data_[app_id] = std::make_pair(instance_id, extra_data);
}
void FakeGCMDriverForInstanceID::RemoveInstanceIDData(
@@ -32,14 +36,50 @@ void FakeGCMDriverForInstanceID::RemoveInstanceIDData(
void FakeGCMDriverForInstanceID::GetInstanceIDData(
const std::string& app_id,
- const gcm::InstanceIDStore::GetInstanceIDDataCallback& callback) {
- std::string data;
+ const GetInstanceIDDataCallback& callback) {
auto iter = instance_id_data_.find(app_id);
- if (iter != instance_id_data_.end())
- data = iter->second;
+ std::string instance_id;
+ std::string extra_data;
+ if (iter != instance_id_data_.end()) {
+ instance_id = iter->second.first;
+ extra_data = iter->second.second;
+ }
base::MessageLoop::current()->PostTask(
FROM_HERE,
- base::Bind(callback, data));
+ base::Bind(callback, instance_id, extra_data));
+}
+
+void FakeGCMDriverForInstanceID::GetToken(
+ const std::string& app_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const std::map<std::string, std::string>& options,
+ const GetTokenCallback& callback) {
+ std::string token;
+ std::string key = app_id + authorized_entity + scope;
+ auto iter = tokens_.find(key);
+ if (iter != tokens_.end()) {
+ token = iter->second;
+ } else {
+ token = base::Uint64ToString(base::RandUint64());
+ tokens_[key] = token;
+ }
+
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, token, gcm::GCMClient::SUCCESS));
+}
+
+void FakeGCMDriverForInstanceID::DeleteToken(
+ const std::string& app_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const DeleteTokenCallback& callback) {
+ std::string key = app_id + authorized_entity + scope;
+ tokens_.erase(key);
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, gcm::GCMClient::SUCCESS));
}
} // namespace instance_id
diff --git a/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h b/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h
index d5f9dd1..9d6b77a 100644
--- a/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h
+++ b/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h
@@ -7,6 +7,7 @@
#include <map>
#include <string>
+#include <utility>
#include "base/compiler_specific.h"
#include "base/macros.h"
@@ -15,24 +16,35 @@
namespace instance_id {
class FakeGCMDriverForInstanceID : public gcm::FakeGCMDriver,
- public gcm::InstanceIDStore {
+ public gcm::InstanceIDHandler {
public:
FakeGCMDriverForInstanceID();
~FakeGCMDriverForInstanceID() override;
// FakeGCMDriver overrides:
- gcm::InstanceIDStore* GetInstanceIDStore() override;
-
- // InstanceIDStore overrides:
+ gcm::InstanceIDHandler* GetInstanceIDHandler() override;
+
+ // InstanceIDHandler overrides:
+ void GetToken(const std::string& app_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const std::map<std::string, std::string>& options,
+ const GetTokenCallback& callback) override;
+ void DeleteToken(const std::string& app_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const DeleteTokenCallback& callback) override;
void AddInstanceIDData(const std::string& app_id,
- const std::string& instance_id_data) override;
+ const std::string& instance_id,
+ const std::string& extra_data) override;
void RemoveInstanceIDData(const std::string& app_id) override;
void GetInstanceIDData(
const std::string& app_id,
- const gcm::InstanceIDStore::GetInstanceIDDataCallback& callback) override;
+ const GetInstanceIDDataCallback& callback) override;
private:
- std::map<std::string, std::string> instance_id_data_;
+ std::map<std::string, std::pair<std::string, std::string>> instance_id_data_;
+ std::map<std::string, std::string> tokens_;
DISALLOW_COPY_AND_ASSIGN(FakeGCMDriverForInstanceID);
};
diff --git a/components/gcm_driver/instance_id/instance_id.h b/components/gcm_driver/instance_id/instance_id.h
index 8141a3a..343b9c5 100644
--- a/components/gcm_driver/instance_id/instance_id.h
+++ b/components/gcm_driver/instance_id/instance_id.h
@@ -30,6 +30,8 @@ class InstanceID {
INVALID_PARAMETER,
// Instance ID is disabled.
DISABLED,
+ // Previous asynchronous operation is still pending to finish.
+ ASYNC_OPERATION_PENDING,
// Network socket error.
NETWORK_ERROR,
// Problem at the server.
diff --git a/components/gcm_driver/instance_id/instance_id_driver_unittest.cc b/components/gcm_driver/instance_id/instance_id_driver_unittest.cc
index 41305b5..5e79331 100644
--- a/components/gcm_driver/instance_id/instance_id_driver_unittest.cc
+++ b/components/gcm_driver/instance_id/instance_id_driver_unittest.cc
@@ -19,6 +19,10 @@ namespace {
const char kTestAppID1[] = "TestApp1";
const char kTestAppID2[] = "TestApp2";
+const char kAuthorizedEntity1[] = "Sender 1";
+const char kAuthorizedEntity2[] = "Sender 2";
+const char kScope1[] = "GCM1";
+const char kScope2[] = "FooBar";
bool VerifyInstanceID(const std::string& str) {
// Checks the length.
@@ -53,6 +57,15 @@ class InstanceIDDriverTest : public testing::Test {
std::string GetID(InstanceID* instance_id);
base::Time GetCreationTime(InstanceID* instance_id);
InstanceID::Result DeleteID(InstanceID* instance_id);
+ std::string GetToken(
+ InstanceID* instance_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const std::map<std::string, std::string>& options);
+ InstanceID::Result DeleteToken(
+ InstanceID* instance_id,
+ const std::string& authorized_entity,
+ const std::string& scope);
InstanceIDDriver* driver() const { return driver_.get(); }
@@ -60,6 +73,8 @@ class InstanceIDDriverTest : public testing::Test {
void GetIDCompleted(const std::string& id);
void GetCreationTimeCompleted(const base::Time& creation_time);
void DeleteIDCompleted(InstanceID::Result result);
+ void GetTokenCompleted(const std::string& token, InstanceID::Result result);
+ void DeleteTokenCompleted(InstanceID::Result result);
base::MessageLoopForUI message_loop_;
scoped_ptr<FakeGCMDriverForInstanceID> gcm_driver_;
@@ -67,6 +82,7 @@ class InstanceIDDriverTest : public testing::Test {
std::string id_;
base::Time creation_time_;
+ std::string token_;
InstanceID::Result result_;
bool async_operation_completed_;
@@ -129,7 +145,41 @@ InstanceID::Result InstanceIDDriverTest::DeleteID(InstanceID* instance_id) {
return result_;
}
+std::string InstanceIDDriverTest::GetToken(
+ InstanceID* instance_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const std::map<std::string, std::string>& options) {
+ async_operation_completed_ = false;
+ token_.clear();
+ result_ = InstanceID::UNKNOWN_ERROR;;
+ instance_id->GetToken(
+ authorized_entity,
+ scope,
+ options,
+ base::Bind(&InstanceIDDriverTest::GetTokenCompleted,
+ base::Unretained(this)));
+ WaitForAsyncOperation();
+ return token_;
+}
+
+InstanceID::Result InstanceIDDriverTest::DeleteToken(
+ InstanceID* instance_id,
+ const std::string& authorized_entity,
+ const std::string& scope) {
+ async_operation_completed_ = false;
+ result_ = InstanceID::UNKNOWN_ERROR;;
+ instance_id->DeleteToken(
+ authorized_entity,
+ scope,
+ base::Bind(&InstanceIDDriverTest::DeleteTokenCompleted,
+ base::Unretained(this)));
+ WaitForAsyncOperation();
+ return result_;
+}
+
void InstanceIDDriverTest::GetIDCompleted(const std::string& id) {
+ DCHECK(!async_operation_completed_);
async_operation_completed_ = true;
id_ = id;
if (!async_operation_completed_callback_.is_null())
@@ -138,6 +188,7 @@ void InstanceIDDriverTest::GetIDCompleted(const std::string& id) {
void InstanceIDDriverTest::GetCreationTimeCompleted(
const base::Time& creation_time) {
+ DCHECK(!async_operation_completed_);
async_operation_completed_ = true;
creation_time_ = creation_time;
if (!async_operation_completed_callback_.is_null())
@@ -145,6 +196,25 @@ void InstanceIDDriverTest::GetCreationTimeCompleted(
}
void InstanceIDDriverTest::DeleteIDCompleted(InstanceID::Result result) {
+ DCHECK(!async_operation_completed_);
+ async_operation_completed_ = true;
+ result_ = result;
+ if (!async_operation_completed_callback_.is_null())
+ async_operation_completed_callback_.Run();
+}
+
+void InstanceIDDriverTest::GetTokenCompleted(
+ const std::string& token, InstanceID::Result result){
+ DCHECK(!async_operation_completed_);
+ async_operation_completed_ = true;
+ token_ = token;
+ result_ = result;
+ if (!async_operation_completed_callback_.is_null())
+ async_operation_completed_callback_.Run();
+}
+
+void InstanceIDDriverTest::DeleteTokenCompleted(InstanceID::Result result) {
+ DCHECK(!async_operation_completed_);
async_operation_completed_ = true;
result_ = result;
if (!async_operation_completed_callback_.is_null())
@@ -220,4 +290,55 @@ TEST_F(InstanceIDDriverTest, DeleteID) {
EXPECT_FALSE(GetCreationTime(instance_id).is_null());
}
+TEST_F(InstanceIDDriverTest, GetToken) {
+ InstanceID* instance_id = driver()->GetInstanceID(kTestAppID1);
+ std::map<std::string, std::string> options;
+ std::string token1 =
+ GetToken(instance_id, kAuthorizedEntity1, kScope1, options);
+ EXPECT_FALSE(token1.empty());
+
+ // Same token is returned for same authorized entity and scope.
+ EXPECT_EQ(token1,
+ GetToken(instance_id, kAuthorizedEntity1, kScope1, options));
+
+ // Different token is returned for different authorized entity or scope.
+ std::string token2 =
+ GetToken(instance_id, kAuthorizedEntity1, kScope2, options);
+ EXPECT_FALSE(token2.empty());
+ EXPECT_NE(token1, token2);
+
+ std::string token3 =
+ GetToken(instance_id, kAuthorizedEntity2, kScope1, options);
+ EXPECT_FALSE(token3.empty());
+ EXPECT_NE(token1, token3);
+ EXPECT_NE(token2, token3);
+}
+
+TEST_F(InstanceIDDriverTest, DeleteToken) {
+ InstanceID* instance_id = driver()->GetInstanceID(kTestAppID1);
+ std::map<std::string, std::string> options;
+
+ // Gets 2 tokens.
+ std::string token1 =
+ GetToken(instance_id, kAuthorizedEntity1, kScope1, options);
+ EXPECT_FALSE(token1.empty());
+ std::string token2 =
+ GetToken(instance_id, kAuthorizedEntity2, kScope1, options);
+ EXPECT_FALSE(token1.empty());
+ EXPECT_NE(token1, token2);
+
+ // Different token is returned for same authorized entity and scope after
+ // deletion.
+ EXPECT_EQ(InstanceID::SUCCESS,
+ DeleteToken(instance_id, kAuthorizedEntity1, kScope1));
+ std::string new_token1 =
+ GetToken(instance_id, kAuthorizedEntity1, kScope2, options);
+ EXPECT_FALSE(new_token1.empty());
+ EXPECT_NE(token1, new_token1);
+
+ // The other token is not affected by the deletion.
+ EXPECT_EQ(token2,
+ GetToken(instance_id, kAuthorizedEntity2, kScope1, options));
+}
+
} // instance_id
diff --git a/components/gcm_driver/instance_id/instance_id_impl.cc b/components/gcm_driver/instance_id/instance_id_impl.cc
index b77cf3f..e9c347e 100644
--- a/components/gcm_driver/instance_id/instance_id_impl.cc
+++ b/components/gcm_driver/instance_id/instance_id_impl.cc
@@ -15,6 +15,34 @@
namespace instance_id {
+namespace {
+
+InstanceID::Result GCMClientResultToInstanceIDResult(
+ gcm::GCMClient::Result result) {
+ switch (result) {
+ case gcm::GCMClient::SUCCESS:
+ return InstanceID::SUCCESS;
+ case gcm::GCMClient::INVALID_PARAMETER:
+ return InstanceID::INVALID_PARAMETER;
+ case gcm::GCMClient::ASYNC_OPERATION_PENDING:
+ return InstanceID::ASYNC_OPERATION_PENDING;
+ case gcm::GCMClient::GCM_DISABLED:
+ return InstanceID::DISABLED;
+ case gcm::GCMClient::NETWORK_ERROR:
+ return InstanceID::NETWORK_ERROR;
+ case gcm::GCMClient::SERVER_ERROR:
+ return InstanceID::SERVER_ERROR;
+ case gcm::GCMClient::UNKNOWN_ERROR:
+ return InstanceID::UNKNOWN_ERROR;
+ default:
+ NOTREACHED() << "Unexpected value of result cannot be converted: "
+ << result;
+ }
+ return InstanceID::UNKNOWN_ERROR;
+}
+
+} // namespace
+
// static
InstanceID* InstanceID::Create(const std::string& app_id,
gcm::GCMDriver* gcm_driver) {
@@ -27,7 +55,7 @@ InstanceIDImpl::InstanceIDImpl(const std::string& app_id,
gcm_driver_(gcm_driver),
load_from_store_(false),
weak_ptr_factory_(this) {
- gcm_driver_->GetInstanceIDStore()->GetInstanceIDData(
+ GetInstanceIDHandler()->GetInstanceIDData(
app_id,
base::Bind(&InstanceIDImpl::GetInstanceIDDataCompleted,
weak_ptr_factory_.GetWeakPtr()));
@@ -75,32 +103,148 @@ void InstanceIDImpl::GetToken(
const std::string& scope,
const std::map<std::string, std::string>& options,
const GetTokenCallback& callback) {
- NOTIMPLEMENTED();
+ if (!delayed_task_controller_.CanRunTaskWithoutDelay()) {
+ delayed_task_controller_.AddTask(
+ base::Bind(&InstanceIDImpl::DoGetToken,
+ weak_ptr_factory_.GetWeakPtr(),
+ authorized_entity,
+ scope,
+ options,
+ callback));
+ return;
+ }
+
+ DoGetToken(authorized_entity, scope, options, callback);
+}
+
+void InstanceIDImpl::DoGetToken(
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const std::map<std::string, std::string>& options,
+ const GetTokenCallback& callback) {
+ EnsureIDGenerated();
+
+ GetInstanceIDHandler()->GetToken(
+ app_id(),
+ authorized_entity,
+ scope,
+ options,
+ base::Bind(&InstanceIDImpl::OnGetTokenCompleted,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback));
}
void InstanceIDImpl::DeleteToken(const std::string& authorized_entity,
const std::string& scope,
const DeleteTokenCallback& callback) {
- NOTIMPLEMENTED();
+ if (!delayed_task_controller_.CanRunTaskWithoutDelay()) {
+ delayed_task_controller_.AddTask(
+ base::Bind(&InstanceIDImpl::DoDeleteToken,
+ weak_ptr_factory_.GetWeakPtr(),
+ authorized_entity,
+ scope,
+ callback));
+ return;
+ }
+
+ DoDeleteToken(authorized_entity, scope, callback);
+}
+
+void InstanceIDImpl::DoDeleteToken(
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const DeleteTokenCallback& callback) {
+ // Nothing to delete if the ID has not been generated.
+ if (id_.empty()) {
+ callback.Run(InstanceID::SUCCESS);
+ return;
+ }
+
+ GetInstanceIDHandler()->DeleteToken(
+ app_id(),
+ authorized_entity,
+ scope,
+ base::Bind(&InstanceIDImpl::OnDeleteTokenCompleted,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback));
}
void InstanceIDImpl::DeleteID(const DeleteIDCallback& callback) {
- gcm_driver_->GetInstanceIDStore()->RemoveInstanceIDData(app_id());
+ if (!delayed_task_controller_.CanRunTaskWithoutDelay()) {
+ delayed_task_controller_.AddTask(
+ base::Bind(&InstanceIDImpl::DoDeleteID,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback));
+ return;
+ }
+
+ DoDeleteID(callback);
+}
+
+void InstanceIDImpl::DoDeleteID(const DeleteIDCallback& callback) {
+ // Nothing to do if ID has not been generated.
+ if (id_.empty()) {
+ callback.Run(InstanceID::SUCCESS);
+ return;
+ }
+
+ GetInstanceIDHandler()->DeleteToken(
+ app_id(),
+ "*",
+ "*",
+ base::Bind(&InstanceIDImpl::OnDeleteIDCompleted,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback));
+
+ GetInstanceIDHandler()->RemoveInstanceIDData(app_id());
id_.clear();
creation_time_ = base::Time();
+}
+
+void InstanceIDImpl::OnGetTokenCompleted(const GetTokenCallback& callback,
+ const std::string& token,
+ gcm::GCMClient::Result result) {
+ callback.Run(token, GCMClientResultToInstanceIDResult(result));
+}
+
+void InstanceIDImpl::OnDeleteTokenCompleted(
+ const DeleteTokenCallback& callback,
+ gcm::GCMClient::Result result) {
+ callback.Run(GCMClientResultToInstanceIDResult(result));
+}
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(callback, InstanceID::SUCCESS));
+void InstanceIDImpl::OnDeleteIDCompleted(
+ const DeleteIDCallback& callback,
+ gcm::GCMClient::Result result) {
+ callback.Run(GCMClientResultToInstanceIDResult(result));
}
void InstanceIDImpl::GetInstanceIDDataCompleted(
- const std::string& instance_id_data) {
- Deserialize(instance_id_data);
+ const std::string& instance_id,
+ const std::string& extra_data) {
+ id_ = instance_id;
+
+ if (extra_data.empty()) {
+ creation_time_ = base::Time();
+ } else {
+ int64 time_internal = 0LL;
+ if (!base::StringToInt64(extra_data, &time_internal)) {
+ DVLOG(1) << "Failed to parse the time data: " + extra_data;
+ return;
+ }
+ creation_time_ = base::Time::FromInternalValue(time_internal);
+ }
+
delayed_task_controller_.SetReady();
}
+gcm::InstanceIDHandler* InstanceIDImpl::GetInstanceIDHandler() const {
+ gcm::InstanceIDHandler* handler = gcm_driver_->GetInstanceIDHandler();
+ DCHECK(handler);
+ return handler;
+}
+
void InstanceIDImpl::EnsureIDGenerated() {
if (!id_.empty())
return;
@@ -131,35 +275,10 @@ void InstanceIDImpl::EnsureIDGenerated() {
creation_time_ = base::Time::Now();
// Save to the persistent store.
- gcm_driver_->GetInstanceIDStore()->AddInstanceIDData(
- app_id(), SerializeAsString());
-}
-
-std::string InstanceIDImpl::SerializeAsString() const {
- std::string serialized_data;
- serialized_data += id_;
- serialized_data += ",";
- serialized_data += base::Int64ToString(creation_time_.ToInternalValue());
- return serialized_data;
-}
-
-void InstanceIDImpl::Deserialize(const std::string& serialized_data) {
- if (serialized_data.empty())
- return;
- std::size_t pos = serialized_data.find(',');
- if (pos == std::string::npos) {
- DVLOG(1) << "Failed to deserialize the InstanceID data: " + serialized_data;
- return;
- }
-
- id_ = serialized_data.substr(0, pos);
-
- int64 time_internal = 0LL;
- if (!base::StringToInt64(serialized_data.substr(pos + 1), &time_internal)) {
- DVLOG(1) << "Failed to deserialize the InstanceID data: " + serialized_data;
- return;
- }
- creation_time_ = base::Time::FromInternalValue(time_internal);
+ GetInstanceIDHandler()->AddInstanceIDData(
+ app_id(),
+ id_,
+ base::Int64ToString(creation_time_.ToInternalValue()));
}
} // namespace instance_id
diff --git a/components/gcm_driver/instance_id/instance_id_impl.h b/components/gcm_driver/instance_id/instance_id_impl.h
index a5124c1..8b0d942 100644
--- a/components/gcm_driver/instance_id/instance_id_impl.h
+++ b/components/gcm_driver/instance_id/instance_id_impl.h
@@ -13,11 +13,13 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
+#include "components/gcm_driver/gcm_client.h"
#include "components/gcm_driver/gcm_delayed_task_controller.h"
#include "components/gcm_driver/instance_id/instance_id.h"
namespace gcm {
class GCMDriver;
+class InstanceIDHandler;
} // namespace gcm
namespace instance_id {
@@ -41,15 +43,31 @@ class InstanceIDImpl : public InstanceID {
void DeleteID(const DeleteIDCallback& callback) override;
private:
+ gcm::InstanceIDHandler* GetInstanceIDHandler() const;
+
void EnsureIDGenerated();
- void GetInstanceIDDataCompleted(const std::string& instance_id_data);
+
+ void OnGetTokenCompleted(const GetTokenCallback& callback,
+ const std::string& token,
+ gcm::GCMClient::Result result);
+ void OnDeleteTokenCompleted(const DeleteTokenCallback& callback,
+ gcm::GCMClient::Result result);
+ void OnDeleteIDCompleted(const DeleteIDCallback& callback,
+ gcm::GCMClient::Result result);
+ void GetInstanceIDDataCompleted(const std::string& instance_id,
+ const std::string& extra_data);
void DoGetID(const GetIDCallback& callback);
void DoGetCreationTime(const GetCreationTimeCallback& callback);
-
- // Encodes/decodes the InstanceID data to work with the persistent store.
- std::string SerializeAsString() const;
- void Deserialize(const std::string& serialized_data);
+ void DoGetToken(
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const std::map<std::string, std::string>& options,
+ const GetTokenCallback& callback);
+ void DoDeleteToken(const std::string& authorized_entity,
+ const std::string& scope,
+ const DeleteTokenCallback& callback);
+ void DoDeleteID(const DeleteIDCallback& callback);
gcm::GCMDriver* gcm_driver_; // Not owned.
diff --git a/components/gcm_driver/registration_info.cc b/components/gcm_driver/registration_info.cc
new file mode 100644
index 0000000..31f412d
--- /dev/null
+++ b/components/gcm_driver/registration_info.cc
@@ -0,0 +1,251 @@
+// Copyright 2015 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 "components/gcm_driver/registration_info.h"
+
+#include "base/strings/string_util.h"
+
+namespace gcm {
+
+namespace {
+const char kInsanceIDSerializationPrefix[] = "iid-";
+const int kInsanceIDSerializationPrefixLength =
+ sizeof(kInsanceIDSerializationPrefix) / sizeof(char) - 1;
+} // namespace
+
+// static
+scoped_ptr<RegistrationInfo> RegistrationInfo::BuildFromString(
+ const std::string& serialzied_key,
+ const std::string& serialzied_value,
+ std::string* registration_id) {
+ scoped_ptr<RegistrationInfo> registration;
+
+ if (StartsWithASCII(serialzied_key, kInsanceIDSerializationPrefix, true))
+ registration.reset(new InstanceIDTokenInfo);
+ else
+ registration.reset(new GCMRegistrationInfo);
+
+ if (!registration->Deserialize(serialzied_key,
+ serialzied_value,
+ registration_id)) {
+ registration.reset();
+ }
+ return registration.Pass();
+}
+
+RegistrationInfo::RegistrationInfo() {
+}
+
+RegistrationInfo::~RegistrationInfo() {
+}
+
+// static
+const GCMRegistrationInfo* GCMRegistrationInfo::FromRegistrationInfo(
+ const RegistrationInfo* registration_info) {
+ if (!registration_info || registration_info->GetType() != GCM_REGISTRATION)
+ return NULL;
+ return static_cast<const GCMRegistrationInfo*>(registration_info);
+}
+
+// static
+GCMRegistrationInfo* GCMRegistrationInfo::FromRegistrationInfo(
+ RegistrationInfo* registration_info) {
+ if (!registration_info || registration_info->GetType() != GCM_REGISTRATION)
+ return NULL;
+ return static_cast<GCMRegistrationInfo*>(registration_info);
+}
+
+GCMRegistrationInfo::GCMRegistrationInfo() {
+}
+
+GCMRegistrationInfo::~GCMRegistrationInfo() {
+}
+
+RegistrationInfo::RegistrationType GCMRegistrationInfo::GetType() const {
+ return GCM_REGISTRATION;
+}
+
+std::string GCMRegistrationInfo::GetSerializedKey() const {
+ // Multiple registrations are not supported for legacy GCM. So the key is
+ // purely based on the application id.
+ return app_id;
+}
+
+std::string GCMRegistrationInfo::GetSerializedValue(
+ const std::string& registration_id) const {
+ if (sender_ids.empty() || registration_id.empty())
+ return std::string();
+
+ // Serialize as:
+ // sender1,sender2,...=reg_id
+ std::string value;
+ for (std::vector<std::string>::const_iterator iter = sender_ids.begin();
+ iter != sender_ids.end(); ++iter) {
+ DCHECK(!iter->empty() &&
+ iter->find(',') == std::string::npos &&
+ iter->find('=') == std::string::npos);
+ if (!value.empty())
+ value += ",";
+ value += *iter;
+ }
+
+ value += '=';
+ value += registration_id;
+ return value;
+}
+
+bool GCMRegistrationInfo::Deserialize(
+ const std::string& serialzied_key,
+ const std::string& serialzied_value,
+ std::string* registration_id) {
+ if (serialzied_key.empty() || serialzied_value.empty())
+ return false;
+
+ // Application ID is same as the serialized key.
+ app_id = serialzied_key;
+
+ // Sender IDs and registration ID are constructed from the serialized value.
+ size_t pos = serialzied_value.find('=');
+ if (pos == std::string::npos)
+ return false;
+
+ std::string senders = serialzied_value.substr(0, pos);
+ std::string registration_id_str = serialzied_value.substr(pos + 1);
+
+ Tokenize(senders, ",", &sender_ids);
+
+ if (sender_ids.empty() || registration_id_str.empty()) {
+ sender_ids.clear();
+ registration_id_str.clear();
+ return false;
+ }
+
+ if (registration_id)
+ *registration_id = registration_id_str;
+
+ return true;
+}
+
+// static
+const InstanceIDTokenInfo* InstanceIDTokenInfo::FromRegistrationInfo(
+ const RegistrationInfo* registration_info) {
+ if (!registration_info || registration_info->GetType() != INSTANCE_ID_TOKEN)
+ return NULL;
+ return static_cast<const InstanceIDTokenInfo*>(registration_info);
+}
+
+// static
+InstanceIDTokenInfo* InstanceIDTokenInfo::FromRegistrationInfo(
+ RegistrationInfo* registration_info) {
+ if (!registration_info || registration_info->GetType() != INSTANCE_ID_TOKEN)
+ return NULL;
+ return static_cast<InstanceIDTokenInfo*>(registration_info);
+}
+
+InstanceIDTokenInfo::InstanceIDTokenInfo() {
+}
+
+InstanceIDTokenInfo::~InstanceIDTokenInfo() {
+}
+
+RegistrationInfo::RegistrationType InstanceIDTokenInfo::GetType() const {
+ return INSTANCE_ID_TOKEN;
+}
+
+std::string InstanceIDTokenInfo::GetSerializedKey() const {
+ DCHECK(authorized_entity.find(',') == std::string::npos &&
+ scope.find(',') == std::string::npos);
+
+ // Multiple registrations are supported for Instance ID. So the key is based
+ // on the combination of (app_id, authorized_entity, scope).
+
+ // Adds a prefix to differentiate easily with GCM registration key.
+ std::string key(kInsanceIDSerializationPrefix);
+ key += app_id;
+ key += ",";
+ key += authorized_entity;
+ key += ",";
+ key += scope;
+ return key;
+}
+
+std::string InstanceIDTokenInfo::GetSerializedValue(
+ const std::string& registration_id) const {
+ return registration_id;
+}
+
+bool InstanceIDTokenInfo::Deserialize(
+ const std::string& serialized_key,
+ const std::string& serialized_value,
+ std::string* registration_id) {
+ if (serialized_key.empty() || serialized_value.empty())
+ return false;
+
+ if (!StartsWithASCII(serialized_key, kInsanceIDSerializationPrefix, true))
+ return false;
+
+ std::vector<std::string> fields;
+ Tokenize(serialized_key.substr(kInsanceIDSerializationPrefixLength),
+ ",",
+ &fields);
+ if (fields.size() != 3 || fields[0].empty() ||
+ fields[1].empty() || fields[2].empty()) {
+ return false;
+ }
+ app_id = fields[0];
+ authorized_entity = fields[1];
+ scope = fields[2];
+
+ // Registration ID is same as the serialized value;
+ if (registration_id)
+ *registration_id = serialized_value;
+
+ return true;
+}
+
+bool RegistrationInfoComparer::operator()(
+ const linked_ptr<RegistrationInfo>& a,
+ const linked_ptr<RegistrationInfo>& b) const {
+ DCHECK(a.get() && b.get());
+
+ // For GCMRegistrationInfo, the comparison is based on app_id only.
+ // For InstanceIDTokenInfo, the comparison is bsaed on
+ // <app_id, authorized_entity, scope>.
+ if (a->app_id < b->app_id)
+ return true;
+ if (a->app_id > b->app_id)
+ return false;
+
+ InstanceIDTokenInfo* iid_a =
+ InstanceIDTokenInfo::FromRegistrationInfo(a.get());
+ InstanceIDTokenInfo* iid_b =
+ InstanceIDTokenInfo::FromRegistrationInfo(b.get());
+
+ // !iid_a && !iid_b => false.
+ // !iid_a && iid_b => true.
+ // This makes GCM record is sorted before InstanceID record.
+ if (!iid_a)
+ return iid_b != NULL;
+
+ // iid_a && !iid_b => false.
+ if (!iid_b)
+ return false;
+
+ // Otherwise, compare with authorized_entity and scope.
+ if (iid_a->authorized_entity < iid_b->authorized_entity)
+ return true;
+ if (iid_a->authorized_entity > iid_b->authorized_entity)
+ return false;
+ return iid_a->scope < iid_b->scope;
+}
+
+bool ExistsGCMRegistrationInMap(const RegistrationInfoMap& map,
+ const std::string& app_id) {
+ scoped_ptr<GCMRegistrationInfo> gcm_registration(new GCMRegistrationInfo);
+ gcm_registration->app_id = app_id;
+ return map.count(
+ make_linked_ptr<RegistrationInfo>(gcm_registration.release())) > 0;
+}
+
+} // namespace gcm
diff --git a/components/gcm_driver/registration_info.h b/components/gcm_driver/registration_info.h
new file mode 100644
index 0000000..346eca3
--- /dev/null
+++ b/components/gcm_driver/registration_info.h
@@ -0,0 +1,130 @@
+// Copyright 2015 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 COMPONENTS_GCM_DRIVER_REGISTRATION_INFO_H_
+#define COMPONENTS_GCM_DRIVER_REGISTRATION_INFO_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace gcm {
+
+// Encapsulates the information needed to register with the server.
+struct RegistrationInfo {
+ enum RegistrationType {
+ GCM_REGISTRATION,
+ INSTANCE_ID_TOKEN
+ };
+
+ // Returns the appropriate RegistrationInfo instance based on the serialized
+ // key and value.
+ // |registration_id| can be NULL if no interest to it.
+ static scoped_ptr<RegistrationInfo> BuildFromString(
+ const std::string& serialzied_key,
+ const std::string& serialzied_value,
+ std::string* registration_id);
+
+ RegistrationInfo();
+ virtual ~RegistrationInfo();
+
+ // Returns the type of the registration info.
+ virtual RegistrationType GetType() const = 0;
+
+ // For persisting to the store. Depending on the type, part of the
+ // registration info is written as key. The remaining of the registration
+ // info plus the registration ID are written as value.
+ virtual std::string GetSerializedKey() const = 0;
+ virtual std::string GetSerializedValue(
+ const std::string& registration_id) const = 0;
+ // |registration_id| can be NULL if it is of no interest to the caller.
+ virtual bool Deserialize(const std::string& serialzied_key,
+ const std::string& serialzied_value,
+ std::string* registration_id) = 0;
+
+ // Every registration is associated with an application.
+ std::string app_id;
+};
+
+// For GCM registration.
+struct GCMRegistrationInfo : public RegistrationInfo {
+ GCMRegistrationInfo();
+ ~GCMRegistrationInfo() override;
+
+ // Converts from the base type;
+ static const GCMRegistrationInfo* FromRegistrationInfo(
+ const RegistrationInfo* registration_info);
+ static GCMRegistrationInfo* FromRegistrationInfo(
+ RegistrationInfo* registration_info);
+
+ // RegistrationInfo overrides:
+ RegistrationType GetType() const override;
+ std::string GetSerializedKey() const override;
+ std::string GetSerializedValue(
+ const std::string& registration_id) const override;
+ bool Deserialize(const std::string& serialzied_key,
+ const std::string& serialzied_value,
+ std::string* registration_id) override;
+
+ // List of IDs of the servers that are allowed to send the messages to the
+ // application. These IDs are assigned by the Google API Console.
+ std::vector<std::string> sender_ids;
+};
+
+// For InstanceID token retrieval.
+struct InstanceIDTokenInfo : public RegistrationInfo {
+ InstanceIDTokenInfo();
+ ~InstanceIDTokenInfo() override;
+
+ // Converts from the base type;
+ static const InstanceIDTokenInfo* FromRegistrationInfo(
+ const RegistrationInfo* registration_info);
+ static InstanceIDTokenInfo* FromRegistrationInfo(
+ RegistrationInfo* registration_info);
+
+ // RegistrationInfo overrides:
+ RegistrationType GetType() const override;
+ std::string GetSerializedKey() const override;
+ std::string GetSerializedValue(
+ const std::string& registration_id) const override;
+ bool Deserialize(const std::string& serialzied_key,
+ const std::string& serialzied_value,
+ std::string* registration_id) override;
+
+ // Entity that is authorized to access resources associated with the Instance
+ // ID. It can be another Instance ID or a project ID assigned by the Google
+ // API Console.
+ std::string authorized_entity;
+
+ // Authorized actions that the authorized entity can take.
+ // E.g. for sending GCM messages, 'GCM' scope should be used.
+ std::string scope;
+
+ // Allows including a small number of string key/value pairs that will be
+ // associated with the token and may be used in processing the request.
+ std::map<std::string, std::string> options;
+};
+
+struct RegistrationInfoComparer {
+ bool operator()(const linked_ptr<RegistrationInfo>& a,
+ const linked_ptr<RegistrationInfo>& b) const;
+};
+
+// Collection of registration info.
+// Map from RegistrationInfo instance to registration ID.
+typedef std::map<linked_ptr<RegistrationInfo>,
+ std::string,
+ RegistrationInfoComparer> RegistrationInfoMap;
+
+// Returns true if a GCM registration for |app_id| exists in |map|.
+bool ExistsGCMRegistrationInMap(const RegistrationInfoMap& map,
+ const std::string& app_id);
+
+} // namespace gcm
+
+#endif // COMPONENTS_GCM_DRIVER_REGISTRATION_INFO_H_
diff --git a/google_apis/gcm/BUILD.gn b/google_apis/gcm/BUILD.gn
index 83aa067..ee6a42f 100644
--- a/google_apis/gcm/BUILD.gn
+++ b/google_apis/gcm/BUILD.gn
@@ -7,6 +7,8 @@ import("//third_party/protobuf/proto_library.gni")
component("gcm") {
sources = [
+ "base/gcm_util.cc",
+ "base/gcm_util.h",
"base/mcs_message.cc",
"base/mcs_message.h",
"base/mcs_util.cc",
@@ -25,18 +27,24 @@ component("gcm") {
"engine/connection_handler.h",
"engine/connection_handler_impl.cc",
"engine/connection_handler_impl.h",
+ "engine/gcm_registration_request_handler.cc",
+ "engine/gcm_registration_request_handler.h",
"engine/gcm_store.cc",
"engine/gcm_store.h",
"engine/gcm_store_impl.cc",
"engine/gcm_store_impl.h",
+ "engine/gcm_unregistration_request_handler.cc",
+ "engine/gcm_unregistration_request_handler.h",
"engine/gservices_settings.cc",
"engine/gservices_settings.h",
"engine/heartbeat_manager.cc",
"engine/heartbeat_manager.h",
+ "engine/instance_id_delete_token_request_handler.cc",
+ "engine/instance_id_delete_token_request_handler.h",
+ "engine/instance_id_get_token_request_handler.cc",
+ "engine/instance_id_get_token_request_handler.h",
"engine/mcs_client.cc",
"engine/mcs_client.h",
- "engine/registration_info.cc",
- "engine/registration_info.h",
"engine/registration_request.cc",
"engine/registration_request.h",
"engine/unregistration_request.cc",
diff --git a/google_apis/gcm/base/gcm_util.cc b/google_apis/gcm/base/gcm_util.cc
new file mode 100644
index 0000000..e51a498
--- /dev/null
+++ b/google_apis/gcm/base/gcm_util.cc
@@ -0,0 +1,19 @@
+// Copyright 2015 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 "google_apis/gcm/base/gcm_util.h"
+
+#include "net/base/escape.h"
+
+namespace gcm {
+
+void BuildFormEncoding(const std::string& key,
+ const std::string& value,
+ std::string* out) {
+ if (!out->empty())
+ out->append("&");
+ out->append(key + "=" + net::EscapeUrlEncodedData(value, true));
+}
+
+} // namespace gcm
diff --git a/google_apis/gcm/base/gcm_util.h b/google_apis/gcm/base/gcm_util.h
new file mode 100644
index 0000000..261950b
--- /dev/null
+++ b/google_apis/gcm/base/gcm_util.h
@@ -0,0 +1,21 @@
+// Copyright 2015 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 GOOGLE_APIS_GCM_BASE_GCM_UTIL_H_
+#define GOOGLE_APIS_GCM_BASE_GCM_UTIL_H_
+
+#include <string>
+
+namespace gcm {
+
+// Encodes key-value pair into form format that could be submitted as http post
+// data. Each key-value pair is separated by an '&', and each key is separated
+// from its value by an '='.
+void BuildFormEncoding(const std::string& key,
+ const std::string& value,
+ std::string* out);
+
+} // namespace gcm
+
+#endif // GOOGLE_APIS_GCM_BASE_GCM_UTIL_H_
diff --git a/google_apis/gcm/engine/gcm_registration_request_handler.cc b/google_apis/gcm/engine/gcm_registration_request_handler.cc
new file mode 100644
index 0000000..c0213f3
--- /dev/null
+++ b/google_apis/gcm/engine/gcm_registration_request_handler.cc
@@ -0,0 +1,29 @@
+// Copyright 2015 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 "google_apis/gcm/engine/gcm_registration_request_handler.h"
+
+#include "google_apis/gcm/base/gcm_util.h"
+
+namespace gcm {
+
+namespace {
+
+// Request constants.
+const char kSenderKey[] = "sender";
+
+} // namespace
+
+GCMRegistrationRequestHandler::GCMRegistrationRequestHandler(
+ const std::string& senders)
+ : senders_(senders) {
+}
+
+GCMRegistrationRequestHandler::~GCMRegistrationRequestHandler() {}
+
+void GCMRegistrationRequestHandler::BuildRequestBody(std::string* body){
+ BuildFormEncoding(kSenderKey, senders_, body);
+}
+
+} // namespace gcm
diff --git a/google_apis/gcm/engine/gcm_registration_request_handler.h b/google_apis/gcm/engine/gcm_registration_request_handler.h
new file mode 100644
index 0000000..26ba49d
--- /dev/null
+++ b/google_apis/gcm/engine/gcm_registration_request_handler.h
@@ -0,0 +1,30 @@
+// Copyright 2015 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 GOOGLE_APIS_GCM_ENGINE_GCM_REGISTRATION_REQUEST_HANDLER_H_
+#define GOOGLE_APIS_GCM_ENGINE_GCM_REGISTRATION_REQUEST_HANDLER_H_
+
+#include "google_apis/gcm/engine/registration_request.h"
+
+namespace gcm {
+
+// Used to obtain the registration ID for applications that want to use GCM.
+class GCM_EXPORT GCMRegistrationRequestHandler :
+ public RegistrationRequest::CustomRequestHandler {
+ public:
+ GCMRegistrationRequestHandler(const std::string& senders);
+ ~GCMRegistrationRequestHandler() override;
+
+ // RegistrationRequest::RequestHandler overrides:
+ void BuildRequestBody(std::string* body) override;
+
+ private:
+ std::string senders_;
+
+ DISALLOW_COPY_AND_ASSIGN(GCMRegistrationRequestHandler);
+};
+
+} // namespace gcm
+
+#endif // GOOGLE_APIS_GCM_ENGINE_GCM_REGISTRATION_REQUEST_HANDLER_H_
diff --git a/google_apis/gcm/engine/gcm_store.h b/google_apis/gcm/engine/gcm_store.h
index cfefe91..83ec73d 100644
--- a/google_apis/gcm/engine/gcm_store.h
+++ b/google_apis/gcm/engine/gcm_store.h
@@ -20,7 +20,6 @@
#include "base/time/time.h"
#include "google_apis/gcm/base/gcm_export.h"
#include "google_apis/gcm/engine/account_mapping.h"
-#include "google_apis/gcm/engine/registration_info.h"
namespace gcm {
@@ -47,7 +46,7 @@ class GCM_EXPORT GCMStore {
bool success;
uint64 device_android_id;
uint64 device_security_token;
- RegistrationInfoMap registrations;
+ std::map<std::string, std::string> registrations;
std::vector<std::string> incoming_messages;
OutgoingMessageMap outgoing_messages;
std::map<std::string, std::string> gservices_settings;
@@ -82,11 +81,15 @@ class GCM_EXPORT GCMStore {
uint64 device_security_token,
const UpdateCallback& callback) = 0;
- // Registration info.
- virtual void AddRegistration(const std::string& app_id,
- const linked_ptr<RegistrationInfo>& registration,
+ // Registration info for both GCM registrations and InstanceID tokens.
+ // For GCM, |serialized_key| is app_id and |serialized_value| is
+ // serialization of (senders, registration_id). For InstanceID,
+ // |serialized_key| is serialization of (app_id, authorized_entity, scope)
+ // and |serialized_value| is token.
+ virtual void AddRegistration(const std::string& serialized_key,
+ const std::string& serialized_value,
const UpdateCallback& callback) = 0;
- virtual void RemoveRegistration(const std::string& app_id,
+ virtual void RemoveRegistration(const std::string& serialized_key,
const UpdateCallback& callback) = 0;
// Unacknowledged incoming message handling.
diff --git a/google_apis/gcm/engine/gcm_store_impl.cc b/google_apis/gcm/engine/gcm_store_impl.cc
index 09bfb83..3436ba9 100644
--- a/google_apis/gcm/engine/gcm_store_impl.cc
+++ b/google_apis/gcm/engine/gcm_store_impl.cc
@@ -190,10 +190,10 @@ class GCMStoreImpl::Backend
void SetDeviceCredentials(uint64 device_android_id,
uint64 device_security_token,
const UpdateCallback& callback);
- void AddRegistration(const std::string& app_id,
- const std::string& serialized_registration,
+ void AddRegistration(const std::string& serialized_key,
+ const std::string& serialized_value,
const UpdateCallback& callback);
- void RemoveRegistration(const std::string& app_id,
+ void RemoveRegistration(const std::string& serialized_key,
const UpdateCallback& callback);
void AddIncomingMessage(const std::string& persistent_id,
const UpdateCallback& callback);
@@ -244,7 +244,7 @@ class GCMStoreImpl::Backend
LoadStatus OpenStoreAndLoadData(LoadResult* result);
bool LoadDeviceCredentials(uint64* android_id, uint64* security_token);
- bool LoadRegistrations(RegistrationInfoMap* registrations);
+ bool LoadRegistrations(std::map<std::string, std::string>* registrations);
bool LoadIncomingMessages(std::vector<std::string>* incoming_messages);
bool LoadOutgoingMessages(OutgoingMessageMap* outgoing_messages);
bool LoadLastCheckinInfo(base::Time* last_checkin_time,
@@ -417,10 +417,10 @@ void GCMStoreImpl::Backend::SetDeviceCredentials(
}
void GCMStoreImpl::Backend::AddRegistration(
- const std::string& app_id,
- const std::string& serialized_registration,
+ const std::string& serialized_key,
+ const std::string& serialized_value,
const UpdateCallback& callback) {
- DVLOG(1) << "Saving registration info for app: " << app_id;
+ DVLOG(1) << "Saving registration info for app: " << serialized_key;
if (!db_.get()) {
LOG(ERROR) << "GCMStore db doesn't exist.";
foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
@@ -429,20 +429,19 @@ void GCMStoreImpl::Backend::AddRegistration(
leveldb::WriteOptions write_options;
write_options.sync = true;
- std::string key = MakeRegistrationKey(app_id);
- const leveldb::Status status = db_->Put(write_options,
- MakeSlice(key),
- MakeSlice(serialized_registration));
- if (status.ok()) {
- foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
- return;
- }
- LOG(ERROR) << "LevelDB put failed: " << status.ToString();
- foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
+ const leveldb::Status status = db_->Put(
+ write_options,
+ MakeSlice(MakeRegistrationKey(serialized_key)),
+ MakeSlice(serialized_value));
+ if (!status.ok())
+ LOG(ERROR) << "LevelDB put failed: " << status.ToString();
+ foreground_task_runner_->PostTask(
+ FROM_HERE, base::Bind(callback, status.ok()));
}
-void GCMStoreImpl::Backend::RemoveRegistration(const std::string& app_id,
- const UpdateCallback& callback) {
+void GCMStoreImpl::Backend::RemoveRegistration(
+ const std::string& serialized_key,
+ const UpdateCallback& callback) {
if (!db_.get()) {
LOG(ERROR) << "GCMStore db doesn't exist.";
foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
@@ -451,14 +450,12 @@ void GCMStoreImpl::Backend::RemoveRegistration(const std::string& app_id,
leveldb::WriteOptions write_options;
write_options.sync = true;
- leveldb::Status status =
- db_->Delete(write_options, MakeSlice(MakeRegistrationKey(app_id)));
- if (status.ok()) {
- foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
- return;
- }
- LOG(ERROR) << "LevelDB remove failed: " << status.ToString();
- foreground_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
+ leveldb::Status status = db_->Delete(
+ write_options, MakeSlice(MakeRegistrationKey(serialized_key)));
+ if (!status.ok())
+ LOG(ERROR) << "LevelDB remove failed: " << status.ToString();
+ foreground_task_runner_->PostTask(
+ FROM_HERE, base::Bind(callback, status.ok()));
}
void GCMStoreImpl::Backend::AddIncomingMessage(const std::string& persistent_id,
@@ -902,7 +899,7 @@ bool GCMStoreImpl::Backend::LoadDeviceCredentials(uint64* android_id,
}
bool GCMStoreImpl::Backend::LoadRegistrations(
- RegistrationInfoMap* registrations) {
+ std::map<std::string, std::string>* registrations) {
leveldb::ReadOptions read_options;
read_options.verify_checksums = true;
@@ -916,13 +913,8 @@ bool GCMStoreImpl::Backend::LoadRegistrations(
return false;
}
std::string app_id = ParseRegistrationKey(iter->key().ToString());
- linked_ptr<RegistrationInfo> registration(new RegistrationInfo);
- if (!registration->ParseFromString(iter->value().ToString())) {
- LOG(ERROR) << "Failed to parse registration with app id " << app_id;
- return false;
- }
DVLOG(1) << "Found registration with app id " << app_id;
- (*registrations)[app_id] = registration;
+ (*registrations)[app_id] = iter->value().ToString();
}
return true;
@@ -1182,16 +1174,15 @@ void GCMStoreImpl::SetDeviceCredentials(uint64 device_android_id,
}
void GCMStoreImpl::AddRegistration(
- const std::string& app_id,
- const linked_ptr<RegistrationInfo>& registration,
+ const std::string& serialized_key,
+ const std::string& serialized_value,
const UpdateCallback& callback) {
- std::string serialized_registration = registration->SerializeAsString();
blocking_task_runner_->PostTask(
FROM_HERE,
base::Bind(&GCMStoreImpl::Backend::AddRegistration,
backend_,
- app_id,
- serialized_registration,
+ serialized_key,
+ serialized_value,
callback));
}
diff --git a/google_apis/gcm/engine/gcm_store_impl.h b/google_apis/gcm/engine/gcm_store_impl.h
index 4815b20..8feebff 100644
--- a/google_apis/gcm/engine/gcm_store_impl.h
+++ b/google_apis/gcm/engine/gcm_store_impl.h
@@ -49,10 +49,10 @@ class GCM_EXPORT GCMStoreImpl : public GCMStore {
const UpdateCallback& callback) override;
// Registration info.
- void AddRegistration(const std::string& app_id,
- const linked_ptr<RegistrationInfo>& registration,
+ void AddRegistration(const std::string& serialized_key,
+ const std::string& serialized_value,
const UpdateCallback& callback) override;
- void RemoveRegistration(const std::string& app_id,
+ void RemoveRegistration(const std::string& serialized_key,
const UpdateCallback& callback) override;
// Unacknowledged incoming message handling.
diff --git a/google_apis/gcm/engine/gcm_store_impl_unittest.cc b/google_apis/gcm/engine/gcm_store_impl_unittest.cc
index b7bf75d..2fe64b4 100644
--- a/google_apis/gcm/engine/gcm_store_impl_unittest.cc
+++ b/google_apis/gcm/engine/gcm_store_impl_unittest.cc
@@ -232,22 +232,17 @@ TEST_F(GCMStoreImplTest, Registrations) {
PumpLoop();
// Add one registration with one sender.
- linked_ptr<RegistrationInfo> registration1(new RegistrationInfo);
- registration1->sender_ids.push_back("sender1");
- registration1->registration_id = "registration1";
+ std::string registration = "sender1=registration1";
gcm_store->AddRegistration(
- "app1",
- registration1,
+ kAppName,
+ registration,
base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
PumpLoop();
// Add one registration with multiple senders.
- linked_ptr<RegistrationInfo> registration2(new RegistrationInfo);
- registration2->sender_ids.push_back("sender2_1");
- registration2->sender_ids.push_back("sender2_2");
- registration2->registration_id = "registration2";
+ std::string registration2 = "sender1,sender2=registration2";
gcm_store->AddRegistration(
- "app2",
+ kAppName2,
registration2,
base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
PumpLoop();
@@ -258,25 +253,15 @@ TEST_F(GCMStoreImplTest, Registrations) {
PumpLoop();
ASSERT_EQ(2u, load_result->registrations.size());
- ASSERT_TRUE(load_result->registrations.find("app1") !=
+ ASSERT_TRUE(load_result->registrations.find(kAppName) !=
load_result->registrations.end());
- EXPECT_EQ(registration1->registration_id,
- load_result->registrations["app1"]->registration_id);
- ASSERT_EQ(1u, load_result->registrations["app1"]->sender_ids.size());
- EXPECT_EQ(registration1->sender_ids[0],
- load_result->registrations["app1"]->sender_ids[0]);
- ASSERT_TRUE(load_result->registrations.find("app2") !=
+ EXPECT_EQ(registration, load_result->registrations[kAppName]);
+ ASSERT_TRUE(load_result->registrations.find(kAppName2) !=
load_result->registrations.end());
- EXPECT_EQ(registration2->registration_id,
- load_result->registrations["app2"]->registration_id);
- ASSERT_EQ(2u, load_result->registrations["app2"]->sender_ids.size());
- EXPECT_EQ(registration2->sender_ids[0],
- load_result->registrations["app2"]->sender_ids[0]);
- EXPECT_EQ(registration2->sender_ids[1],
- load_result->registrations["app2"]->sender_ids[1]);
+ EXPECT_EQ(registration2, load_result->registrations[kAppName2]);
gcm_store->RemoveRegistration(
- "app2",
+ kAppName2,
base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
PumpLoop();
@@ -286,13 +271,9 @@ TEST_F(GCMStoreImplTest, Registrations) {
PumpLoop();
ASSERT_EQ(1u, load_result->registrations.size());
- ASSERT_TRUE(load_result->registrations.find("app1") !=
+ ASSERT_TRUE(load_result->registrations.find(kAppName) !=
load_result->registrations.end());
- EXPECT_EQ(registration1->registration_id,
- load_result->registrations["app1"]->registration_id);
- ASSERT_EQ(1u, load_result->registrations["app1"]->sender_ids.size());
- EXPECT_EQ(registration1->sender_ids[0],
- load_result->registrations["app1"]->sender_ids[0]);
+ EXPECT_EQ(registration, load_result->registrations[kAppName]);
}
// Verify saving some incoming messages, reopening the directory, and then
diff --git a/google_apis/gcm/engine/gcm_unregistration_request_handler.cc b/google_apis/gcm/engine/gcm_unregistration_request_handler.cc
new file mode 100644
index 0000000..86f473b
--- /dev/null
+++ b/google_apis/gcm/engine/gcm_unregistration_request_handler.cc
@@ -0,0 +1,68 @@
+// Copyright 2015 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 "google_apis/gcm/engine/gcm_unregistration_request_handler.h"
+
+#include "google_apis/gcm/base/gcm_util.h"
+#include "net/url_request/url_fetcher.h"
+
+namespace gcm {
+
+namespace {
+
+// Request constants.
+const char kUnregistrationCallerKey[] = "gcm_unreg_caller";
+// We are going to set the value to "false" in order to forcefully unregister
+// the application.
+const char kUnregistrationCallerValue[] = "false";
+
+// Response constants.
+const char kDeletedPrefix[] = "deleted=";
+const char kErrorPrefix[] = "Error=";
+const char kInvalidParameters[] = "INVALID_PARAMETERS";
+
+} // namespace
+
+GCMUnregistrationRequestHandler::GCMUnregistrationRequestHandler(
+ const std::string& app_id)
+ : app_id_(app_id) {
+}
+
+GCMUnregistrationRequestHandler::~GCMUnregistrationRequestHandler() {}
+
+void GCMUnregistrationRequestHandler::BuildRequestBody(std::string* body){
+ BuildFormEncoding(kUnregistrationCallerKey, kUnregistrationCallerValue, body);
+}
+
+UnregistrationRequest::Status GCMUnregistrationRequestHandler::ParseResponse(
+ const net::URLFetcher* source) {
+ std::string response;
+ if (!source->GetResponseAsString(&response)) {
+ DVLOG(1) << "Failed to get response body.";
+ return UnregistrationRequest::NO_RESPONSE_BODY;
+ }
+
+ DVLOG(1) << "Parsing unregistration response.";
+ if (response.find(kDeletedPrefix) != std::string::npos) {
+ std::string deleted_app_id = response.substr(
+ response.find(kDeletedPrefix) + arraysize(kDeletedPrefix) - 1);
+ return deleted_app_id == app_id_ ?
+ UnregistrationRequest::SUCCESS :
+ UnregistrationRequest::INCORRECT_APP_ID;
+ }
+
+ if (response.find(kErrorPrefix) != std::string::npos) {
+ std::string error = response.substr(
+ response.find(kErrorPrefix) + arraysize(kErrorPrefix) - 1);
+ return error == kInvalidParameters ?
+ UnregistrationRequest::INVALID_PARAMETERS :
+ UnregistrationRequest::UNKNOWN_ERROR;
+ }
+
+ DVLOG(1) << "Not able to parse a meaningful output from response body."
+ << response;
+ return UnregistrationRequest::RESPONSE_PARSING_FAILED;
+}
+
+} // namespace gcm
diff --git a/google_apis/gcm/engine/gcm_unregistration_request_handler.h b/google_apis/gcm/engine/gcm_unregistration_request_handler.h
new file mode 100644
index 0000000..ac2a5d4
--- /dev/null
+++ b/google_apis/gcm/engine/gcm_unregistration_request_handler.h
@@ -0,0 +1,33 @@
+// Copyright 2015 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 GOOGLE_APIS_GCM_ENGINE_GCM_UNREGISTRATION_REQUEST_HANDLER_H_
+#define GOOGLE_APIS_GCM_ENGINE_GCM_UNREGISTRATION_REQUEST_HANDLER_H_
+
+#include "google_apis/gcm/engine/unregistration_request.h"
+
+namespace gcm {
+
+// Used to revoke the registration ID when unregister is called or the
+// application has been uninstalled.
+class GCM_EXPORT GCMUnregistrationRequestHandler :
+ public UnregistrationRequest::CustomRequestHandler {
+ public:
+ GCMUnregistrationRequestHandler(const std::string& app_id);
+ ~GCMUnregistrationRequestHandler() override;
+
+ // UnregistrationRequest::CustomRequestHandler overrides:
+ void BuildRequestBody(std::string* body) override;
+ UnregistrationRequest::Status ParseResponse(
+ const net::URLFetcher* source) override;
+
+ private:
+ std::string app_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(GCMUnregistrationRequestHandler);
+};
+
+} // namespace gcm
+
+#endif // GOOGLE_APIS_GCM_ENGINE_GCM_UNREGISTRATION_REQUEST_HANDLER_H_
diff --git a/google_apis/gcm/engine/gservices_settings_unittest.cc b/google_apis/gcm/engine/gservices_settings_unittest.cc
index 09977fa..fcf633e 100644
--- a/google_apis/gcm/engine/gservices_settings_unittest.cc
+++ b/google_apis/gcm/engine/gservices_settings_unittest.cc
@@ -4,7 +4,6 @@
#include "base/strings/string_number_conversions.h"
#include "google_apis/gcm/engine/gservices_settings.h"
-#include "google_apis/gcm/engine/registration_info.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace gcm {
diff --git a/google_apis/gcm/engine/instance_id_delete_token_request_handler.cc b/google_apis/gcm/engine/instance_id_delete_token_request_handler.cc
new file mode 100644
index 0000000..1f3f2c3
--- /dev/null
+++ b/google_apis/gcm/engine/instance_id_delete_token_request_handler.cc
@@ -0,0 +1,65 @@
+// Copyright 2015 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 "google_apis/gcm/engine/instance_id_delete_token_request_handler.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "google_apis/gcm/base/gcm_util.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_request_context_getter.h"
+
+namespace gcm {
+
+namespace {
+
+// Request constants.
+const char kGMSVersionKey[] = "gmsv";
+const char kInstanceIDKey[] = "appid";
+const char kSenderKey[] = "sender";
+const char kScopeKey[] = "scope";
+
+// Response constants.
+const char kTokenPrefix[] = "token=";
+
+} // namespace
+
+InstanceIDDeleteTokenRequestHandler::InstanceIDDeleteTokenRequestHandler(
+ const std::string& instance_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ int gcm_version)
+ : instance_id_(instance_id),
+ authorized_entity_(authorized_entity),
+ scope_(scope),
+ gcm_version_(gcm_version) {
+ DCHECK(!instance_id.empty());
+ DCHECK(!authorized_entity.empty());
+ DCHECK(!scope.empty());
+}
+
+InstanceIDDeleteTokenRequestHandler::~InstanceIDDeleteTokenRequestHandler() {}
+
+void InstanceIDDeleteTokenRequestHandler::BuildRequestBody(std::string* body){
+ BuildFormEncoding(kInstanceIDKey, instance_id_, body);
+ BuildFormEncoding(kSenderKey, authorized_entity_, body);
+ BuildFormEncoding(kScopeKey, scope_, body);
+ BuildFormEncoding(kGMSVersionKey, base::IntToString(gcm_version_), body);
+}
+
+UnregistrationRequest::Status
+InstanceIDDeleteTokenRequestHandler::ParseResponse(
+ const net::URLFetcher* source) {
+ std::string response;
+ if (!source->GetResponseAsString(&response)) {
+ DVLOG(1) << "Failed to get response body.";
+ return UnregistrationRequest::NO_RESPONSE_BODY;
+ }
+
+ if (response.find(kTokenPrefix) == std::string::npos)
+ return UnregistrationRequest::RESPONSE_PARSING_FAILED;
+
+ return UnregistrationRequest::SUCCESS;
+}
+
+} // namespace gcm
diff --git a/google_apis/gcm/engine/instance_id_delete_token_request_handler.h b/google_apis/gcm/engine/instance_id_delete_token_request_handler.h
new file mode 100644
index 0000000..fec6e04
--- /dev/null
+++ b/google_apis/gcm/engine/instance_id_delete_token_request_handler.h
@@ -0,0 +1,41 @@
+// Copyright 2015 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 GOOGLE_APIS_GCM_ENGINE_INSTANCE_ID_DELETE_TOKEN_REQUEST_HANDLER_H_
+#define GOOGLE_APIS_GCM_ENGINE_INSTANCE_ID_DELETE_TOKEN_REQUEST_HANDLER_H_
+
+#include <string>
+
+#include "google_apis/gcm/engine/unregistration_request.h"
+
+namespace gcm {
+
+// Provides custom logic to handle DeleteToken request for InstanceID.
+class GCM_EXPORT InstanceIDDeleteTokenRequestHandler :
+ public UnregistrationRequest::CustomRequestHandler {
+ public:
+ InstanceIDDeleteTokenRequestHandler(
+ const std::string& instance_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ int gcm_version);
+ ~InstanceIDDeleteTokenRequestHandler() override;
+
+ // UnregistrationRequest overrides:
+ void BuildRequestBody(std::string* body) override;
+ UnregistrationRequest::Status ParseResponse(
+ const net::URLFetcher* source) override;
+
+ private:
+ std::string instance_id_;
+ std::string authorized_entity_;
+ std::string scope_;
+ int gcm_version_;
+
+ DISALLOW_COPY_AND_ASSIGN(InstanceIDDeleteTokenRequestHandler);
+};
+
+} // namespace gcm
+
+#endif // GOOGLE_APIS_GCM_ENGINE_INSTANCE_ID_DELETE_TOKEN_REQUEST_HANDLER_H_
diff --git a/google_apis/gcm/engine/instance_id_get_token_request_handler.cc b/google_apis/gcm/engine/instance_id_get_token_request_handler.cc
new file mode 100644
index 0000000..2e1c170
--- /dev/null
+++ b/google_apis/gcm/engine/instance_id_get_token_request_handler.cc
@@ -0,0 +1,52 @@
+// Copyright 2014 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 "google_apis/gcm/engine/instance_id_get_token_request_handler.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "google_apis/gcm/base/gcm_util.h"
+#include "net/url_request/url_request_context_getter.h"
+
+namespace gcm {
+
+namespace {
+
+// Request constants.
+const char kAuthorizedEntityKey[] = "sender";
+const char kGMSVersionKey[] = "gmsv";
+const char kInstanceIDKey[] = "appid";
+const char kScopeKey[] = "scope";
+// Prefix that needs to be added for each option key.
+const char kOptionKeyPrefix[] = "X-";
+
+} // namespace
+
+InstanceIDGetTokenRequestHandler::InstanceIDGetTokenRequestHandler(
+ const std::string& instance_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ int gcm_version,
+ const std::map<std::string, std::string>& options)
+ : instance_id_(instance_id),
+ authorized_entity_(authorized_entity),
+ scope_(scope),
+ gcm_version_(gcm_version),
+ options_(options) {
+ DCHECK(!instance_id.empty());
+ DCHECK(!authorized_entity.empty());
+ DCHECK(!scope.empty());
+}
+
+InstanceIDGetTokenRequestHandler::~InstanceIDGetTokenRequestHandler() {}
+
+void InstanceIDGetTokenRequestHandler::BuildRequestBody(std::string* body){
+ BuildFormEncoding(kScopeKey, scope_, body);
+ for (auto iter = options_.begin(); iter != options_.end(); ++iter)
+ BuildFormEncoding(kOptionKeyPrefix + iter->first, iter->second, body);
+ BuildFormEncoding(kGMSVersionKey, base::IntToString(gcm_version_), body);
+ BuildFormEncoding(kInstanceIDKey, instance_id_, body);
+ BuildFormEncoding(kAuthorizedEntityKey, authorized_entity_, body);
+}
+
+} // namespace gcm
diff --git a/google_apis/gcm/engine/instance_id_get_token_request_handler.h b/google_apis/gcm/engine/instance_id_get_token_request_handler.h
new file mode 100644
index 0000000..c09b1ab
--- /dev/null
+++ b/google_apis/gcm/engine/instance_id_get_token_request_handler.h
@@ -0,0 +1,42 @@
+// Copyright 2015 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 GOOGLE_APIS_GCM_ENGINE_INSTANCE_ID_GET_TOKEN_REQUEST_HANDLER_H_
+#define GOOGLE_APIS_GCM_ENGINE_INSTANCE_ID_GET_TOKEN_REQUEST_HANDLER_H_
+
+#include <map>
+#include <string>
+
+#include "google_apis/gcm/engine/registration_request.h"
+
+namespace gcm {
+
+// Used to obtain a token based on Instance ID.
+class GCM_EXPORT InstanceIDGetTokenRequestHandler :
+ public RegistrationRequest::CustomRequestHandler {
+ public:
+ InstanceIDGetTokenRequestHandler(
+ const std::string& instance_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ int gcm_version,
+ const std::map<std::string, std::string>& options);
+ ~InstanceIDGetTokenRequestHandler() override;
+
+ // RegistrationRequest overrides:
+ void BuildRequestBody(std::string* body) override;
+
+ private:
+ std::string instance_id_;
+ std::string authorized_entity_;
+ std::string scope_;
+ int gcm_version_;
+ std::map<std::string, std::string> options_;
+
+ DISALLOW_COPY_AND_ASSIGN(InstanceIDGetTokenRequestHandler);
+};
+
+} // namespace gcm
+
+#endif // GOOGLE_APIS_GCM_ENGINE_INSTANCE_ID_GET_TOKEN_REQUEST_HANDLER_H_
diff --git a/google_apis/gcm/engine/registration_info.cc b/google_apis/gcm/engine/registration_info.cc
deleted file mode 100644
index 6a41c76..0000000
--- a/google_apis/gcm/engine/registration_info.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2014 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 "google_apis/gcm/engine/registration_info.h"
-
-#include "base/strings/string_util.h"
-
-namespace gcm {
-
-RegistrationInfo::RegistrationInfo() {
-}
-
-RegistrationInfo::~RegistrationInfo() {
-}
-
-std::string RegistrationInfo::SerializeAsString() const {
- if (sender_ids.empty() || registration_id.empty())
- return std::string();
-
- // Serialize as:
- // sender1,sender2,...=reg_id
- std::string value;
- for (std::vector<std::string>::const_iterator iter = sender_ids.begin();
- iter != sender_ids.end(); ++iter) {
- DCHECK(!iter->empty() &&
- iter->find(',') == std::string::npos &&
- iter->find('=') == std::string::npos);
- if (!value.empty())
- value += ",";
- value += *iter;
- }
-
- DCHECK(registration_id.find('=') == std::string::npos);
- value += '=';
- value += registration_id;
- return value;
-}
-
-bool RegistrationInfo::ParseFromString(const std::string& value) {
- if (value.empty())
- return true;
-
- size_t pos = value.find('=');
- if (pos == std::string::npos)
- return false;
-
- std::string senders = value.substr(0, pos);
- registration_id = value.substr(pos + 1);
-
- Tokenize(senders, ",", &sender_ids);
-
- if (sender_ids.empty() || registration_id.empty()) {
- sender_ids.clear();
- registration_id.clear();
- return false;
- }
-
- return true;
-}
-
-} // namespace gcm
diff --git a/google_apis/gcm/engine/registration_info.h b/google_apis/gcm/engine/registration_info.h
deleted file mode 100644
index c06a6aa..0000000
--- a/google_apis/gcm/engine/registration_info.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2014 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 GOOGLE_APIS_GCM_ENGINE_REGISTRATION_INFO_H_
-#define GOOGLE_APIS_GCM_ENGINE_REGISTRATION_INFO_H_
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/memory/linked_ptr.h"
-#include "google_apis/gcm/base/gcm_export.h"
-
-namespace gcm {
-
-struct GCM_EXPORT RegistrationInfo {
- RegistrationInfo();
- ~RegistrationInfo();
-
- std::string SerializeAsString() const;
- bool ParseFromString(const std::string& value);
-
- std::vector<std::string> sender_ids;
- std::string registration_id;
-};
-
-// Map of app id to registration info.
-typedef std::map<std::string, linked_ptr<RegistrationInfo> >
-RegistrationInfoMap;
-
-} // namespace gcm
-
-#endif // GOOGLE_APIS_GCM_ENGINE_REGISTRATION_INFO_H_
diff --git a/google_apis/gcm/engine/registration_request.cc b/google_apis/gcm/engine/registration_request.cc
index 2e52fba..b30bc4c 100644
--- a/google_apis/gcm/engine/registration_request.cc
+++ b/google_apis/gcm/engine/registration_request.cc
@@ -9,8 +9,8 @@
#include "base/metrics/histogram.h"
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
+#include "google_apis/gcm/base/gcm_util.h"
#include "google_apis/gcm/monitoring/gcm_stats_recorder.h"
-#include "net/base/escape.h"
#include "net/base/load_flags.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_status_code.h"
@@ -30,10 +30,6 @@ const char kRegistrationRequestContentType[] =
const char kAppIdKey[] = "app";
const char kDeviceIdKey[] = "device";
const char kLoginHeader[] = "AidLogin";
-const char kSenderKey[] = "sender";
-
-// Request validation constants.
-const size_t kMaxSenders = 100;
// Response constants.
const char kErrorPrefix[] = "Error=";
@@ -43,14 +39,6 @@ const char kAuthenticationFailed[] = "AUTHENTICATION_FAILED";
const char kInvalidSender[] = "INVALID_SENDER";
const char kInvalidParameters[] = "INVALID_PARAMETERS";
-void BuildFormEncoding(const std::string& key,
- const std::string& value,
- std::string* out) {
- if (!out->empty())
- out->append("&");
- out->append(key + "=" + net::EscapeUrlEncodedData(value, true));
-}
-
// Gets correct status from the error message.
RegistrationRequest::Status GetStatusFromError(const std::string& error) {
// TODO(fgorski): Improve error parsing in case there is nore then just an
@@ -87,31 +75,39 @@ void RecordRegistrationStatusToUMA(RegistrationRequest::Status status) {
RegistrationRequest::RequestInfo::RequestInfo(
uint64 android_id,
uint64 security_token,
- const std::string& app_id,
- const std::vector<std::string>& sender_ids)
+ const std::string& app_id)
: android_id(android_id),
security_token(security_token),
- app_id(app_id),
- sender_ids(sender_ids) {
+ app_id(app_id) {
+ DCHECK(android_id != 0UL);
+ DCHECK(security_token != 0UL);
}
RegistrationRequest::RequestInfo::~RequestInfo() {}
+RegistrationRequest::CustomRequestHandler::CustomRequestHandler() {}
+
+RegistrationRequest::CustomRequestHandler::~CustomRequestHandler() {}
+
RegistrationRequest::RegistrationRequest(
const GURL& registration_url,
const RequestInfo& request_info,
+ scoped_ptr<CustomRequestHandler> custom_request_handler,
const net::BackoffEntry::Policy& backoff_policy,
const RegistrationCallback& callback,
int max_retry_count,
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
- GCMStatsRecorder* recorder)
+ GCMStatsRecorder* recorder,
+ const std::string& source_to_record)
: callback_(callback),
request_info_(request_info),
+ custom_request_handler_(custom_request_handler.Pass()),
registration_url_(registration_url),
backoff_entry_(&backoff_policy),
request_context_getter_(request_context_getter),
retries_left_(max_retry_count),
recorder_(recorder),
+ source_to_record_(source_to_record),
weak_ptr_factory_(this) {
DCHECK_GE(max_retry_count, 0);
}
@@ -120,51 +116,49 @@ RegistrationRequest::~RegistrationRequest() {}
void RegistrationRequest::Start() {
DCHECK(!callback_.is_null());
- DCHECK(request_info_.android_id != 0UL);
- DCHECK(request_info_.security_token != 0UL);
- DCHECK(0 < request_info_.sender_ids.size() &&
- request_info_.sender_ids.size() <= kMaxSenders);
-
DCHECK(!url_fetcher_.get());
+
url_fetcher_ =
net::URLFetcher::Create(registration_url_, net::URLFetcher::POST, this);
url_fetcher_->SetRequestContext(request_context_getter_.get());
url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
net::LOAD_DO_NOT_SAVE_COOKIES);
- std::string android_id = base::Uint64ToString(request_info_.android_id);
- std::string auth_header =
- std::string(net::HttpRequestHeaders::kAuthorization) + ": " +
- kLoginHeader + " " + android_id + ":" +
- base::Uint64ToString(request_info_.security_token);
- url_fetcher_->SetExtraRequestHeaders(auth_header);
+ std::string extra_headers;
+ BuildRequestHeaders(&extra_headers);
+ url_fetcher_->SetExtraRequestHeaders(extra_headers);
std::string body;
- BuildFormEncoding(kAppIdKey, request_info_.app_id, &body);
- BuildFormEncoding(kDeviceIdKey, android_id, &body);
-
- std::string senders;
- for (std::vector<std::string>::const_iterator iter =
- request_info_.sender_ids.begin();
- iter != request_info_.sender_ids.end();
- ++iter) {
- DCHECK(!iter->empty());
- if (!senders.empty())
- senders.append(",");
- senders.append(*iter);
- }
- BuildFormEncoding(kSenderKey, senders, &body);
- UMA_HISTOGRAM_COUNTS("GCM.RegistrationSenderIdCount",
- request_info_.sender_ids.size());
+ BuildRequestBody(&body);
DVLOG(1) << "Performing registration for: " << request_info_.app_id;
DVLOG(1) << "Registration request: " << body;
url_fetcher_->SetUploadData(kRegistrationRequestContentType, body);
- recorder_->RecordRegistrationSent(request_info_.app_id, senders);
+ recorder_->RecordRegistrationSent(request_info_.app_id, source_to_record_);
request_start_time_ = base::TimeTicks::Now();
url_fetcher_->Start();
}
+void RegistrationRequest::BuildRequestHeaders(std::string* extra_headers) {
+ net::HttpRequestHeaders headers;
+ headers.SetHeader(
+ net::HttpRequestHeaders::kAuthorization,
+ std::string(kLoginHeader) + " " +
+ base::Uint64ToString(request_info_.android_id) + ":" +
+ base::Uint64ToString(request_info_.security_token));
+ *extra_headers = headers.ToString();
+}
+
+void RegistrationRequest::BuildRequestBody(std::string* body) {
+ BuildFormEncoding(kAppIdKey, request_info_.app_id, body);
+ BuildFormEncoding(kDeviceIdKey,
+ base::Uint64ToString(request_info_.android_id),
+ body);
+
+ DCHECK(custom_request_handler_.get());
+ custom_request_handler_->BuildRequestBody(body);
+}
+
void RegistrationRequest::RetryWithBackoff(bool update_backoff) {
if (update_backoff) {
DCHECK_GT(retries_left_, 0);
@@ -237,14 +231,14 @@ void RegistrationRequest::OnURLFetchComplete(const net::URLFetcher* source) {
RecordRegistrationStatusToUMA(status);
recorder_->RecordRegistrationResponse(
request_info_.app_id,
- request_info_.sender_ids,
+ source_to_record_,
status);
if (ShouldRetryWithStatus(status)) {
if (retries_left_ > 0) {
recorder_->RecordRegistrationRetryRequested(
request_info_.app_id,
- request_info_.sender_ids,
+ source_to_record_,
retries_left_);
RetryWithBackoff(true);
return;
@@ -253,7 +247,7 @@ void RegistrationRequest::OnURLFetchComplete(const net::URLFetcher* source) {
status = REACHED_MAX_RETRIES;
recorder_->RecordRegistrationResponse(
request_info_.app_id,
- request_info_.sender_ids,
+ source_to_record_,
status);
RecordRegistrationStatusToUMA(status);
}
diff --git a/google_apis/gcm/engine/registration_request.h b/google_apis/gcm/engine/registration_request.h
index 1f707b9..c4c3ae7 100644
--- a/google_apis/gcm/engine/registration_request.h
+++ b/google_apis/gcm/engine/registration_request.h
@@ -6,6 +6,7 @@
#define GOOGLE_APIS_GCM_ENGINE_REGISTRATION_REQUEST_H_
#include <map>
+#include <string>
#include <vector>
#include "base/basictypes.h"
@@ -59,14 +60,12 @@ class GCM_EXPORT RegistrationRequest : public net::URLFetcherDelegate {
const std::string& registration_id)>
RegistrationCallback;
- // Details of the of the Registration Request. Only user's android ID and
- // its serial number are optional and can be set to 0. All other parameters
- // have to be specified to successfully complete the call.
+ // Defines the common info about a registration/token request. All parameters
+ // are mandatory.
struct GCM_EXPORT RequestInfo {
RequestInfo(uint64 android_id,
uint64 security_token,
- const std::string& app_id,
- const std::vector<std::string>& sender_ids);
+ const std::string& app_id);
~RequestInfo();
// Android ID of the device.
@@ -75,20 +74,31 @@ class GCM_EXPORT RegistrationRequest : public net::URLFetcherDelegate {
uint64 security_token;
// Application ID.
std::string app_id;
- // Certificate of the application.
- std::string cert;
- // List of IDs of senders. Allowed up to 100.
- std::vector<std::string> sender_ids;
+ };
+
+ // Encapsulates the custom logic that is needed to build and process the
+ // registration request.
+ class GCM_EXPORT CustomRequestHandler {
+ public:
+ CustomRequestHandler();
+ virtual ~CustomRequestHandler();
+
+ // Builds the HTTP request body data. It is called after
+ // RegistrationRequest::BuildRequestBody to append more custom info to
+ // |body|. Note that the request body is encoded in HTTP form format.
+ virtual void BuildRequestBody(std::string* body) = 0;
};
RegistrationRequest(
const GURL& registration_url,
const RequestInfo& request_info,
+ scoped_ptr<CustomRequestHandler> custom_request_handler,
const net::BackoffEntry::Policy& backoff_policy,
const RegistrationCallback& callback,
int max_retry_count,
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
- GCMStatsRecorder* recorder);
+ GCMStatsRecorder* recorder,
+ const std::string& source_to_record);
~RegistrationRequest() override;
void Start();
@@ -101,12 +111,16 @@ class GCM_EXPORT RegistrationRequest : public net::URLFetcherDelegate {
// failure, when |update_backoff| is true.
void RetryWithBackoff(bool update_backoff);
+ void BuildRequestHeaders(std::string* extra_headers);
+ void BuildRequestBody(std::string* body);
+
// Parse the response returned by the URL fetcher into token, and returns the
// status.
Status ParseResponse(const net::URLFetcher* source, std::string* token);
RegistrationCallback callback_;
RequestInfo request_info_;
+ scoped_ptr<CustomRequestHandler> custom_request_handler_;
GURL registration_url_;
net::BackoffEntry backoff_entry_;
@@ -117,6 +131,7 @@ class GCM_EXPORT RegistrationRequest : public net::URLFetcherDelegate {
// Recorder that records GCM activities for debugging purpose. Not owned.
GCMStatsRecorder* recorder_;
+ std::string source_to_record_;
base::WeakPtrFactory<RegistrationRequest> weak_ptr_factory_;
diff --git a/google_apis/gcm/engine/registration_request_unittest.cc b/google_apis/gcm/engine/registration_request_unittest.cc
index b808f39..d85eeea 100644
--- a/google_apis/gcm/engine/registration_request_unittest.cc
+++ b/google_apis/gcm/engine/registration_request_unittest.cc
@@ -8,7 +8,8 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_tokenizer.h"
-#include "google_apis/gcm/engine/registration_request.h"
+#include "google_apis/gcm/engine/gcm_registration_request_handler.h"
+#include "google_apis/gcm/engine/instance_id_get_token_request_handler.h"
#include "google_apis/gcm/monitoring/fake_gcm_stats_recorder.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_status.h"
@@ -24,6 +25,9 @@ const char kDeveloperId[] = "Project1";
const char kLoginHeader[] = "AidLogin";
const char kRegistrationURL[] = "http://foo.bar/register";
const uint64 kSecurityToken = 77UL;
+const int kGCMVersion = 40;
+const char kInstanceId[] = "IID1";
+const char kScope[] = "GCM";
// Backoff policy for testing registration request.
const net::BackoffEntry::Policy kDefaultBackoffPolicy = {
@@ -64,7 +68,6 @@ class RegistrationRequestTest : public testing::Test {
void RegistrationCallback(RegistrationRequest::Status status,
const std::string& registration_id);
- void CreateRequest(const std::string& sender_ids);
void SetResponseStatusAndString(net::HttpStatusCode status_code,
const std::string& response_body);
void CompleteFetch();
@@ -102,26 +105,6 @@ void RegistrationRequestTest::RegistrationCallback(
callback_called_ = true;
}
-void RegistrationRequestTest::CreateRequest(const std::string& sender_ids) {
- std::vector<std::string> senders;
- base::StringTokenizer tokenizer(sender_ids, ",");
- while (tokenizer.GetNext())
- senders.push_back(tokenizer.token());
-
- request_.reset(new RegistrationRequest(
- GURL(kRegistrationURL),
- RegistrationRequest::RequestInfo(kAndroidId,
- kSecurityToken,
- kAppId,
- senders),
- kDefaultBackoffPolicy,
- base::Bind(&RegistrationRequestTest::RegistrationCallback,
- base::Unretained(this)),
- max_retry_count_,
- url_request_context_getter_.get(),
- &recorder_));
-}
-
void RegistrationRequestTest::SetResponseStatusAndString(
net::HttpStatusCode status_code,
const std::string& response_body) {
@@ -141,7 +124,39 @@ void RegistrationRequestTest::CompleteFetch() {
fetcher->delegate()->OnURLFetchComplete(fetcher);
}
-TEST_F(RegistrationRequestTest, RequestSuccessful) {
+class GCMRegistrationRequestTest : public RegistrationRequestTest {
+ public:
+ GCMRegistrationRequestTest();
+ ~GCMRegistrationRequestTest() override;
+
+ void CreateRequest(const std::string& sender_ids);
+};
+
+GCMRegistrationRequestTest::GCMRegistrationRequestTest() {
+}
+
+GCMRegistrationRequestTest::~GCMRegistrationRequestTest() {
+}
+
+void GCMRegistrationRequestTest::CreateRequest(const std::string& sender_ids) {
+ RegistrationRequest::RequestInfo request_info(
+ kAndroidId, kSecurityToken, kAppId);
+ scoped_ptr<GCMRegistrationRequestHandler> request_handler(
+ new GCMRegistrationRequestHandler(sender_ids));
+ request_.reset(new RegistrationRequest(
+ GURL(kRegistrationURL),
+ request_info,
+ request_handler.Pass(),
+ kDefaultBackoffPolicy,
+ base::Bind(&RegistrationRequestTest::RegistrationCallback,
+ base::Unretained(this)),
+ max_retry_count_,
+ url_request_context_getter_.get(),
+ &recorder_,
+ sender_ids));
+}
+
+TEST_F(GCMRegistrationRequestTest, RequestSuccessful) {
set_max_retry_count(0);
CreateRequest("sender1,sender2");
request_->Start();
@@ -154,7 +169,7 @@ TEST_F(RegistrationRequestTest, RequestSuccessful) {
EXPECT_EQ("2501", registration_id_);
}
-TEST_F(RegistrationRequestTest, RequestDataAndURL) {
+TEST_F(GCMRegistrationRequestTest, RequestDataAndURL) {
CreateRequest(kDeveloperId);
request_->Start();
@@ -198,7 +213,7 @@ TEST_F(RegistrationRequestTest, RequestDataAndURL) {
EXPECT_EQ(0UL, expected_pairs.size());
}
-TEST_F(RegistrationRequestTest, RequestRegistrationWithMultipleSenderIds) {
+TEST_F(GCMRegistrationRequestTest, RequestRegistrationWithMultipleSenderIds) {
CreateRequest("sender1,sender2@gmail.com");
request_->Start();
@@ -223,7 +238,7 @@ TEST_F(RegistrationRequestTest, RequestRegistrationWithMultipleSenderIds) {
EXPECT_EQ("sender2@gmail.com", sender_tokenizer.token());
}
-TEST_F(RegistrationRequestTest, ResponseParsing) {
+TEST_F(GCMRegistrationRequestTest, ResponseParsing) {
CreateRequest("sender1,sender2");
request_->Start();
@@ -235,7 +250,7 @@ TEST_F(RegistrationRequestTest, ResponseParsing) {
EXPECT_EQ("2501", registration_id_);
}
-TEST_F(RegistrationRequestTest, ResponseHttpStatusNotOK) {
+TEST_F(GCMRegistrationRequestTest, ResponseHttpStatusNotOK) {
CreateRequest("sender1,sender2");
request_->Start();
@@ -252,7 +267,7 @@ TEST_F(RegistrationRequestTest, ResponseHttpStatusNotOK) {
EXPECT_EQ("2501", registration_id_);
}
-TEST_F(RegistrationRequestTest, ResponseMissingRegistrationId) {
+TEST_F(GCMRegistrationRequestTest, ResponseMissingRegistrationId) {
CreateRequest("sender1,sender2");
request_->Start();
@@ -275,7 +290,7 @@ TEST_F(RegistrationRequestTest, ResponseMissingRegistrationId) {
EXPECT_EQ("2501", registration_id_);
}
-TEST_F(RegistrationRequestTest, ResponseDeviceRegistrationError) {
+TEST_F(GCMRegistrationRequestTest, ResponseDeviceRegistrationError) {
CreateRequest("sender1,sender2");
request_->Start();
@@ -293,7 +308,7 @@ TEST_F(RegistrationRequestTest, ResponseDeviceRegistrationError) {
EXPECT_EQ("2501", registration_id_);
}
-TEST_F(RegistrationRequestTest, ResponseAuthenticationError) {
+TEST_F(GCMRegistrationRequestTest, ResponseAuthenticationError) {
CreateRequest("sender1,sender2");
request_->Start();
@@ -312,7 +327,7 @@ TEST_F(RegistrationRequestTest, ResponseAuthenticationError) {
EXPECT_EQ("2501", registration_id_);
}
-TEST_F(RegistrationRequestTest, ResponseInvalidParameters) {
+TEST_F(GCMRegistrationRequestTest, ResponseInvalidParameters) {
CreateRequest("sender1,sender2");
request_->Start();
@@ -324,7 +339,7 @@ TEST_F(RegistrationRequestTest, ResponseInvalidParameters) {
EXPECT_EQ(std::string(), registration_id_);
}
-TEST_F(RegistrationRequestTest, ResponseInvalidSender) {
+TEST_F(GCMRegistrationRequestTest, ResponseInvalidSender) {
CreateRequest("sender1,sender2");
request_->Start();
@@ -336,7 +351,7 @@ TEST_F(RegistrationRequestTest, ResponseInvalidSender) {
EXPECT_EQ(std::string(), registration_id_);
}
-TEST_F(RegistrationRequestTest, ResponseInvalidSenderBadRequest) {
+TEST_F(GCMRegistrationRequestTest, ResponseInvalidSenderBadRequest) {
CreateRequest("sender1");
request_->Start();
@@ -348,7 +363,7 @@ TEST_F(RegistrationRequestTest, ResponseInvalidSenderBadRequest) {
EXPECT_EQ(std::string(), registration_id_);
}
-TEST_F(RegistrationRequestTest, RequestNotSuccessful) {
+TEST_F(GCMRegistrationRequestTest, RequestNotSuccessful) {
CreateRequest("sender1,sender2");
request_->Start();
@@ -371,7 +386,7 @@ TEST_F(RegistrationRequestTest, RequestNotSuccessful) {
EXPECT_EQ("2501", registration_id_);
}
-TEST_F(RegistrationRequestTest, ResponseHttpNotOk) {
+TEST_F(GCMRegistrationRequestTest, ResponseHttpNotOk) {
CreateRequest("sender1,sender2");
request_->Start();
@@ -389,7 +404,7 @@ TEST_F(RegistrationRequestTest, ResponseHttpNotOk) {
EXPECT_EQ("2501", registration_id_);
}
-TEST_F(RegistrationRequestTest, MaximumAttemptsReachedWithZeroRetries) {
+TEST_F(GCMRegistrationRequestTest, MaximumAttemptsReachedWithZeroRetries) {
set_max_retry_count(0);
CreateRequest("sender1,sender2");
request_->Start();
@@ -402,7 +417,7 @@ TEST_F(RegistrationRequestTest, MaximumAttemptsReachedWithZeroRetries) {
EXPECT_EQ(std::string(), registration_id_);
}
-TEST_F(RegistrationRequestTest, MaximumAttemptsReached) {
+TEST_F(GCMRegistrationRequestTest, MaximumAttemptsReached) {
CreateRequest("sender1,sender2");
request_->Start();
@@ -424,4 +439,128 @@ TEST_F(RegistrationRequestTest, MaximumAttemptsReached) {
EXPECT_EQ(std::string(), registration_id_);
}
+class InstanceIDGetTokenRequestTest : public RegistrationRequestTest {
+ public:
+ InstanceIDGetTokenRequestTest();
+ ~InstanceIDGetTokenRequestTest() override;
+
+ void CreateRequest(const std::string& instance_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const std::map<std::string, std::string>& options);
+};
+
+InstanceIDGetTokenRequestTest::InstanceIDGetTokenRequestTest() {
+}
+
+InstanceIDGetTokenRequestTest::~InstanceIDGetTokenRequestTest() {
+}
+
+void InstanceIDGetTokenRequestTest::CreateRequest(
+ const std::string& instance_id,
+ const std::string& authorized_entity,
+ const std::string& scope,
+ const std::map<std::string, std::string>& options) {
+ RegistrationRequest::RequestInfo request_info(
+ kAndroidId, kSecurityToken, kAppId);
+ scoped_ptr<InstanceIDGetTokenRequestHandler> request_handler(
+ new InstanceIDGetTokenRequestHandler(
+ instance_id, authorized_entity, scope, kGCMVersion, options));
+ request_.reset(new RegistrationRequest(
+ GURL(kRegistrationURL),
+ request_info,
+ request_handler.Pass(),
+ kDefaultBackoffPolicy,
+ base::Bind(&RegistrationRequestTest::RegistrationCallback,
+ base::Unretained(this)),
+ max_retry_count_,
+ url_request_context_getter_.get(),
+ &recorder_,
+ authorized_entity));
+}
+
+TEST_F(InstanceIDGetTokenRequestTest, RequestSuccessful) {
+ std::map<std::string, std::string> options;
+ options["Foo"] = "Bar";
+
+ set_max_retry_count(0);
+ CreateRequest(kInstanceId, kDeveloperId, kScope, options);
+ request_->Start();
+
+ SetResponseStatusAndString(net::HTTP_OK, "token=2501");
+ CompleteFetch();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(RegistrationRequest::SUCCESS, status_);
+ EXPECT_EQ("2501", registration_id_);
+}
+
+TEST_F(InstanceIDGetTokenRequestTest, RequestDataAndURL) {
+ std::map<std::string, std::string> options;
+ options["Foo"] = "Bar";
+ CreateRequest(kInstanceId, kDeveloperId, kScope, options);
+ request_->Start();
+
+ // Get data sent by request.
+ net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
+ ASSERT_TRUE(fetcher);
+
+ EXPECT_EQ(GURL(kRegistrationURL), fetcher->GetOriginalURL());
+
+ // Verify that authorization header was put together properly.
+ net::HttpRequestHeaders headers;
+ fetcher->GetExtraRequestHeaders(&headers);
+ std::string auth_header;
+ headers.GetHeader(net::HttpRequestHeaders::kAuthorization, &auth_header);
+ base::StringTokenizer auth_tokenizer(auth_header, " :");
+ ASSERT_TRUE(auth_tokenizer.GetNext());
+ EXPECT_EQ(kLoginHeader, auth_tokenizer.token());
+ ASSERT_TRUE(auth_tokenizer.GetNext());
+ EXPECT_EQ(base::Uint64ToString(kAndroidId), auth_tokenizer.token());
+ ASSERT_TRUE(auth_tokenizer.GetNext());
+ EXPECT_EQ(base::Uint64ToString(kSecurityToken), auth_tokenizer.token());
+
+ std::map<std::string, std::string> expected_pairs;
+ expected_pairs["gmsv"] = base::IntToString(kGCMVersion);
+ expected_pairs["app"] = kAppId;
+ expected_pairs["sender"] = kDeveloperId;
+ expected_pairs["device"] = base::Uint64ToString(kAndroidId);
+ expected_pairs["appid"] = kInstanceId;
+ expected_pairs["scope"] = kScope;
+ expected_pairs["X-Foo"] = "Bar";
+
+ // Verify data was formatted properly.
+ std::string upload_data = fetcher->upload_data();
+ base::StringTokenizer data_tokenizer(upload_data, "&=");
+ while (data_tokenizer.GetNext()) {
+ std::map<std::string, std::string>::iterator iter =
+ expected_pairs.find(data_tokenizer.token());
+ ASSERT_TRUE(iter != expected_pairs.end());
+ ASSERT_TRUE(data_tokenizer.GetNext());
+ EXPECT_EQ(iter->second, data_tokenizer.token());
+ // Ensure that none of the keys appears twice.
+ expected_pairs.erase(iter);
+ }
+
+ EXPECT_EQ(0UL, expected_pairs.size());
+}
+
+TEST_F(InstanceIDGetTokenRequestTest, ResponseHttpStatusNotOK) {
+ std::map<std::string, std::string> options;
+ CreateRequest(kInstanceId, kDeveloperId, kScope, options);
+ request_->Start();
+
+ SetResponseStatusAndString(net::HTTP_UNAUTHORIZED, "token=2501");
+ CompleteFetch();
+
+ EXPECT_FALSE(callback_called_);
+
+ SetResponseStatusAndString(net::HTTP_OK, "token=2501");
+ CompleteFetch();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(RegistrationRequest::SUCCESS, status_);
+ EXPECT_EQ("2501", registration_id_);
+}
+
} // namespace gcm
diff --git a/google_apis/gcm/engine/unregistration_request.cc b/google_apis/gcm/engine/unregistration_request.cc
index 9b33778..931a5e9 100644
--- a/google_apis/gcm/engine/unregistration_request.cc
+++ b/google_apis/gcm/engine/unregistration_request.cc
@@ -10,6 +10,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/values.h"
+#include "google_apis/gcm/base/gcm_util.h"
#include "google_apis/gcm/monitoring/gcm_stats_recorder.h"
#include "net/base/escape.h"
#include "net/http/http_request_headers.h"
@@ -30,71 +31,6 @@ const char kDeleteKey[] = "delete";
const char kDeleteValue[] = "true";
const char kDeviceIdKey[] = "device";
const char kLoginHeader[] = "AidLogin";
-const char kUnregistrationCallerKey[] = "gcm_unreg_caller";
-// We are going to set the value to "false" in order to forcefully unregister
-// the application.
-const char kUnregistrationCallerValue[] = "false";
-
-// Response constants.
-const char kDeletedPrefix[] = "deleted=";
-const char kErrorPrefix[] = "Error=";
-const char kInvalidParameters[] = "INVALID_PARAMETERS";
-
-
-void BuildFormEncoding(const std::string& key,
- const std::string& value,
- std::string* out) {
- if (!out->empty())
- out->append("&");
- out->append(key + "=" + net::EscapeUrlEncodedData(value, true));
-}
-
-UnregistrationRequest::Status ParseFetcherResponse(
- const net::URLFetcher* source,
- std::string request_app_id) {
- if (!source->GetStatus().is_success()) {
- DVLOG(1) << "Fetcher failed";
- return UnregistrationRequest::URL_FETCHING_FAILED;
- }
-
- net::HttpStatusCode response_status = static_cast<net::HttpStatusCode>(
- source->GetResponseCode());
- if (response_status != net::HTTP_OK) {
- DVLOG(1) << "HTTP Status code is not OK, but: " << response_status;
- if (response_status == net::HTTP_SERVICE_UNAVAILABLE)
- return UnregistrationRequest::SERVICE_UNAVAILABLE;
- else if (response_status == net::HTTP_INTERNAL_SERVER_ERROR)
- return UnregistrationRequest::INTERNAL_SERVER_ERROR;
- return UnregistrationRequest::HTTP_NOT_OK;
- }
-
- std::string response;
- if (!source->GetResponseAsString(&response)) {
- DVLOG(1) << "Failed to get response body.";
- return UnregistrationRequest::NO_RESPONSE_BODY;
- }
-
- DVLOG(1) << "Parsing unregistration response.";
- if (response.find(kDeletedPrefix) != std::string::npos) {
- std::string app_id = response.substr(
- response.find(kDeletedPrefix) + arraysize(kDeletedPrefix) - 1);
- if (app_id == request_app_id)
- return UnregistrationRequest::SUCCESS;
- return UnregistrationRequest::INCORRECT_APP_ID;
- }
-
- if (response.find(kErrorPrefix) != std::string::npos) {
- std::string error = response.substr(
- response.find(kErrorPrefix) + arraysize(kErrorPrefix) - 1);
- if (error == kInvalidParameters)
- return UnregistrationRequest::INVALID_PARAMETERS;
- return UnregistrationRequest::UNKNOWN_ERROR;
- }
-
- DVLOG(1) << "Not able to parse a meaningful output from response body."
- << response;
- return UnregistrationRequest::RESPONSE_PARSING_FAILED;
-}
} // namespace
@@ -105,19 +41,27 @@ UnregistrationRequest::RequestInfo::RequestInfo(
: android_id(android_id),
security_token(security_token),
app_id(app_id) {
+ DCHECK(android_id != 0UL);
+ DCHECK(security_token != 0UL);
}
UnregistrationRequest::RequestInfo::~RequestInfo() {}
+UnregistrationRequest::CustomRequestHandler::CustomRequestHandler() {}
+
+UnregistrationRequest::CustomRequestHandler::~CustomRequestHandler() {}
+
UnregistrationRequest::UnregistrationRequest(
const GURL& registration_url,
const RequestInfo& request_info,
+ scoped_ptr<CustomRequestHandler> custom_request_handler,
const net::BackoffEntry::Policy& backoff_policy,
const UnregistrationCallback& callback,
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
GCMStatsRecorder* recorder)
: callback_(callback),
request_info_(request_info),
+ custom_request_handler_(custom_request_handler.Pass()),
registration_url_(registration_url),
backoff_entry_(&backoff_policy),
request_context_getter_(request_context_getter),
@@ -129,30 +73,18 @@ UnregistrationRequest::~UnregistrationRequest() {}
void UnregistrationRequest::Start() {
DCHECK(!callback_.is_null());
- DCHECK(request_info_.android_id != 0UL);
- DCHECK(request_info_.security_token != 0UL);
DCHECK(!url_fetcher_.get());
url_fetcher_ =
net::URLFetcher::Create(registration_url_, net::URLFetcher::POST, this);
url_fetcher_->SetRequestContext(request_context_getter_.get());
- std::string android_id = base::Uint64ToString(request_info_.android_id);
- std::string auth_header =
- std::string(kLoginHeader) + " " + android_id + ":" +
- base::Uint64ToString(request_info_.security_token);
- net::HttpRequestHeaders headers;
- headers.SetHeader(net::HttpRequestHeaders::kAuthorization, auth_header);
- headers.SetHeader(kAppIdKey, request_info_.app_id);
- url_fetcher_->SetExtraRequestHeaders(headers.ToString());
+ std::string extra_headers;
+ BuildRequestHeaders(&extra_headers);
+ url_fetcher_->SetExtraRequestHeaders(extra_headers);
std::string body;
- BuildFormEncoding(kAppIdKey, request_info_.app_id, &body);
- BuildFormEncoding(kDeviceIdKey, android_id, &body);
- BuildFormEncoding(kDeleteKey, kDeleteValue, &body);
- BuildFormEncoding(kUnregistrationCallerKey,
- kUnregistrationCallerValue,
- &body);
+ BuildRequestBody(&body);
DVLOG(1) << "Unregistration request: " << body;
url_fetcher_->SetUploadData(kRequestContentType, body);
@@ -163,6 +95,50 @@ void UnregistrationRequest::Start() {
url_fetcher_->Start();
}
+void UnregistrationRequest::BuildRequestHeaders(std::string* extra_headers) {
+ net::HttpRequestHeaders headers;
+ headers.SetHeader(
+ net::HttpRequestHeaders::kAuthorization,
+ std::string(kLoginHeader) + " " +
+ base::Uint64ToString(request_info_.android_id) + ":" +
+ base::Uint64ToString(request_info_.security_token));
+ headers.SetHeader(kAppIdKey, request_info_.app_id);
+ *extra_headers = headers.ToString();
+}
+
+void UnregistrationRequest::BuildRequestBody(std::string* body) {
+ BuildFormEncoding(kAppIdKey, request_info_.app_id, body);
+ BuildFormEncoding(kDeviceIdKey,
+ base::Uint64ToString(request_info_.android_id),
+ body);
+ BuildFormEncoding(kDeleteKey, kDeleteValue, body);
+
+ DCHECK(custom_request_handler_.get());
+ custom_request_handler_->BuildRequestBody(body);
+}
+
+UnregistrationRequest::Status UnregistrationRequest::ParseResponse(
+ const net::URLFetcher* source) {
+ if (!source->GetStatus().is_success()) {
+ DVLOG(1) << "Fetcher failed";
+ return URL_FETCHING_FAILED;
+ }
+
+ net::HttpStatusCode response_status = static_cast<net::HttpStatusCode>(
+ source->GetResponseCode());
+ if (response_status != net::HTTP_OK) {
+ DVLOG(1) << "HTTP Status code is not OK, but: " << response_status;
+ if (response_status == net::HTTP_SERVICE_UNAVAILABLE)
+ return SERVICE_UNAVAILABLE;
+ if (response_status == net::HTTP_INTERNAL_SERVER_ERROR)
+ return INTERNAL_SERVER_ERROR;
+ return HTTP_NOT_OK;
+ }
+
+ DCHECK(custom_request_handler_.get());
+ return custom_request_handler_->ParseResponse(source);
+}
+
void UnregistrationRequest::RetryWithBackoff(bool update_backoff) {
if (update_backoff) {
url_fetcher_.reset();
@@ -190,8 +166,7 @@ void UnregistrationRequest::RetryWithBackoff(bool update_backoff) {
}
void UnregistrationRequest::OnURLFetchComplete(const net::URLFetcher* source) {
- UnregistrationRequest::Status status =
- ParseFetcherResponse(source, request_info_.app_id);
+ UnregistrationRequest::Status status = ParseResponse(source);
DVLOG(1) << "UnregistrationRequestStauts: " << status;
UMA_HISTOGRAM_ENUMERATION("GCM.UnregistrationRequestStatus",
diff --git a/google_apis/gcm/engine/unregistration_request.h b/google_apis/gcm/engine/unregistration_request.h
index c5c0eb5..61d9bff2 100644
--- a/google_apis/gcm/engine/unregistration_request.h
+++ b/google_apis/gcm/engine/unregistration_request.h
@@ -24,9 +24,9 @@ namespace gcm {
class GCMStatsRecorder;
-// Unregistration request is used to revoke registration IDs for applications
-// that were uninstalled and should no longer receive GCM messages. In case an
-// attempt to unregister fails, it will retry using the backoff policy.
+// Encapsulates the common logic applying to both GCM unregistration requests
+// and InstanceID delete-token requests. In case an attempt fails, it will retry
+// using the backoff policy.
// TODO(fgorski): Consider sharing code with RegistrationRequest if possible.
class GCM_EXPORT UnregistrationRequest : public net::URLFetcherDelegate {
public:
@@ -55,7 +55,8 @@ class GCM_EXPORT UnregistrationRequest : public net::URLFetcherDelegate {
// Callback completing the unregistration request.
typedef base::Callback<void(Status success)> UnregistrationCallback;
- // Details of the of the Unregistration Request. All parameters are mandatory.
+ // Defines the common info about an unregistration/token-deletion request.
+ // All parameters are mandatory.
struct GCM_EXPORT RequestInfo {
RequestInfo(uint64 android_id,
uint64 security_token,
@@ -70,12 +71,30 @@ class GCM_EXPORT UnregistrationRequest : public net::URLFetcherDelegate {
std::string app_id;
};
+ // Encapsulates the custom logic that is needed to build and process the
+ // unregistration request.
+ class GCM_EXPORT CustomRequestHandler {
+ public:
+ CustomRequestHandler();
+ virtual ~CustomRequestHandler();
+
+ // Builds the HTTP request body data. It is called after
+ // UnregistrationRequest::BuildRequestBody to append more custom info to
+ // |body|. Note that the request body is encoded in HTTP form format.
+ virtual void BuildRequestBody(std::string* body) = 0;
+
+ // Parses the HTTP response. It is called after
+ // UnregistrationRequest::ParseResponse to proceed the parsing.
+ virtual Status ParseResponse(const net::URLFetcher* source) = 0;
+ };
+
// Creates an instance of UnregistrationRequest. |callback| will be called
// once registration has been revoked or there has been an error that makes
// further retries pointless.
UnregistrationRequest(
const GURL& registration_url,
const RequestInfo& request_info,
+ scoped_ptr<CustomRequestHandler> custom_request_handler,
const net::BackoffEntry::Policy& backoff_policy,
const UnregistrationCallback& callback,
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
@@ -85,16 +104,21 @@ class GCM_EXPORT UnregistrationRequest : public net::URLFetcherDelegate {
// Starts an unregistration request.
void Start();
+ private:
// URLFetcherDelegate implementation.
void OnURLFetchComplete(const net::URLFetcher* source) override;
- private:
+ void BuildRequestHeaders(std::string* extra_headers);
+ void BuildRequestBody(std::string* body);
+ Status ParseResponse(const net::URLFetcher* source);
+
// Schedules a retry attempt and informs the backoff of previous request's
// failure, when |update_backoff| is true.
void RetryWithBackoff(bool update_backoff);
UnregistrationCallback callback_;
RequestInfo request_info_;
+ scoped_ptr<CustomRequestHandler> custom_request_handler_;
GURL registration_url_;
net::BackoffEntry backoff_entry_;
diff --git a/google_apis/gcm/engine/unregistration_request_unittest.cc b/google_apis/gcm/engine/unregistration_request_unittest.cc
index 1c736de..9e60297 100644
--- a/google_apis/gcm/engine/unregistration_request_unittest.cc
+++ b/google_apis/gcm/engine/unregistration_request_unittest.cc
@@ -8,7 +8,8 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_tokenizer.h"
-#include "google_apis/gcm/engine/unregistration_request.h"
+#include "google_apis/gcm/engine/gcm_unregistration_request_handler.h"
+#include "google_apis/gcm/engine/instance_id_delete_token_request_handler.h"
#include "google_apis/gcm/monitoring/fake_gcm_stats_recorder.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_test_util.h"
@@ -21,8 +22,13 @@ const uint64 kAndroidId = 42UL;
const char kLoginHeader[] = "AidLogin";
const char kAppId[] = "TestAppId";
const char kDeletedAppId[] = "deleted=TestAppId";
+const char kDeletedToken[] = "token=SomeToken";
const char kRegistrationURL[] = "http://foo.bar/register";
const uint64 kSecurityToken = 77UL;
+const int kGCMVersion = 40;
+const char kInstanceId[] = "IID1";
+const char kDeveloperId[] = "Project1";
+const char kScope[] = "GCM";
// Backoff policy for testing registration request.
const net::BackoffEntry::Policy kDefaultBackoffPolicy = {
@@ -61,7 +67,6 @@ class UnregistrationRequestTest : public testing::Test {
void UnregistrationCallback(UnregistrationRequest::Status status);
- void CreateRequest();
void SetResponseStatusAndString(net::HttpStatusCode status_code,
const std::string& response_body);
void CompleteFetch();
@@ -90,19 +95,6 @@ void UnregistrationRequestTest::UnregistrationCallback(
status_ = status;
}
-void UnregistrationRequestTest::CreateRequest() {
- request_.reset(new UnregistrationRequest(
- GURL(kRegistrationURL),
- UnregistrationRequest::RequestInfo(kAndroidId,
- kSecurityToken,
- kAppId),
- kDefaultBackoffPolicy,
- base::Bind(&UnregistrationRequestTest::UnregistrationCallback,
- base::Unretained(this)),
- url_request_context_getter_.get(),
- &recorder_));
-}
-
void UnregistrationRequestTest::SetResponseStatusAndString(
net::HttpStatusCode status_code,
const std::string& response_body) {
@@ -120,7 +112,37 @@ void UnregistrationRequestTest::CompleteFetch() {
fetcher->delegate()->OnURLFetchComplete(fetcher);
}
-TEST_F(UnregistrationRequestTest, RequestDataPassedToFetcher) {
+class GCMUnregistrationRequestTest : public UnregistrationRequestTest {
+ public:
+ GCMUnregistrationRequestTest();
+ ~GCMUnregistrationRequestTest() override;
+
+ void CreateRequest();
+};
+
+GCMUnregistrationRequestTest::GCMUnregistrationRequestTest() {
+}
+
+GCMUnregistrationRequestTest::~GCMUnregistrationRequestTest() {
+}
+
+void GCMUnregistrationRequestTest::CreateRequest() {
+ UnregistrationRequest::RequestInfo request_info(
+ kAndroidId, kSecurityToken, kAppId);
+ scoped_ptr<GCMUnregistrationRequestHandler> request_handler(
+ new GCMUnregistrationRequestHandler(kAppId));
+ request_.reset(new UnregistrationRequest(
+ GURL(kRegistrationURL),
+ request_info,
+ request_handler.Pass(),
+ kDefaultBackoffPolicy,
+ base::Bind(&UnregistrationRequestTest::UnregistrationCallback,
+ base::Unretained(this)),
+ url_request_context_getter_.get(),
+ &recorder_));
+}
+
+TEST_F(GCMUnregistrationRequestTest, RequestDataPassedToFetcher) {
CreateRequest();
request_->Start();
@@ -168,7 +190,7 @@ TEST_F(UnregistrationRequestTest, RequestDataPassedToFetcher) {
EXPECT_EQ(0UL, expected_pairs.size());
}
-TEST_F(UnregistrationRequestTest, SuccessfulUnregistration) {
+TEST_F(GCMUnregistrationRequestTest, SuccessfulUnregistration) {
CreateRequest();
request_->Start();
@@ -179,7 +201,7 @@ TEST_F(UnregistrationRequestTest, SuccessfulUnregistration) {
EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
}
-TEST_F(UnregistrationRequestTest, ResponseHttpStatusNotOK) {
+TEST_F(GCMUnregistrationRequestTest, ResponseHttpStatusNotOK) {
CreateRequest();
request_->Start();
@@ -190,7 +212,7 @@ TEST_F(UnregistrationRequestTest, ResponseHttpStatusNotOK) {
EXPECT_EQ(UnregistrationRequest::HTTP_NOT_OK, status_);
}
-TEST_F(UnregistrationRequestTest, ResponseEmpty) {
+TEST_F(GCMUnregistrationRequestTest, ResponseEmpty) {
CreateRequest();
request_->Start();
@@ -206,7 +228,7 @@ TEST_F(UnregistrationRequestTest, ResponseEmpty) {
EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
}
-TEST_F(UnregistrationRequestTest, InvalidParametersError) {
+TEST_F(GCMUnregistrationRequestTest, InvalidParametersError) {
CreateRequest();
request_->Start();
@@ -217,7 +239,7 @@ TEST_F(UnregistrationRequestTest, InvalidParametersError) {
EXPECT_EQ(UnregistrationRequest::INVALID_PARAMETERS, status_);
}
-TEST_F(UnregistrationRequestTest, UnkwnownError) {
+TEST_F(GCMUnregistrationRequestTest, UnkwnownError) {
CreateRequest();
request_->Start();
@@ -228,7 +250,7 @@ TEST_F(UnregistrationRequestTest, UnkwnownError) {
EXPECT_EQ(UnregistrationRequest::UNKNOWN_ERROR, status_);
}
-TEST_F(UnregistrationRequestTest, ServiceUnavailable) {
+TEST_F(GCMUnregistrationRequestTest, ServiceUnavailable) {
CreateRequest();
request_->Start();
@@ -244,7 +266,7 @@ TEST_F(UnregistrationRequestTest, ServiceUnavailable) {
EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
}
-TEST_F(UnregistrationRequestTest, InternalServerError) {
+TEST_F(GCMUnregistrationRequestTest, InternalServerError) {
CreateRequest();
request_->Start();
@@ -260,7 +282,7 @@ TEST_F(UnregistrationRequestTest, InternalServerError) {
EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
}
-TEST_F(UnregistrationRequestTest, IncorrectAppId) {
+TEST_F(GCMUnregistrationRequestTest, IncorrectAppId) {
CreateRequest();
request_->Start();
@@ -276,7 +298,7 @@ TEST_F(UnregistrationRequestTest, IncorrectAppId) {
EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
}
-TEST_F(UnregistrationRequestTest, ResponseParsingFailed) {
+TEST_F(GCMUnregistrationRequestTest, ResponseParsingFailed) {
CreateRequest();
request_->Start();
@@ -292,4 +314,113 @@ TEST_F(UnregistrationRequestTest, ResponseParsingFailed) {
EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
}
+class InstaceIDDeleteTokenRequestTest : public UnregistrationRequestTest {
+ public:
+ InstaceIDDeleteTokenRequestTest();
+ ~InstaceIDDeleteTokenRequestTest() override;
+
+ void CreateRequest(const std::string& instance_id,
+ const std::string& authorized_entity,
+ const std::string& scope);
+};
+
+InstaceIDDeleteTokenRequestTest::InstaceIDDeleteTokenRequestTest() {
+}
+
+InstaceIDDeleteTokenRequestTest::~InstaceIDDeleteTokenRequestTest() {
+}
+
+void InstaceIDDeleteTokenRequestTest::CreateRequest(
+ const std::string& instance_id,
+ const std::string& authorized_entity,
+ const std::string& scope) {
+ UnregistrationRequest::RequestInfo request_info(
+ kAndroidId, kSecurityToken, kAppId);
+ scoped_ptr<InstanceIDDeleteTokenRequestHandler> request_handler(
+ new InstanceIDDeleteTokenRequestHandler(
+ instance_id, authorized_entity, scope, kGCMVersion));
+ request_.reset(new UnregistrationRequest(
+ GURL(kRegistrationURL),
+ request_info,
+ request_handler.Pass(),
+ kDefaultBackoffPolicy,
+ base::Bind(&UnregistrationRequestTest::UnregistrationCallback,
+ base::Unretained(this)),
+ url_request_context_getter_.get(),
+ &recorder_));
+}
+
+TEST_F(InstaceIDDeleteTokenRequestTest, RequestDataPassedToFetcher) {
+ CreateRequest(kInstanceId, kDeveloperId, kScope);
+ request_->Start();
+
+ // Get data sent by request.
+ net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
+ ASSERT_TRUE(fetcher);
+
+ EXPECT_EQ(GURL(kRegistrationURL), fetcher->GetOriginalURL());
+
+ // Verify that authorization header was put together properly.
+ net::HttpRequestHeaders headers;
+ fetcher->GetExtraRequestHeaders(&headers);
+ std::string auth_header;
+ headers.GetHeader(net::HttpRequestHeaders::kAuthorization, &auth_header);
+ base::StringTokenizer auth_tokenizer(auth_header, " :");
+ ASSERT_TRUE(auth_tokenizer.GetNext());
+ EXPECT_EQ(kLoginHeader, auth_tokenizer.token());
+ ASSERT_TRUE(auth_tokenizer.GetNext());
+ EXPECT_EQ(base::Uint64ToString(kAndroidId), auth_tokenizer.token());
+ ASSERT_TRUE(auth_tokenizer.GetNext());
+ EXPECT_EQ(base::Uint64ToString(kSecurityToken), auth_tokenizer.token());
+ std::string app_id_header;
+ headers.GetHeader("app", &app_id_header);
+ EXPECT_EQ(kAppId, app_id_header);
+
+ std::map<std::string, std::string> expected_pairs;
+ expected_pairs["gmsv"] = base::IntToString(kGCMVersion);
+ expected_pairs["app"] = kAppId;
+ expected_pairs["device"] = base::Uint64ToString(kAndroidId);
+ expected_pairs["delete"] = "true";
+ expected_pairs["appid"] = kInstanceId;
+ expected_pairs["sender"] = kDeveloperId;
+ expected_pairs["scope"] = kScope;
+
+ // Verify data was formatted properly.
+ std::string upload_data = fetcher->upload_data();
+ base::StringTokenizer data_tokenizer(upload_data, "&=");
+ while (data_tokenizer.GetNext()) {
+ std::map<std::string, std::string>::iterator iter =
+ expected_pairs.find(data_tokenizer.token());
+ ASSERT_TRUE(iter != expected_pairs.end()) << data_tokenizer.token();
+ ASSERT_TRUE(data_tokenizer.GetNext()) << data_tokenizer.token();
+ EXPECT_EQ(iter->second, data_tokenizer.token());
+ // Ensure that none of the keys appears twice.
+ expected_pairs.erase(iter);
+ }
+
+ EXPECT_EQ(0UL, expected_pairs.size());
+}
+
+TEST_F(InstaceIDDeleteTokenRequestTest, SuccessfulUnregistration) {
+ CreateRequest(kInstanceId, kDeveloperId, kScope);
+ request_->Start();
+
+ SetResponseStatusAndString(net::HTTP_OK, kDeletedToken);
+ CompleteFetch();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
+}
+
+TEST_F(InstaceIDDeleteTokenRequestTest, ResponseHttpStatusNotOK) {
+ CreateRequest(kInstanceId, kDeveloperId, kScope);
+ request_->Start();
+
+ SetResponseStatusAndString(net::HTTP_UNAUTHORIZED, "");
+ CompleteFetch();
+
+ EXPECT_TRUE(callback_called_);
+ EXPECT_EQ(UnregistrationRequest::HTTP_NOT_OK, status_);
+}
+
} // namespace gcm
diff --git a/google_apis/gcm/gcm.gyp b/google_apis/gcm/gcm.gyp
index 20a63b9..aa9df60 100644
--- a/google_apis/gcm/gcm.gyp
+++ b/google_apis/gcm/gcm.gyp
@@ -39,6 +39,8 @@
],
'sources': [
# Note: sources list duplicated in GN build.
+ 'base/gcm_util.cc',
+ 'base/gcm_util.h',
'base/mcs_message.cc',
'base/mcs_message.h',
'base/mcs_util.cc',
@@ -57,18 +59,24 @@
'engine/connection_handler.h',
'engine/connection_handler_impl.cc',
'engine/connection_handler_impl.h',
+ 'engine/gcm_registration_request_handler.cc',
+ 'engine/gcm_registration_request_handler.h',
'engine/gcm_store.cc',
'engine/gcm_store.h',
'engine/gcm_store_impl.cc',
'engine/gcm_store_impl.h',
+ 'engine/gcm_unregistration_request_handler.cc',
+ 'engine/gcm_unregistration_request_handler.h',
'engine/gservices_settings.cc',
'engine/gservices_settings.h',
'engine/heartbeat_manager.cc',
'engine/heartbeat_manager.h',
+ 'engine/instance_id_delete_token_request_handler.cc',
+ 'engine/instance_id_delete_token_request_handler.h',
+ 'engine/instance_id_get_token_request_handler.cc',
+ 'engine/instance_id_get_token_request_handler.h',
'engine/mcs_client.cc',
'engine/mcs_client.h',
- 'engine/registration_info.cc',
- 'engine/registration_info.h',
'engine/registration_request.cc',
'engine/registration_request.h',
'engine/unregistration_request.cc',
diff --git a/google_apis/gcm/monitoring/fake_gcm_stats_recorder.cc b/google_apis/gcm/monitoring/fake_gcm_stats_recorder.cc
index b324727..0388d24 100644
--- a/google_apis/gcm/monitoring/fake_gcm_stats_recorder.cc
+++ b/google_apis/gcm/monitoring/fake_gcm_stats_recorder.cc
@@ -44,18 +44,18 @@ void FakeGCMStatsRecorder::RecordConnectionResetSignaled(
void FakeGCMStatsRecorder::RecordRegistrationSent(
const std::string& app_id,
- const std::string& sender_ids) {
+ const std::string& senders) {
}
void FakeGCMStatsRecorder::RecordRegistrationResponse(
const std::string& app_id,
- const std::vector<std::string>& sender_ids,
+ const std::string& senders,
RegistrationRequest::Status status) {
}
void FakeGCMStatsRecorder::RecordRegistrationRetryRequested(
const std::string& app_id,
- const std::vector<std::string>& sender_ids,
+ const std::string& senders,
int retries_left) {
}
diff --git a/google_apis/gcm/monitoring/fake_gcm_stats_recorder.h b/google_apis/gcm/monitoring/fake_gcm_stats_recorder.h
index d4503dd..5dcd448 100644
--- a/google_apis/gcm/monitoring/fake_gcm_stats_recorder.h
+++ b/google_apis/gcm/monitoring/fake_gcm_stats_recorder.h
@@ -26,13 +26,13 @@ class FakeGCMStatsRecorder : public GCMStatsRecorder {
void RecordConnectionResetSignaled(
ConnectionFactory::ConnectionResetReason reason) override;
void RecordRegistrationSent(const std::string& app_id,
- const std::string& sender_ids) override;
+ const std::string& senders) override;
void RecordRegistrationResponse(const std::string& app_id,
- const std::vector<std::string>& sender_ids,
+ const std::string& senders,
RegistrationRequest::Status status) override;
void RecordRegistrationRetryRequested(
const std::string& app_id,
- const std::vector<std::string>& sender_ids,
+ const std::string& senders,
int retries_left) override;
void RecordUnregistrationSent(const std::string& app_id) override;
void RecordUnregistrationResponse(
diff --git a/google_apis/gcm/monitoring/gcm_stats_recorder.h b/google_apis/gcm/monitoring/gcm_stats_recorder.h
index 7191569..83367d8 100644
--- a/google_apis/gcm/monitoring/gcm_stats_recorder.h
+++ b/google_apis/gcm/monitoring/gcm_stats_recorder.h
@@ -32,7 +32,7 @@ class GCM_EXPORT GCMStatsRecorder {
// A delegate interface that allows the GCMStatsRecorderImpl instance to
// interact with its container.
class Delegate {
- public:
+ public:
// Called when the GCMStatsRecorderImpl is recording activities and a new
// activity has just been recorded.
virtual void OnActivityRecorded() = 0;
@@ -73,19 +73,19 @@ class GCM_EXPORT GCMStatsRecorder {
// Records that a registration request has been sent. This could be initiated
// directly from API, or from retry logic.
virtual void RecordRegistrationSent(const std::string& app_id,
- const std::string& sender_ids) = 0;
+ const std::string& senders) = 0;
// Records that a registration response has been received from server.
virtual void RecordRegistrationResponse(
const std::string& app_id,
- const std::vector<std::string>& sender_ids,
+ const std::string& senders,
RegistrationRequest::Status status) = 0;
// Records that a registration retry has been requested. The actual retry
// action may not occur until some time later according to backoff logic.
virtual void RecordRegistrationRetryRequested(
const std::string& app_id,
- const std::vector<std::string>& sender_ids,
+ const std::string& senders,
int retries_left) = 0;
// Records that an unregistration request has been sent. This could be