diff options
author | Alexander Tkachev | 2016-05-31 14:18:32 +0600 |
---|---|---|
committer | Alexander Tkachev | 2016-08-24 16:07:55 +0600 |
commit | b39f46788a70a6c72d5ca678c79c0b53ebde9b68 (patch) | |
tree | 6b6e3043dac1956c5a799cbd45094698b36108cb /backends | |
parent | eb63b50b7f0841e40365f3fbafa9810e8b190872 (diff) | |
download | scummvm-rg350-b39f46788a70a6c72d5ca678c79c0b53ebde9b68.tar.gz scummvm-rg350-b39f46788a70a6c72d5ca678c79c0b53ebde9b68.tar.bz2 scummvm-rg350-b39f46788a70a6c72d5ca678c79c0b53ebde9b68.zip |
CLOUD: Add OneDriveUploadRequest
Doesn't support server's requested ranges yet.
Commit also adds some PUT-related code in NetworkReadStream and
CurlRequest.
Diffstat (limited to 'backends')
-rw-r--r-- | backends/cloud/dropbox/dropboxstorage.cpp | 13 | ||||
-rw-r--r-- | backends/cloud/dropbox/dropboxstorage.h | 3 | ||||
-rw-r--r-- | backends/cloud/onedrive/onedrivestorage.cpp | 19 | ||||
-rw-r--r-- | backends/cloud/onedrive/onedrivestorage.h | 4 | ||||
-rw-r--r-- | backends/cloud/onedrive/onedrivetokenrefresher.cpp | 2 | ||||
-rw-r--r-- | backends/cloud/onedrive/onedriveuploadrequest.cpp | 171 | ||||
-rw-r--r-- | backends/cloud/onedrive/onedriveuploadrequest.h | 61 | ||||
-rw-r--r-- | backends/cloud/storage.cpp | 42 | ||||
-rw-r--r-- | backends/cloud/storage.h | 2 | ||||
-rw-r--r-- | backends/module.mk | 4 | ||||
-rw-r--r-- | backends/networking/curl/curlrequest.cpp | 8 | ||||
-rw-r--r-- | backends/networking/curl/curlrequest.h | 4 | ||||
-rw-r--r-- | backends/networking/curl/networkreadstream.cpp | 38 | ||||
-rw-r--r-- | backends/networking/curl/networkreadstream.h | 16 |
14 files changed, 354 insertions, 33 deletions
diff --git a/backends/cloud/dropbox/dropboxstorage.cpp b/backends/cloud/dropbox/dropboxstorage.cpp index d22e0abf60..7ba072d578 100644 --- a/backends/cloud/dropbox/dropboxstorage.cpp +++ b/backends/cloud/dropbox/dropboxstorage.cpp @@ -131,19 +131,6 @@ Networking::Request *DropboxStorage::upload(Common::String path, Common::Seekabl return ConnMan.addRequest(new DropboxUploadRequest(_token, path, contents, callback, errorCallback)); } -Networking::Request *DropboxStorage::upload(Common::String remotePath, Common::String localPath, UploadCallback callback, Networking::ErrorCallback errorCallback) { - Common::File *f = new Common::File(); - if (!f->open(localPath)) { - warning("DropboxStorage: unable to open file to upload from"); - if (errorCallback) (*errorCallback)(Networking::ErrorResponse(nullptr, false, true, "", -1)); - delete errorCallback; - delete callback; - delete f; - return nullptr; - } - return upload(remotePath, f, callback, errorCallback); -} - Networking::Request *DropboxStorage::streamFile(Common::String path, Networking::NetworkReadStreamCallback callback, Networking::ErrorCallback errorCallback) { Common::JSONObject jsonRequestParameters; jsonRequestParameters.setVal("path", new Common::JSONValue(path)); diff --git a/backends/cloud/dropbox/dropboxstorage.h b/backends/cloud/dropbox/dropboxstorage.h index 0082e5cebd..a5ef76a3d6 100644 --- a/backends/cloud/dropbox/dropboxstorage.h +++ b/backends/cloud/dropbox/dropboxstorage.h @@ -74,8 +74,7 @@ public: virtual Networking::Request *listDirectory(Common::String path, ListDirectoryCallback callback, Networking::ErrorCallback errorCallback, bool recursive = false); /** Returns UploadStatus struct with info about uploaded file. */ - virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback, Networking::ErrorCallback errorCallback); - virtual Networking::Request *upload(Common::String remotePath, Common::String localPath, UploadCallback callback, Networking::ErrorCallback errorCallback); + virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback, Networking::ErrorCallback errorCallback); /** Returns pointer to Networking::NetworkReadStream. */ virtual Networking::Request *streamFile(Common::String path, Networking::NetworkReadStreamCallback callback, Networking::ErrorCallback errorCallback); diff --git a/backends/cloud/onedrive/onedrivestorage.cpp b/backends/cloud/onedrive/onedrivestorage.cpp index 8746b7ab33..fe10580616 100644 --- a/backends/cloud/onedrive/onedrivestorage.cpp +++ b/backends/cloud/onedrive/onedrivestorage.cpp @@ -24,8 +24,10 @@ #include "backends/cloud/onedrive/onedrivestorage.h" #include "backends/cloud/onedrive/onedrivetokenrefresher.h" #include "backends/cloud/onedrive/onedrivelistdirectoryrequest.h" +#include "backends/cloud/onedrive/onedriveuploadrequest.h" #include "backends/cloud/downloadrequest.h" #include "backends/cloud/folderdownloadrequest.h" +#include "backends/cloud/savessyncrequest.h" #include "backends/networking/curl/connectionmanager.h" #include "backends/networking/curl/curljsonrequest.h" #include "common/cloudmanager.h" @@ -35,7 +37,6 @@ #include "common/json.h" #include "common/system.h" #include <curl/curl.h> -#include "../savessyncrequest.h" namespace Cloud { namespace OneDrive { @@ -168,6 +169,9 @@ Networking::Request *OneDriveStorage::listDirectory(Common::String path, ListDir return ConnMan.addRequest(new OneDriveListDirectoryRequest(this, path, callback, errorCallback, recursive)); } +Networking::Request *OneDriveStorage::upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback, Networking::ErrorCallback errorCallback) { + return ConnMan.addRequest(new OneDriveUploadRequest(this, path, contents, callback, errorCallback)); +} Networking::Request *OneDriveStorage::streamFile(Common::String path, Networking::NetworkReadStreamCallback outerCallback, Networking::ErrorCallback errorCallback) { Common::String url = "https://api.onedrive.com/v1.0/drive/special/approot:/" + path; @@ -210,6 +214,13 @@ void OneDriveStorage::printBool(BoolResponse response) { debug("bool: %s", response.value ? "true" : "false"); } +void OneDriveStorage::printFile(UploadResponse response) { + debug("\nuploaded file info:"); + debug("\tpath: %s", response.value.path().c_str()); + debug("\tsize: %u", response.value.size()); + debug("\ttimestamp: %u", response.value.timestamp()); +} + void OneDriveStorage::printErrorResponse(Networking::ErrorResponse error) { debug("error response (%s, %ld):", (error.failed ? "failed" : "interrupted"), error.httpResponseCode); debug("%s", error.response.c_str()); @@ -228,7 +239,11 @@ Networking::Request *OneDriveStorage::syncSaves(BoolCallback callback, Networkin return ConnMan.addRequest(request); */ //return downloadFolder("subfolder", "local/onedrive/subfolder_downloaded", new Common::Callback<OneDriveStorage, FileArrayResponse>(this, &OneDriveStorage::printFiles), false); - return ConnMan.addRequest(new SavesSyncRequest(this, new Common::Callback<OneDriveStorage, BoolResponse>(this, &OneDriveStorage::printBool), getErrorPrintingCallback())); //TODO + return Storage::upload( + "uploads/test.jpg", "test.jpg", + new Common::Callback<OneDriveStorage, UploadResponse>(this, &OneDriveStorage::printFile), getErrorPrintingCallback() + ); + //return ConnMan.addRequest(new SavesSyncRequest(this, new Common::Callback<OneDriveStorage, BoolResponse>(this, &OneDriveStorage::printBool), getErrorPrintingCallback())); //TODO } OneDriveStorage *OneDriveStorage::loadFromConfig(Common::String keyPrefix) { diff --git a/backends/cloud/onedrive/onedrivestorage.h b/backends/cloud/onedrive/onedrivestorage.h index f95ea89bc1..0ced98cd4e 100644 --- a/backends/cloud/onedrive/onedrivestorage.h +++ b/backends/cloud/onedrive/onedrivestorage.h @@ -53,6 +53,7 @@ class OneDriveStorage: public Cloud::Storage { void fileDownloaded(BoolResponse response); void printFiles(FileArrayResponse response); void printBool(BoolResponse response); + void printFile(UploadResponse response); void printErrorResponse(Networking::ErrorResponse error); Networking::ErrorCallback getErrorPrintingCallback(); @@ -80,8 +81,7 @@ public: virtual Networking::Request *listDirectory(Common::String path, ListDirectoryCallback callback, Networking::ErrorCallback errorCallback, bool recursive = false); /** Returns UploadStatus struct with info about uploaded file. */ - virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback, Networking::ErrorCallback errorCallback) { return nullptr; } //TODO - virtual Networking::Request *upload(Common::String remotePath, Common::String localPath, UploadCallback callback, Networking::ErrorCallback errorCallback) { return nullptr; } //TODO + virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback, Networking::ErrorCallback errorCallback); /** Returns pointer to Networking::NetworkReadStream. */ virtual Networking::Request *streamFile(Common::String path, Networking::NetworkReadStreamCallback callback, Networking::ErrorCallback errorCallback); diff --git a/backends/cloud/onedrive/onedrivetokenrefresher.cpp b/backends/cloud/onedrive/onedrivetokenrefresher.cpp index bc7bd74dbe..bf849f7964 100644 --- a/backends/cloud/onedrive/onedrivetokenrefresher.cpp +++ b/backends/cloud/onedrive/onedrivetokenrefresher.cpp @@ -90,6 +90,8 @@ void OneDriveTokenRefresher::finishSuccess(Common::JSONValue *json) { irrecoverable = false; } + if (code == "unauthenticated") irrecoverable = false; + if (irrecoverable) { finishError(Networking::ErrorResponse(this, false, true, json->stringify(true), -1)); //TODO: httpCode delete json; diff --git a/backends/cloud/onedrive/onedriveuploadrequest.cpp b/backends/cloud/onedrive/onedriveuploadrequest.cpp new file mode 100644 index 0000000000..752907f333 --- /dev/null +++ b/backends/cloud/onedrive/onedriveuploadrequest.cpp @@ -0,0 +1,171 @@ +/* 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. +* +*/ + +#include "backends/cloud/onedrive/onedriveuploadrequest.h" +#include "backends/cloud/onedrive/onedrivestorage.h" +#include "backends/cloud/iso8601.h" +#include "backends/cloud/storage.h" +#include "backends/networking/curl/connectionmanager.h" +#include "backends/networking/curl/curljsonrequest.h" +#include "backends/networking/curl/networkreadstream.h" +#include "common/json.h" +#include "common/debug.h" +#include "onedrivetokenrefresher.h" + +namespace Cloud { +namespace OneDrive { + +OneDriveUploadRequest::OneDriveUploadRequest(OneDriveStorage *storage, Common::String path, Common::SeekableReadStream *contents, Storage::UploadCallback callback, Networking::ErrorCallback ecb): + Networking::Request(nullptr, ecb), _storage(storage), _savePath(path), _contentsStream(contents), _uploadCallback(callback), + _workingRequest(nullptr), _ignoreCallback(false) { + start(); +} + +OneDriveUploadRequest::~OneDriveUploadRequest() { + _ignoreCallback = true; + if (_workingRequest) _workingRequest->finish(); + delete _contentsStream; + delete _uploadCallback; +} + +void OneDriveUploadRequest::start() { + _ignoreCallback = true; + if (_workingRequest) _workingRequest->finish(); + if (!_contentsStream->seek(0)) { + warning("OneDriveUploadRequest: cannot restart because stream couldn't seek(0)"); + finishError(Networking::ErrorResponse(this, false, true, "", -1)); + } + _ignoreCallback = false; + + uploadNextPart(); +} + +void OneDriveUploadRequest::uploadNextPart() { + const uint32 UPLOAD_PER_ONE_REQUEST = 10 * 1024 * 1024; + + if (_uploadUrl == "" && _contentsStream->size() > UPLOAD_PER_ONE_REQUEST) { + Common::String url = "https://api.onedrive.com/v1.0/drive/special/approot:/"+_savePath+":/upload.createSession"; //folder must exist + Networking::JsonCallback callback = new Common::Callback<OneDriveUploadRequest, Networking::JsonResponse>(this, &OneDriveUploadRequest::partUploadedCallback); + Networking::ErrorCallback failureCallback = new Common::Callback<OneDriveUploadRequest, Networking::ErrorResponse>(this, &OneDriveUploadRequest::partUploadedErrorCallback); + Networking::CurlJsonRequest *request = new OneDriveTokenRefresher(_storage, callback, failureCallback, url.c_str()); + request->addHeader("Authorization: Bearer " + _storage->accessToken()); + request->setBuffer(new byte[1], 0); //use POST + _workingRequest = ConnMan.addRequest(request); + return; + } + + Common::String url; + if (_uploadUrl == "") { + url = "https://api.onedrive.com/v1.0/drive/special/approot:/"+_savePath+":/content"; + } else { + url = _uploadUrl; + } + + Networking::JsonCallback callback = new Common::Callback<OneDriveUploadRequest, Networking::JsonResponse>(this, &OneDriveUploadRequest::partUploadedCallback); + Networking::ErrorCallback failureCallback = new Common::Callback<OneDriveUploadRequest, Networking::ErrorResponse>(this, &OneDriveUploadRequest::partUploadedErrorCallback); + Networking::CurlJsonRequest *request = new OneDriveTokenRefresher(_storage, callback, failureCallback, url.c_str()); + request->addHeader("Authorization: Bearer " + _storage->accessToken()); + request->usePut(); + + uint32 oldPos = _contentsStream->pos(); + + byte *buffer = new byte[UPLOAD_PER_ONE_REQUEST]; + uint32 size = _contentsStream->read(buffer, UPLOAD_PER_ONE_REQUEST); + request->setBuffer(buffer, size); + + //request->addHeader(Common::String::format("Content-Length: %u", size)); + if (_uploadUrl != "") + request->addHeader(Common::String::format("Content-Range: bytes %u-%u/%u", oldPos, _contentsStream->pos()-1, _contentsStream->size())); ; + + _workingRequest = ConnMan.addRequest(request); +} + +void OneDriveUploadRequest::partUploadedCallback(Networking::JsonResponse response) { + _workingRequest = nullptr; + if (_ignoreCallback) return; + + Networking::ErrorResponse error(this, false, true, "", -1); + Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)response.request; + if (rq && rq->getNetworkReadStream()) + error.httpResponseCode = rq->getNetworkReadStream()->httpResponseCode(); + + Common::JSONValue *json = response.value; + if (json) { + if (json->isObject()) { + Common::JSONObject object = json->asObject(); + + if (object.contains("error")) { + warning("OneDrive returned error: %s", json->stringify(true).c_str()); + delete json; + error.response = json->stringify(true); + finishError(error); + return; + } + + if (object.contains("id") && object.contains("name")) { + //finished + Common::String path = _savePath; //object.getVal("name")->asString();; //object.getVal("id")->asString(); + uint32 size = object.getVal("size")->asIntegerNumber(); + uint32 timestamp = ISO8601::convertToTimestamp(object.getVal("lastModifiedDateTime")->asString()); + finishSuccess(StorageFile(path, size, timestamp, false)); + return; + } + + if (_uploadUrl == "") { + if (object.contains("uploadUrl")) + _uploadUrl = object.getVal("uploadUrl")->asString(); + else + warning("no uploadUrl found in OneDrive's response"); + } + } + + if (_contentsStream->eos() || _contentsStream->pos() >= _contentsStream->size() - 1) { + warning("no file info to return"); + finishSuccess(StorageFile(_savePath, 0, 0, false)); + } else { + uploadNextPart(); + } + } else { + warning("null, not json"); + finishError(error); + } + + delete json; +} + +void OneDriveUploadRequest::partUploadedErrorCallback(Networking::ErrorResponse error) { + _workingRequest = nullptr; + if (_ignoreCallback) return; + finishError(error); +} + +void OneDriveUploadRequest::handle() {} + +void OneDriveUploadRequest::restart() { start(); } + +void OneDriveUploadRequest::finishSuccess(StorageFile file) { + Request::finishSuccess(); + if (_uploadCallback) (*_uploadCallback)(Storage::UploadResponse(this, file)); +} + +} // End of namespace OneDrive +} // End of namespace Cloud diff --git a/backends/cloud/onedrive/onedriveuploadrequest.h b/backends/cloud/onedrive/onedriveuploadrequest.h new file mode 100644 index 0000000000..09419d8a15 --- /dev/null +++ b/backends/cloud/onedrive/onedriveuploadrequest.h @@ -0,0 +1,61 @@ +/* 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_ONEDRIVE_ONEDRIVEUPLOADREQUEST_H +#define BACKENDS_CLOUD_ONEDRIVE_ONEDRIVEUPLOADREQUEST_H + +#include "backends/cloud/storage.h" +#include "backends/networking/curl/curljsonrequest.h" +#include "backends/networking/curl/request.h" +#include "common/callback.h" + +namespace Cloud { +namespace OneDrive { +class OneDriveStorage; + +class OneDriveUploadRequest: public Networking::Request { + OneDriveStorage *_storage; + Common::String _savePath; + Common::SeekableReadStream *_contentsStream; + Storage::UploadCallback _uploadCallback; + Request *_workingRequest; + bool _ignoreCallback; + Common::String _uploadUrl; + + void start(); + void uploadNextPart(); + void partUploadedCallback(Networking::JsonResponse response); + void partUploadedErrorCallback(Networking::ErrorResponse error); + void finishSuccess(StorageFile status); + +public: + OneDriveUploadRequest(OneDriveStorage *storage, Common::String path, Common::SeekableReadStream *contents, Storage::UploadCallback callback, Networking::ErrorCallback ecb); + virtual ~OneDriveUploadRequest(); + + virtual void handle(); + virtual void restart(); +}; + +} // End of namespace OneDrive +} // End of namespace Cloud + +#endif diff --git a/backends/cloud/storage.cpp b/backends/cloud/storage.cpp new file mode 100644 index 0000000000..6588b05193 --- /dev/null +++ b/backends/cloud/storage.cpp @@ -0,0 +1,42 @@ +/* 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. +* +*/ + +#include "backends/cloud/storage.h" +#include "common/file.h" + +namespace Cloud { + +Networking::Request *Storage::upload(Common::String remotePath, Common::String localPath, UploadCallback callback, Networking::ErrorCallback errorCallback) { + Common::File *f = new Common::File(); + if (!f->open(localPath)) { + warning("Storage: unable to open file to upload from"); + if (errorCallback) (*errorCallback)(Networking::ErrorResponse(nullptr, false, true, "", -1)); + delete errorCallback; + delete callback; + delete f; + return nullptr; + } + return upload(remotePath, f, callback, errorCallback); +} + +} // End of namespace Cloud + diff --git a/backends/cloud/storage.h b/backends/cloud/storage.h index 32c437857c..1d92189fa4 100644 --- a/backends/cloud/storage.h +++ b/backends/cloud/storage.h @@ -77,7 +77,7 @@ public: /** Returns UploadStatus struct with info about uploaded file. */ virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback, Networking::ErrorCallback errorCallback) = 0; - virtual Networking::Request *upload(Common::String remotePath, Common::String localPath, UploadCallback callback, Networking::ErrorCallback errorCallback) = 0; + virtual Networking::Request *upload(Common::String remotePath, Common::String localPath, UploadCallback callback, Networking::ErrorCallback errorCallback); /** Returns pointer to Networking::NetworkReadStream. */ virtual Networking::Request *streamFile(Common::String path, Networking::NetworkReadStreamCallback callback, Networking::ErrorCallback errorCallback) = 0; diff --git a/backends/module.mk b/backends/module.mk index c40781d63a..fd06e52f9d 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -23,6 +23,7 @@ ifdef USE_CLOUD MODULE_OBJS += \ cloud/iso8601.o \ cloud/manager.o \ + cloud/storage.o \ cloud/storagefile.o \ cloud/downloadrequest.o \ cloud/folderdownloadrequest.o \ @@ -32,7 +33,8 @@ MODULE_OBJS += \ cloud/dropbox/dropboxuploadrequest.o \ cloud/onedrive/onedrivestorage.o \ cloud/onedrive/onedrivetokenrefresher.o \ - cloud/onedrive/onedrivelistdirectoryrequest.o + cloud/onedrive/onedrivelistdirectoryrequest.o \ + cloud/onedrive/onedriveuploadrequest.o endif ifdef USE_LIBCURL diff --git a/backends/networking/curl/curlrequest.cpp b/backends/networking/curl/curlrequest.cpp index 861546b906..a3f997a4ff 100644 --- a/backends/networking/curl/curlrequest.cpp +++ b/backends/networking/curl/curlrequest.cpp @@ -31,7 +31,7 @@ namespace Networking { CurlRequest::CurlRequest(DataCallback cb, ErrorCallback ecb, Common::String url): - Request(cb, ecb), _url(url), _stream(nullptr), _headersList(nullptr), _bytesBuffer(nullptr), _bytesBufferSize(0) {} + Request(cb, ecb), _url(url), _stream(nullptr), _headersList(nullptr), _bytesBuffer(nullptr), _bytesBufferSize(0), _uploading(false) {} CurlRequest::~CurlRequest() { delete _stream; @@ -40,8 +40,8 @@ CurlRequest::~CurlRequest() { NetworkReadStream *CurlRequest::makeStream() { if (_bytesBuffer) - return new NetworkReadStream(_url.c_str(), _headersList, _bytesBuffer, _bytesBufferSize, true); - return new NetworkReadStream(_url.c_str(), _headersList, _postFields); + return new NetworkReadStream(_url.c_str(), _headersList, _bytesBuffer, _bytesBufferSize, _uploading, true); + return new NetworkReadStream(_url.c_str(), _headersList, _postFields, _uploading); } @@ -97,6 +97,8 @@ void CurlRequest::setBuffer(byte *buffer, uint32 size) { _bytesBufferSize = size; } +void CurlRequest::usePut() { _uploading = true; } + NetworkReadStreamResponse CurlRequest::execute() { if (!_stream) { _stream = makeStream(); diff --git a/backends/networking/curl/curlrequest.h b/backends/networking/curl/curlrequest.h index 660479e34a..5737078b2d 100644 --- a/backends/networking/curl/curlrequest.h +++ b/backends/networking/curl/curlrequest.h @@ -44,6 +44,7 @@ protected: Common::String _postFields; byte *_bytesBuffer; uint32 _bytesBufferSize; + bool _uploading; //using PUT method virtual NetworkReadStream *makeStream(); @@ -66,6 +67,9 @@ public: /** Sets bytes buffer. */ virtual void setBuffer(byte *buffer, uint32 size); + /** Remembers to use PUT method when it would create NetworkReadStream. */ + virtual void usePut(); + /** * Starts this Request with ConnMan. * @return its NetworkReadStream in NetworkReadStreamResponse. diff --git a/backends/networking/curl/networkreadstream.cpp b/backends/networking/curl/networkreadstream.cpp index f96a069e16..283e5e667f 100644 --- a/backends/networking/curl/networkreadstream.cpp +++ b/backends/networking/curl/networkreadstream.cpp @@ -35,11 +35,17 @@ static size_t curlDataCallback(char *d, size_t n, size_t l, void *p) { return 0; } -NetworkReadStream::NetworkReadStream(const char *url, curl_slist *headersList, Common::String postFields): - NetworkReadStream(url, headersList, (byte *)postFields.c_str(), postFields.size(), false) {} +static size_t curlReadDataCallback(char *d, size_t n, size_t l, void *p) { + NetworkReadStream *stream = (NetworkReadStream *)p; + if (stream) return stream->fillWithSendingContents(d, n*l); + return 0; +} + +NetworkReadStream::NetworkReadStream(const char *url, curl_slist *headersList, Common::String postFields, bool uploading): + NetworkReadStream(url, headersList, (byte *)postFields.c_str(), postFields.size(), uploading, false) {} -NetworkReadStream::NetworkReadStream(const char *url, curl_slist *headersList, byte *buffer, uint32 bufferSize, bool post) : - _easy(0), _eos(false), _requestComplete(false) { +NetworkReadStream::NetworkReadStream(const char *url, curl_slist *headersList, byte *buffer, uint32 bufferSize, bool uploading, bool post): + _easy(0), _eos(false), _requestComplete(false), _sendingContentsBuffer(nullptr), _sendingContentsSize(0), _sendingContentsPos(0) { _easy = curl_easy_init(); curl_easy_setopt(_easy, CURLOPT_WRITEFUNCTION, curlDataCallback); curl_easy_setopt(_easy, CURLOPT_WRITEDATA, this); //so callback can call us @@ -49,9 +55,17 @@ NetworkReadStream::NetworkReadStream(const char *url, curl_slist *headersList, b curl_easy_setopt(_easy, CURLOPT_VERBOSE, 0L); curl_easy_setopt(_easy, CURLOPT_FOLLOWLOCATION, 1L); //probably it's OK to have it always on curl_easy_setopt(_easy, CURLOPT_HTTPHEADER, headersList); - if (post || bufferSize != 0) { - curl_easy_setopt(_easy, CURLOPT_POSTFIELDSIZE, bufferSize); - curl_easy_setopt(_easy, CURLOPT_COPYPOSTFIELDS, buffer); + if (uploading) { + curl_easy_setopt(_easy, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(_easy, CURLOPT_READDATA, this); + curl_easy_setopt(_easy, CURLOPT_READFUNCTION, curlReadDataCallback); + _sendingContentsBuffer = buffer; + _sendingContentsSize = bufferSize; + } else { + if (post || bufferSize != 0) { + curl_easy_setopt(_easy, CURLOPT_POSTFIELDSIZE, bufferSize); + curl_easy_setopt(_easy, CURLOPT_COPYPOSTFIELDS, buffer); + } } ConnMan.registerEasyHandle(_easy); } @@ -87,4 +101,14 @@ long NetworkReadStream::httpResponseCode() const { return responseCode; } +uint32 NetworkReadStream::fillWithSendingContents(char *bufferToFill, uint32 maxSize) { + uint32 size = _sendingContentsSize - _sendingContentsPos; + if (size > maxSize) size = maxSize; + for (uint32 i = 0; i < size; ++i) { + bufferToFill[i] = _sendingContentsBuffer[_sendingContentsPos + i]; + } + _sendingContentsPos += size; + return size; +} + } // End of namespace Cloud diff --git a/backends/networking/curl/networkreadstream.h b/backends/networking/curl/networkreadstream.h index f1f41264aa..d48d01b198 100644 --- a/backends/networking/curl/networkreadstream.h +++ b/backends/networking/curl/networkreadstream.h @@ -35,10 +35,13 @@ namespace Networking { class NetworkReadStream: public Common::MemoryReadWriteStream { CURL *_easy; bool _eos, _requestComplete; + byte *_sendingContentsBuffer; + uint32 _sendingContentsSize; + uint32 _sendingContentsPos; public: - NetworkReadStream(const char *url, curl_slist *headersList, Common::String postFields); - NetworkReadStream(const char *url, curl_slist *headersList, byte *buffer, uint32 bufferSize, bool post = true); + NetworkReadStream(const char *url, curl_slist *headersList, Common::String postFields, bool uploading = false); + NetworkReadStream(const char *url, curl_slist *headersList, byte *buffer, uint32 bufferSize, bool uploading = false, bool post = true); virtual ~NetworkReadStream(); /** @@ -82,6 +85,15 @@ public: * @note This method should be called when eos() == true. */ long httpResponseCode() const; + + /** + * Fills the passed buffer with _sendingContentsBuffer contents. + * It works similarly to read(), expect it's not for reading + * Stream's contents, but for sending our own data to the server. + * + * @returns how many bytes were actually read (filled in) + */ + uint32 fillWithSendingContents(char *bufferToFill, uint32 maxSize); }; } // End of namespace Networking |