From fc8e29d5832728a513cab0f10be218c6a632758a Mon Sep 17 00:00:00 2001 From: Alexander Tkachev Date: Tue, 26 Jul 2016 14:53:44 +0600 Subject: [PATCH] CLOUD: Update OneDrive Added JSON checks. New jsonContainsObject() method added to CurlJsonRequest. --- .../cloud/googledrive/googledrivestorage.cpp | 2 +- .../onedrivecreatedirectoryrequest.cpp | 11 ++- backends/cloud/onedrive/onedrivestorage.cpp | 74 ++++++++++++++----- backends/networking/curl/curljsonrequest.cpp | 17 +++++ backends/networking/curl/curljsonrequest.h | 1 + 5 files changed, 83 insertions(+), 22 deletions(-) diff --git a/backends/cloud/googledrive/googledrivestorage.cpp b/backends/cloud/googledrive/googledrivestorage.cpp index eb04e7e4394..1b4b8baf560 100644 --- a/backends/cloud/googledrive/googledrivestorage.cpp +++ b/backends/cloud/googledrive/googledrivestorage.cpp @@ -93,7 +93,7 @@ void GoogleDriveStorage::getAccessToken(BoolCallback callback, Networking::Error Networking::JsonCallback innerCallback = new Common::CallbackBridge(this, &GoogleDriveStorage::tokenRefreshed, callback); if (errorCallback == nullptr) errorCallback = getErrorPrintingCallback(); - Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, errorCallback, GOOGLEDRIVE_OAUTH2_TOKEN); //TODO + Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, errorCallback, GOOGLEDRIVE_OAUTH2_TOKEN); if (codeFlow) { request->addPostField("code=" + code); request->addPostField("grant_type=authorization_code"); diff --git a/backends/cloud/onedrive/onedrivecreatedirectoryrequest.cpp b/backends/cloud/onedrive/onedrivecreatedirectoryrequest.cpp index 4d6d8fceda3..fc7e4f58b07 100644 --- a/backends/cloud/onedrive/onedrivecreatedirectoryrequest.cpp +++ b/backends/cloud/onedrive/onedrivecreatedirectoryrequest.cpp @@ -101,12 +101,19 @@ void OneDriveCreateDirectoryRequest::responseCallback(Networking::JsonResponse r if (rq && rq->getNetworkReadStream()) error.httpResponseCode = rq->getNetworkReadStream()->httpResponseCode(); - if (!json) { - warning("OneDriveCreateDirectoryRequest: NULL passed instead of JSON"); + if (json == nullptr) { + error.response = "Failed to parse JSON, null passed!"; finishError(error); return; } + if (!json->isObject()) { + error.response = "Passed JSON is not an object!"; + finishError(error); + delete json; + return; + } + Common::JSONObject info = json->asObject(); if (info.contains("id")) { finishCreation(true); diff --git a/backends/cloud/onedrive/onedrivestorage.cpp b/backends/cloud/onedrive/onedrivestorage.cpp index 9fde2ed2c7b..4b70bb73b93 100644 --- a/backends/cloud/onedrive/onedrivestorage.cpp +++ b/backends/cloud/onedrive/onedrivestorage.cpp @@ -116,12 +116,24 @@ void OneDriveStorage::tokenRefreshed(BoolCallback callback, Networking::JsonResp Common::JSONValue *json = response.value; if (!json) { warning("OneDriveStorage: got NULL instead of JSON"); - if (callback) (*callback)(BoolResponse(nullptr, false)); + if (callback) + (*callback)(BoolResponse(nullptr, false)); + delete callback; + return; + } + + if (!Networking::CurlJsonRequest::jsonIsObject(json, "OneDriveStorage")) { + if (callback) + (*callback)(BoolResponse(nullptr, false)); + delete json; + delete callback; return; } Common::JSONObject result = json->asObject(); - if (!result.contains("access_token") || !result.contains("user_id") || !result.contains("refresh_token")) { + if (!Networking::CurlJsonRequest::jsonContainsString(result, "access_token", "OneDriveStorage") || + !Networking::CurlJsonRequest::jsonContainsString(result, "user_id", "OneDriveStorage") || + !Networking::CurlJsonRequest::jsonContainsString(result, "refresh_token", "OneDriveStorage")) { warning("OneDriveStorage: bad response, no token or user_id passed"); debug(9, "%s", json->stringify().c_str()); if (callback) @@ -135,6 +147,7 @@ void OneDriveStorage::tokenRefreshed(BoolCallback callback, Networking::JsonResp (*callback)(BoolResponse(nullptr, true)); } delete json; + delete callback; } void OneDriveStorage::codeFlowComplete(BoolResponse response) { @@ -168,7 +181,13 @@ Common::String OneDriveStorage::name() const { void OneDriveStorage::infoInnerCallback(StorageInfoCallback outerCallback, Networking::JsonResponse response) { Common::JSONValue *json = response.value; if (!json) { - warning("OneDriveStorage: NULL passed instead of JSON"); + warning("OneDriveStorage::infoInnerCallback: NULL passed instead of JSON"); + delete outerCallback; + return; + } + + if (!Networking::CurlJsonRequest::jsonIsObject(json, "OneDriveStorage::infoInnerCallback")) { + delete json; delete outerCallback; return; } @@ -178,16 +197,18 @@ void OneDriveStorage::infoInnerCallback(StorageInfoCallback outerCallback, Netwo 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()) { + if (Networking::CurlJsonRequest::jsonContainsObject(info, "createdBy", "OneDriveStorage::infoInnerCallback")) { Common::JSONObject createdBy = info.getVal("createdBy")->asObject(); - if (createdBy.contains("user") && createdBy.getVal("user")->isObject()) { + if (Networking::CurlJsonRequest::jsonContainsObject(createdBy, "user", "OneDriveStorage::infoInnerCallback")) { Common::JSONObject user = createdBy.getVal("user")->asObject(); - uid = user.getVal("id")->asString(); - name = user.getVal("displayName")->asString(); + if (Networking::CurlJsonRequest::jsonContainsString(user, "id", "OneDriveStorage::infoInnerCallback")) + uid = user.getVal("id")->asString(); + if (Networking::CurlJsonRequest::jsonContainsString(user, "displayName", "OneDriveStorage::infoInnerCallback")) + name = user.getVal("displayName")->asString(); } } - if (info.contains("size") && info.getVal("size")->isIntegerNumber()) { + if (Networking::CurlJsonRequest::jsonContainsIntegerNumber(info, "size", "OneDriveStorage::infoInnerCallback")) { quotaUsed = info.getVal("size")->asIntegerNumber(); } @@ -207,28 +228,43 @@ void OneDriveStorage::infoInnerCallback(StorageInfoCallback outerCallback, Netwo } void OneDriveStorage::fileInfoCallback(Networking::NetworkReadStreamCallback outerCallback, Networking::JsonResponse response) { - if (!response.value) { - warning("OneDriveStorage::fileInfoCallback: NULL, not JSON"); + Common::JSONValue *json = response.value; + if (!json) { + warning("OneDriveStorage::fileInfoCallback: NULL passed instead of JSON"); if (outerCallback) (*outerCallback)(Networking::NetworkReadStreamResponse(response.request, nullptr)); + delete outerCallback; + return; + } + + if (!Networking::CurlJsonRequest::jsonIsObject(json, "OneDriveStorage::fileInfoCallback")) { + if (outerCallback) + (*outerCallback)(Networking::NetworkReadStreamResponse(response.request, nullptr)); + delete json; + delete outerCallback; return; } Common::JSONObject result = response.value->asObject(); - if (result.contains("@content.downloadUrl")) { - const char *url = result.getVal("@content.downloadUrl")->asString().c_str(); - if (outerCallback) - (*outerCallback)(Networking::NetworkReadStreamResponse( - response.request, - new Networking::NetworkReadStream(url, nullptr, "") - )); - } else { + if (!Networking::CurlJsonRequest::jsonContainsString(result, "@content.downloadUrl", "OneDriveStorage::fileInfoCallback")) { warning("OneDriveStorage: downloadUrl not found in passed JSON"); debug(9, "%s", response.value->stringify().c_str()); if (outerCallback) (*outerCallback)(Networking::NetworkReadStreamResponse(response.request, nullptr)); + delete json; + delete outerCallback; + return; } - delete response.value; + + const char *url = result.getVal("@content.downloadUrl")->asString().c_str(); + if (outerCallback) + (*outerCallback)(Networking::NetworkReadStreamResponse( + response.request, + new Networking::NetworkReadStream(url, nullptr, "") + )); + + delete json; + delete outerCallback; } Networking::Request *OneDriveStorage::listDirectory(Common::String path, ListDirectoryCallback callback, Networking::ErrorCallback errorCallback, bool recursive) { diff --git a/backends/networking/curl/curljsonrequest.cpp b/backends/networking/curl/curljsonrequest.cpp index aac89a15133..6ff35d7b3d4 100644 --- a/backends/networking/curl/curljsonrequest.cpp +++ b/backends/networking/curl/curljsonrequest.cpp @@ -114,6 +114,23 @@ bool CurlJsonRequest::jsonIsObject(Common::JSONValue *item, const char *warningP return false; } +bool CurlJsonRequest::jsonContainsObject(Common::JSONObject &item, const char *key, const char *warningPrefix, bool isOptional) { + if (!item.contains(key)) { + if (isOptional) { + return true; + } + + warning("%s: passed item misses the \"%s\" attribute!", warningPrefix, key); + return false; + } + + if (item.getVal(key)->isObject()) return true; + + warning("%s: passed item's \"%s\" attribute is not an object!", warningPrefix, key); + debug(9, "%s", item.getVal(key)->stringify(true).c_str()); + return false; +} + bool CurlJsonRequest::jsonContainsString(Common::JSONObject &item, const char *key, const char *warningPrefix, bool isOptional) { if (!item.contains(key)) { if (isOptional) { diff --git a/backends/networking/curl/curljsonrequest.h b/backends/networking/curl/curljsonrequest.h index cab75bf4bcf..edd523015a3 100644 --- a/backends/networking/curl/curljsonrequest.h +++ b/backends/networking/curl/curljsonrequest.h @@ -54,6 +54,7 @@ public: virtual void restart(); static bool jsonIsObject(Common::JSONValue *item, const char *warningPrefix); + static bool jsonContainsObject(Common::JSONObject &item, const char *key, const char *warningPrefix, bool isOptional = false); static bool jsonContainsString(Common::JSONObject &item, const char *key, const char *warningPrefix, bool isOptional = false); static bool jsonContainsIntegerNumber(Common::JSONObject &item, const char *key, const char *warningPrefix, bool isOptional = false); static bool jsonContainsArray(Common::JSONObject &item, const char *key, const char *warningPrefix, bool isOptional = false);