[Scummvm-git-logs] scummvm master -> 99e21f4320d86d027c6fac1884310f4f86835d66
sev-
sev at scummvm.org
Tue Nov 5 01:47:06 CET 2019
This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
2acb8e2215 JANITORIAL: Fix Networking::DataResponse typedef naming
bc63abd3e1 NETWORKING: Add CurlRequest::wait()
f7d9156967 NETWORKING: Enter SessionRequest
99e21f4320 NETWORKING: Enter Session
Commit: 2acb8e22154b621424827d8602badc93507db576
https://github.com/scummvm/scummvm/commit/2acb8e22154b621424827d8602badc93507db576
Author: Alexander Tkachev (alexander at tkachov.ru)
Date: 2019-11-05T01:47:00+01:00
Commit Message:
JANITORIAL: Fix Networking::DataResponse typedef naming
Changed paths:
backends/networking/curl/request.h
diff --git a/backends/networking/curl/request.h b/backends/networking/curl/request.h
index e23b677..efddd15 100644
--- a/backends/networking/curl/request.h
+++ b/backends/networking/curl/request.h
@@ -82,8 +82,8 @@ struct ErrorResponse {
ErrorResponse(Request *rq, bool interrupt, bool failure, Common::String resp, long httpCode);
};
-typedef Response<void *> DataReponse;
-typedef Common::BaseCallback<DataReponse> *DataCallback;
+typedef Response<void *> DataResponse;
+typedef Common::BaseCallback<DataResponse> *DataCallback;
typedef Common::BaseCallback<ErrorResponse> *ErrorCallback;
/**
Commit: bc63abd3e198a07ae6af093ae5c472379b86a9aa
https://github.com/scummvm/scummvm/commit/bc63abd3e198a07ae6af093ae5c472379b86a9aa
Author: Alexander Tkachev (alexander at tkachov.ru)
Date: 2019-11-05T01:47:00+01:00
Commit Message:
NETWORKING: Add CurlRequest::wait()
Changed paths:
backends/networking/curl/curlrequest.cpp
backends/networking/curl/curlrequest.h
diff --git a/backends/networking/curl/curlrequest.cpp b/backends/networking/curl/curlrequest.cpp
index f7d169c..887ba86 100644
--- a/backends/networking/curl/curlrequest.cpp
+++ b/backends/networking/curl/curlrequest.cpp
@@ -148,4 +148,10 @@ NetworkReadStreamResponse CurlRequest::execute() {
const NetworkReadStream *CurlRequest::getNetworkReadStream() const { return _stream; }
+void CurlRequest::wait(int spinlockDelay) {
+ while (state() == Networking::PROCESSING) {
+ g_system->delayMillis(spinlockDelay);
+ }
+}
+
} // End of namespace Networking
diff --git a/backends/networking/curl/curlrequest.h b/backends/networking/curl/curlrequest.h
index 75fb787..f8d71c4 100644
--- a/backends/networking/curl/curlrequest.h
+++ b/backends/networking/curl/curlrequest.h
@@ -93,6 +93,9 @@ public:
/** Returns Request's NetworkReadStream. */
const NetworkReadStream *getNetworkReadStream() const;
+
+ /** Waits for Request to be processed. Should be called after Request is put into ConnMan. */
+ void wait(int spinlockDelay = 5);
};
} // End of namespace Networking
Commit: f7d9156967af8005543434c64430fdf06cab7033
https://github.com/scummvm/scummvm/commit/f7d9156967af8005543434c64430fdf06cab7033
Author: Alexander Tkachev (alexander at tkachov.ru)
Date: 2019-11-05T01:47:00+01:00
Commit Message:
NETWORKING: Enter SessionRequest
It is to be used in a Session, though it might be used separately. It
must implement keep-alive, but it does not yet.
You must not put it to ConnMan by yourself (instead, use start()) and
you must call close() after you've finished using this request.
You can either work with it in callback, or wait() and simply use its
methods (check it's success() and then, for example, use text()). Like
this:
```
Networking::SessionRequest *rq = new Networking::SessionRequest(url);
rq->startAndWait();
if (rq->success())
warning("HTTP GET: %s", rq->text());
rq->close();
```
Changed paths:
A backends/networking/curl/sessionrequest.cpp
A backends/networking/curl/sessionrequest.h
backends/module.mk
diff --git a/backends/module.mk b/backends/module.mk
index 886947e..bd16546 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -66,6 +66,7 @@ MODULE_OBJS += \
networking/curl/curlrequest.o \
networking/curl/curljsonrequest.o \
networking/curl/postrequest.o \
+ networking/curl/sessionrequest.o \
networking/curl/request.o
endif
diff --git a/backends/networking/curl/sessionrequest.cpp b/backends/networking/curl/sessionrequest.cpp
new file mode 100644
index 0000000..5fe0e64
--- /dev/null
+++ b/backends/networking/curl/sessionrequest.cpp
@@ -0,0 +1,135 @@
+/* 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 <curl/curl.h>
+#include "backends/networking/curl/connectionmanager.h"
+#include "backends/networking/curl/networkreadstream.h"
+#include "backends/networking/curl/sessionrequest.h"
+#include "common/debug.h"
+#include "common/json.h"
+
+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) {}
+
+SessionRequest::~SessionRequest() {
+ delete[] _buffer;
+}
+
+char *SessionRequest::getPreparedContents() {
+ //write one more byte in the end
+ byte zero[1] = {0};
+ _contentsStream.write(zero, 1);
+
+ //replace all "bad" bytes with '.' character
+ byte *result = _contentsStream.getData();
+ uint32 size = _contentsStream.size();
+
+ //make it zero-terminated string
+ result[size - 1] = '\0';
+
+ return (char *)result;
+}
+
+void SessionRequest::finishError(ErrorResponse error) {
+ _complete = true;
+ _success = false;
+ CurlRequest::finishError(error);
+}
+
+void SessionRequest::finishSuccess() {
+ _state = PAUSED;
+ _complete = true;
+ _success = true;
+
+ if (_callback)
+ (*_callback)(DataResponse(this, text()));
+}
+
+void SessionRequest::start() {
+ if (_started) {
+ warning("Can't start() SessionRequest as it is already started");
+ } else {
+ _started = true;
+ ConnMan.addRequest(this);
+ }
+}
+
+void SessionRequest::handle() {
+ if (!_stream) _stream = makeStream();
+
+ if (_stream) {
+ uint32 readBytes = _stream->read(_buffer, CURL_SESSION_REQUEST_BUFFER_SIZE);
+ if (readBytes != 0)
+ if (_contentsStream.write(_buffer, readBytes) != readBytes)
+ warning("SessionRequest: unable to write all the bytes into MemoryWriteStreamDynamic");
+
+ if (_stream->eos()) {
+ finishSuccess();
+ }
+ }
+}
+
+void SessionRequest::restart() {
+ if (_stream)
+ delete _stream;
+ _stream = nullptr;
+ _contentsStream = Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES);
+ _text = nullptr;
+ _complete = false;
+ _success = false;
+ //with no stream available next handle() will create another one
+}
+
+void SessionRequest::close() {
+ _state = FINISHED;
+}
+
+void SessionRequest::startAndWait() {
+ start();
+ wait();
+}
+
+bool SessionRequest::complete() {
+ return _complete;
+}
+
+bool SessionRequest::success() {
+ return _success;
+}
+
+char *SessionRequest::text() {
+ if (_text == nullptr)
+ _text = getPreparedContents();
+ return _text;
+}
+
+Common::JSONValue *SessionRequest::json() {
+ return Common::JSON::parse(text());
+}
+
+} // End of namespace Networking
diff --git a/backends/networking/curl/sessionrequest.h b/backends/networking/curl/sessionrequest.h
new file mode 100644
index 0000000..590eee4
--- /dev/null
+++ b/backends/networking/curl/sessionrequest.h
@@ -0,0 +1,69 @@
+/* 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_SESSIONREQUEST_H
+#define BACKENDS_NETWORKING_CURL_SESSIONREQUEST_H
+
+#include "backends/networking/curl/curlrequest.h"
+#include "common/memstream.h"
+#include "common/json.h"
+
+namespace Networking {
+
+#define CURL_SESSION_REQUEST_BUFFER_SIZE 512 * 1024
+
+class SessionRequest: public CurlRequest {
+protected:
+ Common::MemoryWriteStreamDynamic _contentsStream;
+ byte *_buffer;
+ char *_text;
+ bool _started, _complete, _success;
+
+ /** Prepares raw bytes from _contentsStream. */
+ char *getPreparedContents();
+
+ virtual void finishError(ErrorResponse error);
+ virtual void finishSuccess();
+
+public:
+ SessionRequest(Common::String url, DataCallback cb = nullptr, ErrorCallback ecb = nullptr);
+ virtual ~SessionRequest();
+
+ virtual void start();
+ 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();
+
+ bool complete();
+ bool success();
+
+ char *text();
+ Common::JSONValue *json();
+};
+
+} // End of namespace Networking
+
+#endif
Commit: 99e21f4320d86d027c6fac1884310f4f86835d66
https://github.com/scummvm/scummvm/commit/99e21f4320d86d027c6fac1884310f4f86835d66
Author: Alexander Tkachev (alexander at tkachov.ru)
Date: 2019-11-05T01:47:00+01:00
Commit Message:
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();
```
Changed paths:
A backends/networking/curl/session.cpp
A backends/networking/curl/session.h
backends/networking/curl/curlrequest.cpp
backends/networking/curl/curlrequest.h
backends/networking/curl/networkreadstream.cpp
backends/networking/curl/networkreadstream.h
backends/networking/curl/sessionrequest.cpp
backends/networking/curl/sessionrequest.h
diff --git a/backends/networking/curl/curlrequest.cpp b/backends/networking/curl/curlrequest.cpp
index 887ba86..a3c836b 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 f8d71c4..9bca05c 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 b8f06b7..06f4dc5 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 468fce7..f8a49ea 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 0000000..260f6d8
--- /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 0000000..d3aa580
--- /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 5fe0e64..42afd63 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 590eee4..fd2757f 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();
More information about the Scummvm-git-logs
mailing list