diff options
author | Alexander Tkachev | 2016-07-20 14:44:24 +0600 |
---|---|---|
committer | Alexander Tkachev | 2016-08-24 16:07:55 +0600 |
commit | f743b319633dcd57ea08f5ac86d3daec548d1ab0 (patch) | |
tree | ff02af57d11ce16e01c9adae9df081155f71aee5 /backends | |
parent | 0200694dd050409eec7a30efd8a616ab6b1fdae1 (diff) | |
download | scummvm-rg350-f743b319633dcd57ea08f5ac86d3daec548d1ab0.tar.gz scummvm-rg350-f743b319633dcd57ea08f5ac86d3daec548d1ab0.tar.bz2 scummvm-rg350-f743b319633dcd57ea08f5ac86d3daec548d1ab0.zip |
CLOUD: Fix CloudManager::connectStorage() memory leak
Diffstat (limited to 'backends')
-rw-r--r-- | backends/cloud/box/boxstorage.cpp | 18 | ||||
-rw-r--r-- | backends/cloud/box/boxstorage.h | 3 | ||||
-rw-r--r-- | backends/cloud/cloudmanager.cpp | 20 | ||||
-rw-r--r-- | backends/cloud/cloudmanager.h | 7 | ||||
-rw-r--r-- | backends/cloud/dropbox/dropboxstorage.cpp | 13 | ||||
-rw-r--r-- | backends/cloud/dropbox/dropboxstorage.h | 1 | ||||
-rw-r--r-- | backends/cloud/googledrive/googledrivestorage.cpp | 18 | ||||
-rw-r--r-- | backends/cloud/googledrive/googledrivestorage.h | 3 | ||||
-rw-r--r-- | backends/cloud/onedrive/onedrivestorage.cpp | 18 | ||||
-rw-r--r-- | backends/cloud/onedrive/onedrivestorage.h | 3 |
10 files changed, 89 insertions, 15 deletions
diff --git a/backends/cloud/box/boxstorage.cpp b/backends/cloud/box/boxstorage.cpp index 9e036b1187..8162af299c 100644 --- a/backends/cloud/box/boxstorage.cpp +++ b/backends/cloud/box/boxstorage.cpp @@ -56,12 +56,16 @@ BoxStorage::BoxStorage(Common::String accessToken, Common::String refreshToken): _token(accessToken), _refreshToken(refreshToken) {} BoxStorage::BoxStorage(Common::String code) { - getAccessToken(new Common::Callback<BoxStorage, BoolResponse>(this, &BoxStorage::codeFlowComplete), code); + getAccessToken( + new Common::Callback<BoxStorage, BoolResponse>(this, &BoxStorage::codeFlowComplete), + new Common::Callback<BoxStorage, Networking::ErrorResponse>(this, &BoxStorage::codeFlowFailed), + code + ); } BoxStorage::~BoxStorage() {} -void BoxStorage::getAccessToken(BoolCallback callback, Common::String code) { +void BoxStorage::getAccessToken(BoolCallback callback, Networking::ErrorCallback errorCallback, Common::String code) { if (!KEY || !SECRET) loadKeyAndSecret(); bool codeFlow = (code != ""); @@ -72,7 +76,8 @@ void BoxStorage::getAccessToken(BoolCallback callback, Common::String code) { } Networking::JsonCallback innerCallback = new Common::CallbackBridge<BoxStorage, BoolResponse, Networking::JsonResponse>(this, &BoxStorage::tokenRefreshed, callback); - Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, getErrorPrintingCallback(), "https://api.box.com/oauth2/token"); + if (errorCallback == nullptr) errorCallback = getErrorPrintingCallback(); + Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, errorCallback, "https://api.box.com/oauth2/token"); if (codeFlow) { request->addPostField("grant_type=authorization_code"); request->addPostField("code=" + code); @@ -117,6 +122,7 @@ void BoxStorage::tokenRefreshed(BoolCallback callback, Networking::JsonResponse void BoxStorage::codeFlowComplete(BoolResponse response) { if (!response.value) { warning("BoxStorage: failed to get access token through code flow"); + CloudMan.removeStorage(this); return; } @@ -124,6 +130,12 @@ void BoxStorage::codeFlowComplete(BoolResponse response) { ConfMan.flushToDisk(); } +void BoxStorage::codeFlowFailed(Networking::ErrorResponse error) { + debug("Box's code flow failed (%s, %ld):", (error.failed ? "failed" : "interrupted"), error.httpResponseCode); + debug("%s", error.response.c_str()); + CloudMan.removeStorage(this); +} + void BoxStorage::saveConfig(Common::String keyPrefix) { ConfMan.set(keyPrefix + "access_token", _token, ConfMan.kCloudDomain); ConfMan.set(keyPrefix + "refresh_token", _refreshToken, ConfMan.kCloudDomain); diff --git a/backends/cloud/box/boxstorage.h b/backends/cloud/box/boxstorage.h index 51f2a9591c..826d6bef4e 100644 --- a/backends/cloud/box/boxstorage.h +++ b/backends/cloud/box/boxstorage.h @@ -42,6 +42,7 @@ class BoxStorage: public Id::IdStorage { void tokenRefreshed(BoolCallback callback, Networking::JsonResponse response); void codeFlowComplete(BoolResponse response); + void codeFlowFailed(Networking::ErrorResponse error); /** Constructs StorageInfo based on JSON response from cloud. */ void infoInnerCallback(StorageInfoCallback outerCallback, Networking::JsonResponse json); @@ -108,7 +109,7 @@ public: * Use "" in order to refresh token and pass a callback, so you could * continue your work when new token is available. */ - void getAccessToken(BoolCallback callback, Common::String code = ""); + void getAccessToken(BoolCallback callback, Networking::ErrorCallback errorCallback = nullptr, Common::String code = ""); Common::String accessToken() { return _token; } }; diff --git a/backends/cloud/cloudmanager.cpp b/backends/cloud/cloudmanager.cpp index b6a721be90..8b7230fb5c 100644 --- a/backends/cloud/cloudmanager.cpp +++ b/backends/cloud/cloudmanager.cpp @@ -45,6 +45,7 @@ CloudManager::CloudManager() : _currentStorageIndex(0), _activeStorage(nullptr) CloudManager::~CloudManager() { //TODO: do we have to save storages on manager destruction? delete _activeStorage; + freeStorages(); } Common::String CloudManager::getStorageConfigName(uint32 index) const { @@ -124,6 +125,7 @@ void CloudManager::save() { } void CloudManager::replaceStorage(Storage *storage, uint32 index) { + freeStorages(); if (!storage) error("CloudManager::replaceStorage: NULL storage passed"); if (index >= kStorageTotal) error("CloudManager::replaceStorage: invalid index passed"); delete _activeStorage; @@ -138,6 +140,18 @@ void CloudManager::replaceStorage(Storage *storage, uint32 index) { } } +void CloudManager::removeStorage(Storage *storage) { + // can't just delete it as it's mostly likely the one who calls the method + // it would be freed on freeStorages() call (on next Storage connect or replace) + _storagesToRemove.push_back(storage); +} + +void CloudManager::freeStorages() { + for (uint32 i = 0; i < _storagesToRemove.size(); ++i) + delete _storagesToRemove[i]; + _storagesToRemove.clear(); +} + Storage *CloudManager::getCurrentStorage() const { return _activeStorage; } @@ -207,6 +221,8 @@ void CloudManager::setStorageLastSync(uint32 index, Common::String date) { } void CloudManager::connectStorage(uint32 index, Common::String code) { + freeStorages(); + Storage *storage = nullptr; switch (index) { case kStorageDropboxId: storage = new Dropbox::DropboxStorage(code); break; @@ -214,7 +230,9 @@ void CloudManager::connectStorage(uint32 index, Common::String code) { case kStorageGoogleDriveId: storage = new GoogleDrive::GoogleDriveStorage(code); break; case kStorageBoxId: storage = new Box::BoxStorage(code); break; } - //these would automatically request replaceStorage() when they receive the token + // in these constructors Storages request token using the passed code + // when the token is received, they call replaceStorage() + // or removeStorage(), if some error occurred } void CloudManager::printBool(Storage::BoolResponse response) const { diff --git a/backends/cloud/cloudmanager.h b/backends/cloud/cloudmanager.h index 15409ee3a1..4442b9bfbe 100644 --- a/backends/cloud/cloudmanager.h +++ b/backends/cloud/cloudmanager.h @@ -59,6 +59,7 @@ class CloudManager : public Common::Singleton<CloudManager> { Common::Array<StorageConfig> _storages; uint _currentStorageIndex; Storage *_activeStorage; + Common::Array<Storage *> _storagesToRemove; void printBool(Cloud::Storage::BoolResponse response) const; @@ -66,6 +67,9 @@ class CloudManager : public Common::Singleton<CloudManager> { Common::String getStorageConfigName(uint32 index) const; + /** Frees memory used by storages which failed to connect. */ + void freeStorages(); + public: CloudManager(); virtual ~CloudManager(); @@ -91,6 +95,9 @@ public: */ void replaceStorage(Storage *storage, uint32 index); + /** Adds storage in the list of storages to remove later. */ + void removeStorage(Storage *storage); + /** * Returns active Storage, which could be used to interact * with cloud storage. diff --git a/backends/cloud/dropbox/dropboxstorage.cpp b/backends/cloud/dropbox/dropboxstorage.cpp index e34912ed66..4171af0443 100644 --- a/backends/cloud/dropbox/dropboxstorage.cpp +++ b/backends/cloud/dropbox/dropboxstorage.cpp @@ -62,8 +62,9 @@ DropboxStorage::~DropboxStorage() {} void DropboxStorage::getAccessToken(Common::String code) { if (!KEY || !SECRET) loadKeyAndSecret(); - Networking::JsonCallback callback = new Common::Callback<DropboxStorage, Networking::JsonResponse>(this, &DropboxStorage::codeFlowComplete); - Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(callback, nullptr, "https://api.dropboxapi.com/oauth2/token"); + Networking::JsonCallback callback = new Common::Callback<DropboxStorage, Networking::JsonResponse>(this, &DropboxStorage::codeFlowComplete); + Networking::ErrorCallback errorCallback = new Common::Callback<DropboxStorage, Networking::ErrorResponse>(this, &DropboxStorage::codeFlowFailed); + Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(callback, errorCallback, "https://api.dropboxapi.com/oauth2/token"); request->addPostField("code=" + code); request->addPostField("grant_type=authorization_code"); request->addPostField("client_id=" + Common::String(KEY)); @@ -83,6 +84,7 @@ void DropboxStorage::codeFlowComplete(Networking::JsonResponse response) { if (!result.contains("access_token") || !result.contains("uid")) { warning("%s", json->stringify(true).c_str()); warning("Bad response, no token/uid passed"); + CloudMan.removeStorage(this); } else { _token = result.getVal("access_token")->asString(); _uid = result.getVal("uid")->asString(); @@ -94,9 +96,16 @@ void DropboxStorage::codeFlowComplete(Networking::JsonResponse response) { delete json; } else { debug("DropboxStorage::codeFlowComplete: got NULL instead of JSON!"); + CloudMan.removeStorage(this); } } +void DropboxStorage::codeFlowFailed(Networking::ErrorResponse error) { + debug("Dropbox's code flow failed (%s, %ld):", (error.failed ? "failed" : "interrupted"), error.httpResponseCode); + debug("%s", error.response.c_str()); + CloudMan.removeStorage(this); +} + void DropboxStorage::saveConfig(Common::String keyPrefix) { ConfMan.set(keyPrefix + "access_token", _token, ConfMan.kCloudDomain); ConfMan.set(keyPrefix + "user_id", _uid, ConfMan.kCloudDomain); diff --git a/backends/cloud/dropbox/dropboxstorage.h b/backends/cloud/dropbox/dropboxstorage.h index 2c9cf163ab..9dd28ba810 100644 --- a/backends/cloud/dropbox/dropboxstorage.h +++ b/backends/cloud/dropbox/dropboxstorage.h @@ -42,6 +42,7 @@ class DropboxStorage: public Cloud::Storage { void getAccessToken(Common::String code); void codeFlowComplete(Networking::JsonResponse response); + void codeFlowFailed(Networking::ErrorResponse error); public: /** This constructor uses OAuth code flow to get tokens. */ diff --git a/backends/cloud/googledrive/googledrivestorage.cpp b/backends/cloud/googledrive/googledrivestorage.cpp index 2816301cac..c4264099fd 100644 --- a/backends/cloud/googledrive/googledrivestorage.cpp +++ b/backends/cloud/googledrive/googledrivestorage.cpp @@ -56,12 +56,16 @@ GoogleDriveStorage::GoogleDriveStorage(Common::String accessToken, Common::Strin _token(accessToken), _refreshToken(refreshToken) {} GoogleDriveStorage::GoogleDriveStorage(Common::String code) { - getAccessToken(new Common::Callback<GoogleDriveStorage, BoolResponse>(this, &GoogleDriveStorage::codeFlowComplete), code); + getAccessToken( + new Common::Callback<GoogleDriveStorage, BoolResponse>(this, &GoogleDriveStorage::codeFlowComplete), + new Common::Callback<GoogleDriveStorage, Networking::ErrorResponse>(this, &GoogleDriveStorage::codeFlowFailed), + code + ); } GoogleDriveStorage::~GoogleDriveStorage() {} -void GoogleDriveStorage::getAccessToken(BoolCallback callback, Common::String code) { +void GoogleDriveStorage::getAccessToken(BoolCallback callback, Networking::ErrorCallback errorCallback, Common::String code) { if (!KEY || !SECRET) loadKeyAndSecret(); bool codeFlow = (code != ""); @@ -72,7 +76,8 @@ void GoogleDriveStorage::getAccessToken(BoolCallback callback, Common::String co } Networking::JsonCallback innerCallback = new Common::CallbackBridge<GoogleDriveStorage, BoolResponse, Networking::JsonResponse>(this, &GoogleDriveStorage::tokenRefreshed, callback); - Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, getErrorPrintingCallback(), "https://accounts.google.com/o/oauth2/token"); //TODO + if (errorCallback == nullptr) errorCallback = getErrorPrintingCallback(); + Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, errorCallback, "https://accounts.google.com/o/oauth2/token"); //TODO if (codeFlow) { request->addPostField("code=" + code); request->addPostField("grant_type=authorization_code"); @@ -118,6 +123,7 @@ void GoogleDriveStorage::tokenRefreshed(BoolCallback callback, Networking::JsonR void GoogleDriveStorage::codeFlowComplete(BoolResponse response) { if (!response.value) { warning("GoogleDriveStorage: failed to get access token through code flow"); + CloudMan.removeStorage(this); return; } @@ -126,6 +132,12 @@ void GoogleDriveStorage::codeFlowComplete(BoolResponse response) { ConfMan.flushToDisk(); } +void GoogleDriveStorage::codeFlowFailed(Networking::ErrorResponse error) { + debug("Google Drive's code flow failed (%s, %ld):", (error.failed ? "failed" : "interrupted"), error.httpResponseCode); + debug("%s", error.response.c_str()); + CloudMan.removeStorage(this); +} + void GoogleDriveStorage::saveConfig(Common::String keyPrefix) { ConfMan.set(keyPrefix + "access_token", _token, ConfMan.kCloudDomain); ConfMan.set(keyPrefix + "refresh_token", _refreshToken, ConfMan.kCloudDomain); diff --git a/backends/cloud/googledrive/googledrivestorage.h b/backends/cloud/googledrive/googledrivestorage.h index 4a7dbab99f..eee4de90b0 100644 --- a/backends/cloud/googledrive/googledrivestorage.h +++ b/backends/cloud/googledrive/googledrivestorage.h @@ -42,6 +42,7 @@ class GoogleDriveStorage: public Id::IdStorage { void tokenRefreshed(BoolCallback callback, Networking::JsonResponse response); void codeFlowComplete(BoolResponse response); + void codeFlowFailed(Networking::ErrorResponse error); /** Constructs StorageInfo based on JSON response from cloud. */ void infoInnerCallback(StorageInfoCallback outerCallback, Networking::JsonResponse json); @@ -110,7 +111,7 @@ public: * Use "" in order to refresh token and pass a callback, so you could * continue your work when new token is available. */ - void getAccessToken(BoolCallback callback, Common::String code = ""); + void getAccessToken(BoolCallback callback, Networking::ErrorCallback errorCallback = nullptr, Common::String code = ""); Common::String accessToken() { return _token; } }; diff --git a/backends/cloud/onedrive/onedrivestorage.cpp b/backends/cloud/onedrive/onedrivestorage.cpp index 3c8ea5fe81..e9165943af 100644 --- a/backends/cloud/onedrive/onedrivestorage.cpp +++ b/backends/cloud/onedrive/onedrivestorage.cpp @@ -57,12 +57,16 @@ OneDriveStorage::OneDriveStorage(Common::String accessToken, Common::String user _token(accessToken), _uid(userId), _refreshToken(refreshToken) {} OneDriveStorage::OneDriveStorage(Common::String code) { - getAccessToken(new Common::Callback<OneDriveStorage, BoolResponse>(this, &OneDriveStorage::codeFlowComplete), code); + getAccessToken( + new Common::Callback<OneDriveStorage, BoolResponse>(this, &OneDriveStorage::codeFlowComplete), + new Common::Callback<OneDriveStorage, Networking::ErrorResponse>(this, &OneDriveStorage::codeFlowFailed), + code + ); } OneDriveStorage::~OneDriveStorage() {} -void OneDriveStorage::getAccessToken(BoolCallback callback, Common::String code) { +void OneDriveStorage::getAccessToken(BoolCallback callback, Networking::ErrorCallback errorCallback, Common::String code) { if (!KEY || !SECRET) loadKeyAndSecret(); bool codeFlow = (code != ""); @@ -73,7 +77,8 @@ void OneDriveStorage::getAccessToken(BoolCallback callback, Common::String code) } Networking::JsonCallback innerCallback = new Common::CallbackBridge<OneDriveStorage, BoolResponse, Networking::JsonResponse>(this, &OneDriveStorage::tokenRefreshed, callback); - Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, getErrorPrintingCallback(), "https://login.live.com/oauth20_token.srf"); //TODO + if (errorCallback == nullptr) errorCallback = getErrorPrintingCallback(); + Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, errorCallback, "https://login.live.com/oauth20_token.srf"); //TODO if (codeFlow) { request->addPostField("code=" + code); request->addPostField("grant_type=authorization_code"); @@ -117,6 +122,7 @@ void OneDriveStorage::tokenRefreshed(BoolCallback callback, Networking::JsonResp void OneDriveStorage::codeFlowComplete(BoolResponse response) { if (!response.value) { warning("OneDriveStorage: failed to get access token through code flow"); + CloudMan.removeStorage(this); return; } @@ -125,6 +131,12 @@ void OneDriveStorage::codeFlowComplete(BoolResponse response) { ConfMan.flushToDisk(); } +void OneDriveStorage::codeFlowFailed(Networking::ErrorResponse error) { + debug("OneDrive's code flow failed (%s, %ld):", (error.failed ? "failed" : "interrupted"), error.httpResponseCode); + debug("%s", error.response.c_str()); + CloudMan.removeStorage(this); +} + void OneDriveStorage::saveConfig(Common::String keyPrefix) { ConfMan.set(keyPrefix + "access_token", _token, ConfMan.kCloudDomain); ConfMan.set(keyPrefix + "user_id", _uid, ConfMan.kCloudDomain); diff --git a/backends/cloud/onedrive/onedrivestorage.h b/backends/cloud/onedrive/onedrivestorage.h index 650c240aef..8ceaaf107e 100644 --- a/backends/cloud/onedrive/onedrivestorage.h +++ b/backends/cloud/onedrive/onedrivestorage.h @@ -41,6 +41,7 @@ class OneDriveStorage: public Cloud::Storage { void tokenRefreshed(BoolCallback callback, Networking::JsonResponse response); void codeFlowComplete(BoolResponse response); + void codeFlowFailed(Networking::ErrorResponse error); /** Constructs StorageInfo based on JSON response from cloud. */ void infoInnerCallback(StorageInfoCallback outerCallback, Networking::JsonResponse json); @@ -101,7 +102,7 @@ public: * Use "" in order to refresh token and pass a callback, so you could * continue your work when new token is available. */ - void getAccessToken(BoolCallback callback, Common::String code = ""); + void getAccessToken(BoolCallback callback, Networking::ErrorCallback errorCallback = nullptr, Common::String code = ""); Common::String accessToken() { return _token; } }; |