diff options
author | Alexander Tkachev | 2016-07-13 12:52:04 +0600 |
---|---|---|
committer | Alexander Tkachev | 2016-08-24 16:07:55 +0600 |
commit | 85f1ce8ece7d4f4c6e54cfe29eaebe2c4ec13aec (patch) | |
tree | 1cdf0b580272b11870fb7144f32c42b328c94ce6 | |
parent | 0a43dad629099505701b14723f1b22ba013a869e (diff) | |
download | scummvm-rg350-85f1ce8ece7d4f4c6e54cfe29eaebe2c4ec13aec.tar.gz scummvm-rg350-85f1ce8ece7d4f4c6e54cfe29eaebe2c4ec13aec.tar.bz2 scummvm-rg350-85f1ce8ece7d4f4c6e54cfe29eaebe2c4ec13aec.zip |
CLOUD: Add BoxTokenRefresher and BoxStorage::info()
BoxTokenRefresher does refresh if HTTP 401 is returned by the server.
To test refresher, BoxStorage::info() was added.
-rw-r--r-- | backends/cloud/box/boxstorage.cpp | 39 | ||||
-rw-r--r-- | backends/cloud/box/boxtokenrefresher.cpp | 134 | ||||
-rw-r--r-- | backends/cloud/box/boxtokenrefresher.h | 53 | ||||
-rw-r--r-- | backends/module.mk | 1 |
4 files changed, 209 insertions, 18 deletions
diff --git a/backends/cloud/box/boxstorage.cpp b/backends/cloud/box/boxstorage.cpp index 8a2e004e53..85bbf34221 100644 --- a/backends/cloud/box/boxstorage.cpp +++ b/backends/cloud/box/boxstorage.cpp @@ -22,6 +22,7 @@ #define FORBIDDEN_SYMBOL_ALLOW_ALL #include "backends/cloud/box/boxstorage.h" +#include "backends/cloud/box/boxtokenrefresher.h" #include "backends/cloud/cloudmanager.h" #include "backends/networking/curl/connectionmanager.h" #include "backends/networking/curl/curljsonrequest.h" @@ -141,20 +142,25 @@ void BoxStorage::infoInnerCallback(StorageInfoCallback outerCallback, Networking Common::JSONObject info = json->asObject(); Common::String uid, name, email; - uint64 quotaUsed = 0, quotaAllocated = 26843545600L; // 25 GB, because I actually don't know any way to find out the real one - - if (info.contains("createdBy") && info.getVal("createdBy")->isObject()) { - Common::JSONObject createdBy = info.getVal("createdBy")->asObject(); - if (createdBy.contains("user") && createdBy.getVal("user")->isObject()) { - Common::JSONObject user = createdBy.getVal("user")->asObject(); - uid = user.getVal("id")->asString(); - name = user.getVal("displayName")->asString(); - } - } + uint64 quotaUsed = 0, quotaAllocated = 0; - if (info.contains("size") && info.getVal("size")->isIntegerNumber()) { - quotaUsed = info.getVal("size")->asIntegerNumber(); - } + // can check that "type": "user" + // there is also "max_upload_size", "phone" and "avatar_url" + + if (info.contains("id") && info.getVal("id")->isString()) + uid = info.getVal("id")->asString(); + + if (info.contains("name") && info.getVal("name")->isString()) + name = info.getVal("name")->asString(); + + if (info.contains("login") && info.getVal("login")->isString()) + email = info.getVal("login")->asString(); + + if (info.contains("space_amount") && info.getVal("space_amount")->isIntegerNumber()) + quotaAllocated = info.getVal("space_amount")->asIntegerNumber(); + + if (info.contains("space_used") && info.getVal("space_used")->isIntegerNumber()) + quotaUsed = info.getVal("space_used")->asIntegerNumber(); Common::String username = email; if (username == "") username = name; @@ -254,13 +260,10 @@ Networking::Request *BoxStorage::createDirectory(Common::String path, BoolCallba } Networking::Request *BoxStorage::info(StorageInfoCallback callback, Networking::ErrorCallback errorCallback) { - /* Networking::JsonCallback innerCallback = new Common::CallbackBridge<BoxStorage, StorageInfoResponse, Networking::JsonResponse>(this, &BoxStorage::infoInnerCallback, callback); - Networking::CurlJsonRequest *request = new BoxTokenRefresher(this, innerCallback, errorCallback, "https://api.Box.com/v1.0/drive/special/approot"); - request->addHeader("Authorization: bearer " + _token); + Networking::CurlJsonRequest *request = new BoxTokenRefresher(this, innerCallback, errorCallback, "https://api.box.com/2.0/users/me"); + request->addHeader("Authorization: Bearer " + _token); return addRequest(request); - */ - return nullptr; //TODO } Common::String BoxStorage::savesDirectoryPath() { return "saves/"; } diff --git a/backends/cloud/box/boxtokenrefresher.cpp b/backends/cloud/box/boxtokenrefresher.cpp new file mode 100644 index 0000000000..9dfbef537f --- /dev/null +++ b/backends/cloud/box/boxtokenrefresher.cpp @@ -0,0 +1,134 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "backends/cloud/box/boxtokenrefresher.h" +#include "backends/cloud/box/boxstorage.h" +#include "backends/networking/curl/networkreadstream.h" +#include "common/debug.h" +#include "common/json.h" +#include <curl/curl.h> + +namespace Cloud { +namespace Box { + +BoxTokenRefresher::BoxTokenRefresher(BoxStorage *parent, Networking::JsonCallback callback, Networking::ErrorCallback ecb, const char *url): + CurlJsonRequest(callback, ecb, url), _parentStorage(parent) {} + +BoxTokenRefresher::~BoxTokenRefresher() {} + +void BoxTokenRefresher::tokenRefreshed(Storage::BoolResponse response) { + if (!response.value) { + //failed to refresh token, notify user with NULL in original callback + warning("BoxTokenRefresher: failed to refresh token"); + finishError(Networking::ErrorResponse(this, false, true, "", -1)); + return; + } + + //update headers: first change header with token, then pass those to request + for (uint32 i = 0; i < _headers.size(); ++i) { + if (_headers[i].contains("Authorization")) { + _headers[i] = "Authorization: Bearer " + _parentStorage->accessToken(); + } + } + setHeaders(_headers); + + //successfully received refreshed token, can restart the original request now + retry(0); +} + +void BoxTokenRefresher::finishJson(Common::JSONValue *json) { + if (!json) { + //that's probably not an error (200 OK) + CurlJsonRequest::finishJson(nullptr); + return; + } + + Common::JSONObject result = json->asObject(); + if (result.contains("type") && result.getVal("type")->isString() && result.getVal("type")->asString() == "error") { + //new token needed => request token & then retry original request + long httpCode = -1; + if (_stream) { + httpCode = _stream->httpResponseCode(); + debug("code %ld", httpCode); + } + + bool irrecoverable = true; + + Common::String code, message; + if (result.contains("code")) { + code = result.getVal("code")->asString(); + debug("code = %s", code.c_str()); + } + + if (result.contains("message")) { + message = result.getVal("message")->asString(); + debug("message = %s", message.c_str()); + } + + //TODO: decide when token refreshment will help + //if (code == "unauthenticated") irrecoverable = false; + + if (irrecoverable) { + finishError(Networking::ErrorResponse(this, false, true, json->stringify(true), httpCode)); + delete json; + return; + } + + pause(); + delete json; + _parentStorage->getAccessToken(new Common::Callback<BoxTokenRefresher, Storage::BoolResponse>(this, &BoxTokenRefresher::tokenRefreshed)); + return; + } + + //notify user of success + CurlJsonRequest::finishJson(json); +} + +void BoxTokenRefresher::finishError(Networking::ErrorResponse error) { + if (error.httpResponseCode == 401) { // invalid_token + pause(); + _parentStorage->getAccessToken(new Common::Callback<BoxTokenRefresher, Storage::BoolResponse>(this, &BoxTokenRefresher::tokenRefreshed)); + return; + } + + // there are also 400 == invalid_request and 403 == insufficient_scope + // but TokenRefresher is there to refresh token when it's invalid only + + Request::finishError(error); +} + +void BoxTokenRefresher::setHeaders(Common::Array<Common::String> &headers) { + _headers = headers; + curl_slist_free_all(_headersList); + _headersList = 0; + for (uint32 i = 0; i < headers.size(); ++i) + CurlJsonRequest::addHeader(headers[i]); +} + +void BoxTokenRefresher::addHeader(Common::String header) { + _headers.push_back(header); + CurlJsonRequest::addHeader(header); +} + +} // End of namespace Box +} // End of namespace Cloud diff --git a/backends/cloud/box/boxtokenrefresher.h b/backends/cloud/box/boxtokenrefresher.h new file mode 100644 index 0000000000..7dedefdbe5 --- /dev/null +++ b/backends/cloud/box/boxtokenrefresher.h @@ -0,0 +1,53 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#ifndef BACKENDS_CLOUD_BOX_BOXTOKENREFRESHER_H +#define BACKENDS_CLOUD_BOX_BOXTOKENREFRESHER_H + +#include "backends/cloud/storage.h" +#include "backends/networking/curl/curljsonrequest.h" + +namespace Cloud { +namespace Box { + +class BoxStorage; + +class BoxTokenRefresher: public Networking::CurlJsonRequest { + BoxStorage *_parentStorage; + Common::Array<Common::String> _headers; + + void tokenRefreshed(Storage::BoolResponse response); + + virtual void finishJson(Common::JSONValue *json); + virtual void finishError(Networking::ErrorResponse error); +public: + BoxTokenRefresher(BoxStorage *parent, Networking::JsonCallback callback, Networking::ErrorCallback ecb, const char *url); + virtual ~BoxTokenRefresher(); + + virtual void setHeaders(Common::Array<Common::String> &headers); + virtual void addHeader(Common::String header); +}; + +} // End of namespace Box +} // End of namespace Cloud + +#endif diff --git a/backends/module.mk b/backends/module.mk index d1737b19e5..2c2a4e2cfc 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -29,6 +29,7 @@ MODULE_OBJS += \ cloud/folderdownloadrequest.o \ cloud/savessyncrequest.o \ cloud/box/boxstorage.o \ + cloud/box/boxtokenrefresher.o \ cloud/dropbox/dropboxstorage.o \ cloud/dropbox/dropboxcreatedirectoryrequest.o \ cloud/dropbox/dropboxlistdirectoryrequest.o \ |