aboutsummaryrefslogtreecommitdiff
path: root/backends/networking
diff options
context:
space:
mode:
authorAlexander Tkachev2019-11-03 02:16:00 +0700
committerEugene Sandulenko2019-11-05 01:47:00 +0100
commit99e21f4320d86d027c6fac1884310f4f86835d66 (patch)
tree80303453b0b802f5ad618a31e969204e170f3beb /backends/networking
parentf7d9156967af8005543434c64430fdf06cab7033 (diff)
downloadscummvm-rg350-99e21f4320d86d027c6fac1884310f4f86835d66.tar.gz
scummvm-rg350-99e21f4320d86d027c6fac1884310f4f86835d66.tar.bz2
scummvm-rg350-99e21f4320d86d027c6fac1884310f4f86835d66.zip
NETWORKING: Enter Session
Session allows to reuse SessionRequests to the same host by making them keeping alive connection. Turns out, though, that libcurl already does that for us, and we didn't gain any speedup we thought we'd get. Usage: ``` Networking::Session s; Networking::SessionRequest *request = s.get(url); request->startAndWait(); warning("HTTP GET: %s", request->text()); s.close(); ``` You can still use SessionRequest without Session (but you can't put them on stack!): ``` Networking::SessionRequest *request = new Networking::SessionRequest(url); request->startAndWait(); warning("HTTP GET: %s", request->text()); request->close(); ```
Diffstat (limited to 'backends/networking')
-rw-r--r--backends/networking/curl/curlrequest.cpp18
-rw-r--r--backends/networking/curl/curlrequest.h6
-rw-r--r--backends/networking/curl/networkreadstream.cpp123
-rw-r--r--backends/networking/curl/networkreadstream.h33
-rw-r--r--backends/networking/curl/session.cpp77
-rw-r--r--backends/networking/curl/session.h45
-rw-r--r--backends/networking/curl/sessionrequest.cpp68
-rw-r--r--backends/networking/curl/sessionrequest.h12
8 files changed, 302 insertions, 80 deletions
diff --git a/backends/networking/curl/curlrequest.cpp b/backends/networking/curl/curlrequest.cpp
index 887ba86c6e..a3c836b7c4 100644
--- a/backends/networking/curl/curlrequest.cpp
+++ b/backends/networking/curl/curlrequest.cpp
@@ -32,7 +32,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), _uploading(false), _usingPatch(false) {}
+ _bytesBufferSize(0), _uploading(false), _usingPatch(false), _keepAlive(false), _keepAliveIdle(120), _keepAliveInterval(60) {}
CurlRequest::~CurlRequest() {
delete _stream;
@@ -41,10 +41,10 @@ CurlRequest::~CurlRequest() {
NetworkReadStream *CurlRequest::makeStream() {
if (_bytesBuffer)
- return new NetworkReadStream(_url.c_str(), _headersList, _bytesBuffer, _bytesBufferSize, _uploading, _usingPatch, true);
+ return new NetworkReadStream(_url.c_str(), _headersList, _bytesBuffer, _bytesBufferSize, _uploading, _usingPatch, true, _keepAlive, _keepAliveIdle, _keepAliveInterval);
if (!_formFields.empty() || !_formFiles.empty())
- return new NetworkReadStream(_url.c_str(), _headersList, _formFields, _formFiles);
- return new NetworkReadStream(_url.c_str(), _headersList, _postFields, _uploading, _usingPatch);
+ return new NetworkReadStream(_url.c_str(), _headersList, _formFields, _formFiles, _keepAlive, _keepAliveIdle, _keepAliveInterval);
+ return new NetworkReadStream(_url.c_str(), _headersList, _postFields, _uploading, _usingPatch, _keepAlive, _keepAliveIdle, _keepAliveInterval);
}
void CurlRequest::handle() {
@@ -137,6 +137,16 @@ void CurlRequest::usePut() { _uploading = true; }
void CurlRequest::usePatch() { _usingPatch = true; }
+void CurlRequest::connectionKeepAlive(long idle, long interval) {
+ _keepAlive = true;
+ _keepAliveIdle = idle;
+ _keepAliveInterval = interval;
+}
+
+void CurlRequest::connectionClose() {
+ _keepAlive = false;
+}
+
NetworkReadStreamResponse CurlRequest::execute() {
if (!_stream) {
_stream = makeStream();
diff --git a/backends/networking/curl/curlrequest.h b/backends/networking/curl/curlrequest.h
index f8d71c4828..9bca05c771 100644
--- a/backends/networking/curl/curlrequest.h
+++ b/backends/networking/curl/curlrequest.h
@@ -50,6 +50,8 @@ protected:
uint32 _bytesBufferSize;
bool _uploading; //using PUT method
bool _usingPatch; //using PATCH method
+ bool _keepAlive;
+ long _keepAliveIdle, _keepAliveInterval;
virtual NetworkReadStream *makeStream();
@@ -85,6 +87,10 @@ public:
/** Remembers to use PATCH method when it would create NetworkReadStream. */
virtual void usePatch();
+ /** Remembers to use Connection: keep-alive or close. */
+ virtual void connectionKeepAlive(long idle = 120, long interval = 60);
+ virtual void connectionClose();
+
/**
* 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 b8f06b728f..06f4dc52a8 100644
--- a/backends/networking/curl/networkreadstream.cpp
+++ b/backends/networking/curl/networkreadstream.cpp
@@ -63,13 +63,18 @@ int NetworkReadStream::curlProgressCallbackOlder(void *p, double dltotal, double
return curlProgressCallback(p, (curl_off_t)dltotal, (curl_off_t)dlnow, (curl_off_t)ultotal, (curl_off_t)ulnow);
}
-void NetworkReadStream::init(const char *url, curl_slist *headersList, const byte *buffer, uint32 bufferSize, bool uploading, bool usingPatch, bool post) {
+void NetworkReadStream::resetStream() {
_eos = _requestComplete = false;
- _errorBuffer = (char *)calloc(CURL_ERROR_SIZE, 1);
+ if (!_errorBuffer)
+ _errorBuffer = (char *)calloc(CURL_ERROR_SIZE, 1);
_sendingContentsBuffer = nullptr;
_sendingContentsSize = _sendingContentsPos = 0;
_progressDownloaded = _progressTotal = 0;
_bufferCopy = nullptr;
+}
+
+void NetworkReadStream::initCurl(const char *url, curl_slist *headersList) {
+ resetStream();
_easy = curl_easy_init();
curl_easy_setopt(_easy, CURLOPT_WRITEFUNCTION, curlDataCallback);
@@ -102,6 +107,30 @@ void NetworkReadStream::init(const char *url, curl_slist *headersList, const byt
curl_easy_setopt(_easy, CURLOPT_XFERINFOFUNCTION, curlProgressCallback);
curl_easy_setopt(_easy, CURLOPT_XFERINFODATA, this);
#endif
+
+ if (_keepAlive) {
+ curl_easy_setopt(_easy, CURLOPT_TCP_KEEPALIVE, 1L);
+ curl_easy_setopt(_easy, CURLOPT_TCP_KEEPIDLE, _keepAliveIdle);
+ curl_easy_setopt(_easy, CURLOPT_TCP_KEEPINTVL, _keepAliveInterval);
+ }
+}
+
+bool NetworkReadStream::reuseCurl(const char *url, curl_slist *headersList) {
+ if (!_keepAlive) {
+ warning("NetworkReadStream: Can't reuse curl handle (was not setup as keep-alive)");
+ return false;
+ }
+
+ resetStream();
+
+ curl_easy_setopt(_easy, CURLOPT_URL, url);
+ curl_easy_setopt(_easy, CURLOPT_HTTPHEADER, headersList);
+ curl_easy_setopt(_easy, CURLOPT_USERAGENT, gScummVMFullVersion); // in case headersList rewrites it
+
+ return true;
+}
+
+void NetworkReadStream::setupBufferContents(const byte *buffer, uint32 bufferSize, bool uploading, bool usingPatch, bool post) {
if (uploading) {
curl_easy_setopt(_easy, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(_easy, CURLOPT_READDATA, this);
@@ -126,46 +155,7 @@ void NetworkReadStream::init(const char *url, curl_slist *headersList, const byt
ConnMan.registerEasyHandle(_easy);
}
-void NetworkReadStream::init(const char *url, curl_slist *headersList, Common::HashMap<Common::String, Common::String> formFields, Common::HashMap<Common::String, Common::String> formFiles) {
- _eos = _requestComplete = false;
- _errorBuffer = (char *)calloc(CURL_ERROR_SIZE, 1);
- _sendingContentsBuffer = nullptr;
- _sendingContentsSize = _sendingContentsPos = 0;
- _progressDownloaded = _progressTotal = 0;
- _bufferCopy = nullptr;
-
- _easy = curl_easy_init();
- curl_easy_setopt(_easy, CURLOPT_WRITEFUNCTION, curlDataCallback);
- curl_easy_setopt(_easy, CURLOPT_WRITEDATA, this); //so callback can call us
- curl_easy_setopt(_easy, CURLOPT_PRIVATE, this); //so ConnectionManager can call us when request is complete
- curl_easy_setopt(_easy, CURLOPT_HEADER, 0L);
- curl_easy_setopt(_easy, CURLOPT_HEADERDATA, this);
- curl_easy_setopt(_easy, CURLOPT_HEADERFUNCTION, curlHeadersCallback);
- curl_easy_setopt(_easy, CURLOPT_URL, url);
- curl_easy_setopt(_easy, CURLOPT_ERRORBUFFER, _errorBuffer);
- 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);
- curl_easy_setopt(_easy, CURLOPT_USERAGENT, gScummVMFullVersion);
- curl_easy_setopt(_easy, CURLOPT_NOPROGRESS, 0L);
- curl_easy_setopt(_easy, CURLOPT_PROGRESSFUNCTION, curlProgressCallbackOlder);
- curl_easy_setopt(_easy, CURLOPT_PROGRESSDATA, this);
-#if defined NINTENDO_SWITCH || defined ANDROID_PLAIN_PORT
- curl_easy_setopt(_easy, CURLOPT_SSL_VERIFYPEER, 0);
-#endif
-
- const char *caCertPath = ConnMan.getCaCertPath();
- if (caCertPath) {
- curl_easy_setopt(_easy, CURLOPT_CAINFO, caCertPath);
- }
-
-#if LIBCURL_VERSION_NUM >= 0x072000
- // CURLOPT_XFERINFOFUNCTION introduced in libcurl 7.32.0
- // CURLOPT_PROGRESSFUNCTION is used as a backup plan in case older version is used
- curl_easy_setopt(_easy, CURLOPT_XFERINFOFUNCTION, curlProgressCallback);
- curl_easy_setopt(_easy, CURLOPT_XFERINFODATA, this);
-#endif
-
+void NetworkReadStream::setupFormMultipart(Common::HashMap<Common::String, Common::String> formFields, Common::HashMap<Common::String, Common::String> formFiles) {
// set POST multipart upload form fields/files
struct curl_httppost *formpost = nullptr;
struct curl_httppost *lastptr = nullptr;
@@ -197,23 +187,52 @@ void NetworkReadStream::init(const char *url, curl_slist *headersList, Common::H
}
curl_easy_setopt(_easy, CURLOPT_HTTPPOST, formpost);
-
ConnMan.registerEasyHandle(_easy);
}
-NetworkReadStream::NetworkReadStream(const char *url, curl_slist *headersList, Common::String postFields, bool uploading, bool usingPatch) :
- _backingStream(DisposeAfterUse::YES) {
- init(url, headersList, (const byte *)postFields.c_str(), postFields.size(), uploading, usingPatch, false);
+NetworkReadStream::NetworkReadStream(const char *url, curl_slist *headersList, Common::String postFields, bool uploading, bool usingPatch, bool keepAlive, long keepAliveIdle, long keepAliveInterval):
+ _backingStream(DisposeAfterUse::YES), _keepAlive(keepAlive), _keepAliveIdle(keepAliveIdle), _keepAliveInterval(keepAliveInterval), _errorBuffer(nullptr) {
+ initCurl(url, headersList);
+ setupBufferContents((const byte *)postFields.c_str(), postFields.size(), uploading, usingPatch, false);
+}
+
+NetworkReadStream::NetworkReadStream(const char *url, curl_slist *headersList, Common::HashMap<Common::String, Common::String> formFields, Common::HashMap<Common::String, Common::String> formFiles, bool keepAlive, long keepAliveIdle, long keepAliveInterval):
+ _backingStream(DisposeAfterUse::YES), _keepAlive(keepAlive), _keepAliveIdle(keepAliveIdle), _keepAliveInterval(keepAliveInterval), _errorBuffer(nullptr) {
+ initCurl(url, headersList);
+ setupFormMultipart(formFields, formFiles);
}
-NetworkReadStream::NetworkReadStream(const char *url, curl_slist *headersList, Common::HashMap<Common::String, Common::String> formFields, Common::HashMap<Common::String, Common::String> formFiles) :
- _backingStream(DisposeAfterUse::YES) {
- init(url, headersList, formFields, formFiles);
+NetworkReadStream::NetworkReadStream(const char *url, curl_slist *headersList, const byte *buffer, uint32 bufferSize, bool uploading, bool usingPatch, bool post, bool keepAlive, long keepAliveIdle, long keepAliveInterval):
+ _backingStream(DisposeAfterUse::YES), _keepAlive(keepAlive), _keepAliveIdle(keepAliveIdle), _keepAliveInterval(keepAliveInterval), _errorBuffer(nullptr) {
+ initCurl(url, headersList);
+ setupBufferContents(buffer, bufferSize, uploading, usingPatch, post);
}
-NetworkReadStream::NetworkReadStream(const char *url, curl_slist *headersList, const byte *buffer, uint32 bufferSize, bool uploading, bool usingPatch, bool post) :
- _backingStream(DisposeAfterUse::YES) {
- init(url, headersList, buffer, bufferSize, uploading, usingPatch, post);
+bool NetworkReadStream::reuse(const char *url, curl_slist *headersList, Common::String postFields, bool uploading, bool usingPatch) {
+ if (!reuseCurl(url, headersList))
+ return false;
+
+ _backingStream = Common::MemoryReadWriteStream(DisposeAfterUse::YES);
+ setupBufferContents((const byte *)postFields.c_str(), postFields.size(), uploading, usingPatch, false);
+ return true;
+}
+
+bool NetworkReadStream::reuse(const char *url, curl_slist *headersList, Common::HashMap<Common::String, Common::String> formFields, Common::HashMap<Common::String, Common::String> formFiles) {
+ if (!reuseCurl(url, headersList))
+ return false;
+
+ _backingStream = Common::MemoryReadWriteStream(DisposeAfterUse::YES);
+ setupFormMultipart(formFields, formFiles);
+ return true;
+}
+
+bool NetworkReadStream::reuse(const char *url, curl_slist *headersList, const byte *buffer, uint32 bufferSize, bool uploading, bool usingPatch, bool post) {
+ if (!reuseCurl(url, headersList))
+ return false;
+
+ _backingStream = Common::MemoryReadWriteStream(DisposeAfterUse::YES);
+ setupBufferContents(buffer, bufferSize, uploading, usingPatch, post);
+ return true;
}
NetworkReadStream::~NetworkReadStream() {
diff --git a/backends/networking/curl/networkreadstream.h b/backends/networking/curl/networkreadstream.h
index 468fce70a4..f8a49ea18f 100644
--- a/backends/networking/curl/networkreadstream.h
+++ b/backends/networking/curl/networkreadstream.h
@@ -37,16 +37,22 @@ namespace Networking {
class NetworkReadStream: public Common::ReadStream {
CURL *_easy;
Common::MemoryReadWriteStream _backingStream;
+ bool _keepAlive;
+ long _keepAliveIdle, _keepAliveInterval;
bool _eos, _requestComplete;
char *_errorBuffer;
const byte *_sendingContentsBuffer;
uint32 _sendingContentsSize;
uint32 _sendingContentsPos;
- byte* _bufferCopy; // To use with old curl version where CURLOPT_COPYPOSTFIELDS is not available
+ byte *_bufferCopy; // To use with old curl version where CURLOPT_COPYPOSTFIELDS is not available
Common::String _responseHeaders;
uint64 _progressDownloaded, _progressTotal;
- void init(const char *url, curl_slist *headersList, const byte *buffer, uint32 bufferSize, bool uploading, bool usingPatch, bool post);
- void init(const char *url, curl_slist *headersList, Common::HashMap<Common::String, Common::String> formFields, Common::HashMap<Common::String, Common::String> formFiles);
+
+ void resetStream();
+ void initCurl(const char *url, curl_slist *headersList);
+ bool reuseCurl(const char *url, curl_slist *headersList);
+ void setupBufferContents(const byte *buffer, uint32 bufferSize, bool uploading, bool usingPatch, bool post);
+ void setupFormMultipart(Common::HashMap<Common::String, Common::String> formFields, Common::HashMap<Common::String, Common::String> formFiles);
/**
* Fills the passed buffer with _sendingContentsBuffer contents.
@@ -70,16 +76,27 @@ class NetworkReadStream: public Common::ReadStream {
static int curlProgressCallbackOlder(void *p, double dltotal, double dlnow, double ultotal, double ulnow);
public:
/** Send <postFields>, using POST by default. */
- NetworkReadStream(const char *url, curl_slist *headersList, Common::String postFields, bool uploading = false, bool usingPatch = false);
+ NetworkReadStream(const char *url, curl_slist *headersList, Common::String postFields, bool uploading = false, bool usingPatch = false, bool keepAlive = false, long keepAliveIdle = 120, long keepAliveInterval = 60);
/** Send <formFields>, <formFiles>, using POST multipart/form. */
NetworkReadStream(
const char *url, curl_slist *headersList,
Common::HashMap<Common::String, Common::String> formFields,
- Common::HashMap<Common::String, Common::String> formFiles);
- /** Send <buffer, using POST by default. */
- NetworkReadStream(const char *url, curl_slist *headersList, const byte *buffer, uint32 bufferSize, bool uploading = false, bool usingPatch = false, bool post = true);
+ Common::HashMap<Common::String, Common::String> formFiles,
+ bool keepAlive = false, long keepAliveIdle = 120, long keepAliveInterval = 60);
+ /** Send <buffer>, using POST by default. */
+ NetworkReadStream(const char *url, curl_slist *headersList, const byte *buffer, uint32 bufferSize, bool uploading = false, bool usingPatch = false, bool post = true, bool keepAlive = false, long keepAliveIdle = 120, long keepAliveInterval = 60);
virtual ~NetworkReadStream();
+ /** Send <postFields>, using POST by default. */
+ bool reuse(const char *url, curl_slist *headersList, Common::String postFields, bool uploading = false, bool usingPatch = false);
+ /** Send <formFields>, <formFiles>, using POST multipart/form. */
+ bool reuse(
+ const char *url, curl_slist *headersList,
+ Common::HashMap<Common::String, Common::String> formFields,
+ Common::HashMap<Common::String, Common::String> formFiles);
+ /** Send <buffer>, using POST by default. */
+ bool reuse(const char *url, curl_slist *headersList, const byte *buffer, uint32 bufferSize, bool uploading = false, bool usingPatch = false, bool post = true);
+
/**
* Returns true if a read failed because the stream end has been reached.
* This flag is cleared by clearErr().
@@ -150,6 +167,8 @@ public:
/** Used in curl progress callback to pass current downloaded/total values. */
void setProgress(uint64 downloaded, uint64 total);
+
+ bool keepAlive() const { return _keepAlive; }
};
} // End of namespace Networking
diff --git a/backends/networking/curl/session.cpp b/backends/networking/curl/session.cpp
new file mode 100644
index 0000000000..260f6d85c8
--- /dev/null
+++ b/backends/networking/curl/session.cpp
@@ -0,0 +1,77 @@
+/* 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/networking/curl/session.h"
+
+namespace Networking {
+
+Session::Session(Common::String prefix):
+ _prefix(prefix), _request(nullptr) {}
+
+Session::~Session() {
+ close();
+}
+
+SessionRequest *Session::get(Common::String url, DataCallback cb, ErrorCallback ecb) {
+ // check url prefix
+ if (!_prefix.empty()) {
+ if (url.contains("://")) {
+ if (url.size() < _prefix.size() || url.find(_prefix) != 0) {
+ warning("Session: given URL does not match the prefix!\n\t%s\n\t%s", url.c_str(), _prefix.c_str());
+ return nullptr;
+ }
+ } else {
+ // if no schema given, just append <url> to <_prefix>
+ Common::String newUrl = _prefix;
+ if (newUrl.lastChar() != '/' && (url.size() > 0 && url.firstChar() != '/'))
+ newUrl += "/";
+ newUrl += url;
+ url = newUrl;
+ }
+ }
+
+ // check if request has finished (ready to be replaced)
+ if (_request) {
+ if (!_request->complete()) {
+ warning("Session: can't reuse Request that is being processed");
+ return nullptr;
+ }
+ }
+
+ if (!_request) {
+ _request = new Networking::SessionRequest(url, cb, ecb); // automatically added to ConnMan
+ _request->connectionKeepAlive();
+ } else {
+ _request->reuse(url, cb, ecb);
+ }
+
+ return _request;
+}
+
+void Session::close() {
+ if (_request)
+ _request->close();
+}
+
+} // End of namespace Networking
diff --git a/backends/networking/curl/session.h b/backends/networking/curl/session.h
new file mode 100644
index 0000000000..d3aa5807a7
--- /dev/null
+++ b/backends/networking/curl/session.h
@@ -0,0 +1,45 @@
+/* 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_NETWORKING_CURL_SESSION_H
+#define BACKENDS_NETWORKING_CURL_SESSION_H
+
+#include "backends/networking/curl/sessionrequest.h"
+
+namespace Networking {
+
+class Session {
+protected:
+ Common::String _prefix;
+ SessionRequest *_request;
+
+public:
+ Session(Common::String prefix = "");
+ ~Session();
+
+ SessionRequest *get(Common::String url, DataCallback cb = nullptr, ErrorCallback ecb = nullptr);
+ void close();
+};
+
+} // End of namespace Networking
+
+#endif
diff --git a/backends/networking/curl/sessionrequest.cpp b/backends/networking/curl/sessionrequest.cpp
index 5fe0e64aa1..42afd6387b 100644
--- a/backends/networking/curl/sessionrequest.cpp
+++ b/backends/networking/curl/sessionrequest.cpp
@@ -34,12 +34,32 @@ namespace Networking {
SessionRequest::SessionRequest(Common::String url, DataCallback cb, ErrorCallback ecb):
CurlRequest(cb, ecb, url), _contentsStream(DisposeAfterUse::YES),
_buffer(new byte[CURL_SESSION_REQUEST_BUFFER_SIZE]), _text(nullptr),
- _started(false), _complete(false), _success(false) {}
+ _started(false), _complete(false), _success(false) {
+
+ // automatically go under ConnMan control so nobody would be able to leak the memory
+ // but, we don't need it to be working just yet
+ _state = PAUSED;
+ ConnMan.addRequest(this);
+}
SessionRequest::~SessionRequest() {
delete[] _buffer;
}
+bool SessionRequest::reuseStream() {
+ if (!_stream) {
+ return false;
+ }
+
+ if (_bytesBuffer)
+ return _stream->reuse(_url.c_str(), _headersList, _bytesBuffer, _bytesBufferSize, _uploading, _usingPatch, true);
+
+ if (!_formFields.empty() || !_formFiles.empty())
+ return _stream->reuse(_url.c_str(), _headersList, _formFields, _formFiles);
+
+ return _stream->reuse(_url.c_str(), _headersList, _postFields, _uploading, _usingPatch);
+}
+
char *SessionRequest::getPreparedContents() {
//write one more byte in the end
byte zero[1] = {0};
@@ -71,12 +91,29 @@ void SessionRequest::finishSuccess() {
}
void SessionRequest::start() {
- if (_started) {
+ if (_state != PAUSED || _started) {
warning("Can't start() SessionRequest as it is already started");
- } else {
- _started = true;
- ConnMan.addRequest(this);
+ return;
}
+
+ _state = PROCESSING;
+ _started = true;
+}
+
+void SessionRequest::startAndWait() {
+ start();
+ wait();
+}
+
+void SessionRequest::reuse(Common::String url, DataCallback cb, ErrorCallback ecb) {
+ _url = url;
+
+ delete _callback;
+ delete _errorCallback;
+ _callback = cb;
+ _errorCallback = ecb;
+
+ restart();
}
void SessionRequest::handle() {
@@ -95,13 +132,23 @@ void SessionRequest::handle() {
}
void SessionRequest::restart() {
- if (_stream)
- delete _stream;
- _stream = nullptr;
+ if (_stream) {
+ bool deleteStream = true;
+ if (_keepAlive && reuseStream()) {
+ deleteStream = false;
+ }
+
+ if (deleteStream) {
+ delete _stream;
+ _stream = nullptr;
+ }
+ }
+
_contentsStream = Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES);
_text = nullptr;
_complete = false;
_success = false;
+ _started = false;
//with no stream available next handle() will create another one
}
@@ -109,11 +156,6 @@ void SessionRequest::close() {
_state = FINISHED;
}
-void SessionRequest::startAndWait() {
- start();
- wait();
-}
-
bool SessionRequest::complete() {
return _complete;
}
diff --git a/backends/networking/curl/sessionrequest.h b/backends/networking/curl/sessionrequest.h
index 590eee4a5a..fd2757fcd2 100644
--- a/backends/networking/curl/sessionrequest.h
+++ b/backends/networking/curl/sessionrequest.h
@@ -38,6 +38,8 @@ protected:
char *_text;
bool _started, _complete, _success;
+ bool reuseStream();
+
/** Prepares raw bytes from _contentsStream. */
char *getPreparedContents();
@@ -48,14 +50,16 @@ public:
SessionRequest(Common::String url, DataCallback cb = nullptr, ErrorCallback ecb = nullptr);
virtual ~SessionRequest();
- virtual void start();
+ void start();
+ void startAndWait();
+
+ void reuse(Common::String url, DataCallback cb = nullptr, ErrorCallback ecb = nullptr);
+
virtual void handle();
virtual void restart();
/** This request DOES NOT delete automatically after calling callbacks. It gets PAUSED, and in order to make it FINISHED (i.e. delete), this method MUST be called. */
- virtual void close();
-
- void startAndWait();
+ void close();
bool complete();
bool success();