aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backends/cloud/dropbox/dropboxstorage.cpp13
-rw-r--r--backends/cloud/dropbox/dropboxstorage.h3
-rw-r--r--backends/cloud/onedrive/onedrivestorage.cpp19
-rw-r--r--backends/cloud/onedrive/onedrivestorage.h4
-rw-r--r--backends/cloud/onedrive/onedrivetokenrefresher.cpp2
-rw-r--r--backends/cloud/onedrive/onedriveuploadrequest.cpp171
-rw-r--r--backends/cloud/onedrive/onedriveuploadrequest.h61
-rw-r--r--backends/cloud/storage.cpp42
-rw-r--r--backends/cloud/storage.h2
-rw-r--r--backends/module.mk4
-rw-r--r--backends/networking/curl/curlrequest.cpp8
-rw-r--r--backends/networking/curl/curlrequest.h4
-rw-r--r--backends/networking/curl/networkreadstream.cpp38
-rw-r--r--backends/networking/curl/networkreadstream.h16
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