diff options
Diffstat (limited to 'src/network/access/qnetworkreplywasmimpl.cpp')
-rw-r--r-- | src/network/access/qnetworkreplywasmimpl.cpp | 178 |
1 files changed, 118 insertions, 60 deletions
diff --git a/src/network/access/qnetworkreplywasmimpl.cpp b/src/network/access/qnetworkreplywasmimpl.cpp index c02f0b4e61..ccf1542958 100644 --- a/src/network/access/qnetworkreplywasmimpl.cpp +++ b/src/network/access/qnetworkreplywasmimpl.cpp @@ -4,11 +4,11 @@ #include "qnetworkreplywasmimpl_p.h" #include "qnetworkrequest.h" -#include <QtCore/qtimer.h> #include <QtCore/qdatetime.h> #include <QtCore/qcoreapplication.h> #include <QtCore/qfileinfo.h> #include <QtCore/qthread.h> +#include <QtCore/private/qeventdispatcher_wasm_p.h> #include <QtCore/private/qoffsetstringarray_p.h> #include <QtCore/private/qtools_p.h> @@ -63,11 +63,27 @@ QNetworkReplyWasmImplPrivate::QNetworkReplyWasmImplPrivate() , totalDownloadSize(0) , percentFinished(0) , m_fetch(nullptr) + , m_fetchContext(nullptr) { } QNetworkReplyWasmImplPrivate::~QNetworkReplyWasmImplPrivate() { + + if (m_fetchContext) { // fetch has been initiated + std::unique_lock lock{ m_fetchContext->mutex }; + + if (m_fetchContext->state == FetchContext::State::SCHEDULED + || m_fetchContext->state == FetchContext::State::SENT + || m_fetchContext->state == FetchContext::State::CANCELED) { + m_fetchContext->reply = nullptr; + m_fetchContext->state = FetchContext::State::TO_BE_DESTROYED; + } else if (m_fetchContext->state == FetchContext::State::FINISHED) { + lock.unlock(); + delete m_fetchContext; + } + } + } QNetworkReplyWasmImpl::QNetworkReplyWasmImpl(QObject *parent) @@ -116,7 +132,7 @@ void QNetworkReplyWasmImpl::close() d->state = QNetworkReplyPrivate::Finished; d->setCanceled(); } - + emscripten_fetch_close(d->m_fetch); QNetworkReply::close(); } @@ -134,8 +150,14 @@ void QNetworkReplyWasmImpl::abort() void QNetworkReplyWasmImplPrivate::setCanceled() { Q_Q(QNetworkReplyWasmImpl); - if (m_fetch) - m_fetch->userData = nullptr; + { + if (m_fetchContext) { + std::scoped_lock lock{ m_fetchContext->mutex }; + if (m_fetchContext->state == FetchContext::State::SCHEDULED + || m_fetchContext->state == FetchContext::State::SENT) + m_fetchContext->state = FetchContext::State::CANCELED; + } + } emitReplyError(QNetworkReply::OperationCanceledError, QStringLiteral("Operation canceled")); q->setFinished(true); @@ -227,48 +249,7 @@ void QNetworkReplyWasmImplPrivate::doSendRequest() emscripten_fetch_attr_t attr; emscripten_fetch_attr_init(&attr); - strcpy(attr.requestMethod, q->methodName().constData()); - - QList<QByteArray> headersData = request.rawHeaderList(); - int arrayLength = getArraySize(headersData.count()); - const char *customHeaders[arrayLength]; - QStringList trimmedHeaders; - - if (headersData.count() > 0) { - int i = 0; - for (const auto &headerName : headersData) { - if (isUnsafeHeader(QLatin1StringView(headerName.constData()))) { - trimmedHeaders.push_back(QString::fromLatin1(headerName)); - } else { - customHeaders[i++] = headerName.constData(); - customHeaders[i++] = request.rawHeader(headerName).constData(); - } - } - if (!trimmedHeaders.isEmpty()) { - qWarning() << "Qt has trimmed the following forbidden headers from the request:" - << trimmedHeaders.join(QLatin1StringView(", ")); - } - customHeaders[i] = nullptr; - attr.requestHeaders = customHeaders; - } - - if (outgoingData) { // data from post request - // handle extra data - requestData = outgoingData->readAll(); // is there a size restriction here? - if (!requestData.isEmpty()) { - attr.requestData = requestData.data(); - attr.requestDataSize = requestData.size(); - } - } - - QByteArray userName, password; - // username & password - if (!request.url().userInfo().isEmpty()) { - userName = request.url().userName().toUtf8(); - password = request.url().password().toUtf8(); - attr.userName = userName.constData(); - attr.password = password.constData(); - } + qstrncpy(attr.requestMethod, q->methodName().constData(), 32); // requestMethod is char[32] in emscripten attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY; @@ -293,13 +274,67 @@ void QNetworkReplyWasmImplPrivate::doSendRequest() attr.onprogress = QNetworkReplyWasmImplPrivate::downloadProgress; attr.onreadystatechange = QNetworkReplyWasmImplPrivate::stateChange; attr.timeoutMSecs = request.transferTimeout(); - attr.userData = reinterpret_cast<void *>(this); - QString dPath = "/home/web_user/"_L1 + request.url().fileName(); - QByteArray destinationPath = dPath.toUtf8(); - attr.destinationPath = destinationPath.constData(); + m_fetchContext = new FetchContext(this);; + attr.userData = static_cast<void *>(m_fetchContext); + if (outgoingData) { // data from post request + m_fetchContext->requestData = outgoingData->readAll(); // is there a size restriction here? + if (!m_fetchContext->requestData.isEmpty()) { + attr.requestData = m_fetchContext->requestData.data(); + attr.requestDataSize = m_fetchContext->requestData.size(); + } + } - m_fetch = emscripten_fetch(&attr, request.url().toString().toUtf8().constData()); + QEventDispatcherWasm::runOnMainThread([attr, fetchContext = m_fetchContext]() mutable { + std::unique_lock lock{ fetchContext->mutex }; + if (fetchContext->state == FetchContext::State::CANCELED) { + fetchContext->state = FetchContext::State::FINISHED; + return; + } else if (fetchContext->state == FetchContext::State::TO_BE_DESTROYED) { + lock.unlock(); + delete fetchContext; + return; + } + const auto reply = fetchContext->reply; + const auto &request = reply->request; + + QByteArray userName, password; + if (!request.url().userInfo().isEmpty()) { + userName = request.url().userName().toUtf8(); + password = request.url().password().toUtf8(); + attr.userName = userName.constData(); + attr.password = password.constData(); + } + + QList<QByteArray> headersData = request.rawHeaderList(); + int arrayLength = getArraySize(headersData.count()); + const char *customHeaders[arrayLength]; + QStringList trimmedHeaders; + if (headersData.count() > 0) { + int i = 0; + for (const auto &headerName : headersData) { + if (isUnsafeHeader(QLatin1StringView(headerName.constData()))) { + trimmedHeaders.push_back(QString::fromLatin1(headerName)); + } else { + customHeaders[i++] = headerName.constData(); + customHeaders[i++] = request.rawHeader(headerName).constData(); + } + } + if (!trimmedHeaders.isEmpty()) { + qWarning() << "Qt has trimmed the following forbidden headers from the request:" + << trimmedHeaders.join(QLatin1StringView(", ")); + } + customHeaders[i] = nullptr; + attr.requestHeaders = customHeaders; + } + + auto url = request.url().toString().toUtf8(); + QString dPath = "/home/web_user/"_L1 + request.url().fileName(); + QByteArray destinationPath = dPath.toUtf8(); + attr.destinationPath = destinationPath.constData(); + reply->m_fetch = emscripten_fetch(&attr, url.constData()); + fetchContext->state = FetchContext::State::SENT; + }); state = Working; } @@ -477,8 +512,18 @@ void QNetworkReplyWasmImplPrivate::_q_bufferOutgoingData() void QNetworkReplyWasmImplPrivate::downloadSucceeded(emscripten_fetch_t *fetch) { - auto reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData); - if (reply) { + auto fetchContext = static_cast<FetchContext *>(fetch->userData); + std::unique_lock lock{ fetchContext->mutex }; + + if (fetchContext->state == FetchContext::State::TO_BE_DESTROYED) { + lock.unlock(); + delete fetchContext; + return; + } else if (fetchContext->state == FetchContext::State::CANCELED) { + fetchContext->state = FetchContext::State::FINISHED; + return; + } else if (fetchContext->state == FetchContext::State::SENT) { + const auto reply = fetchContext->reply; if (reply->state != QNetworkReplyPrivate::Aborted) { QByteArray buffer(fetch->data, fetch->numBytes); reply->dataReceived(buffer); @@ -487,8 +532,8 @@ void QNetworkReplyWasmImplPrivate::downloadSucceeded(emscripten_fetch_t *fetch) reply->setReplyFinished(); } reply->m_fetch = nullptr; + fetchContext->state = FetchContext::State::FINISHED; } - emscripten_fetch_close(fetch); } void QNetworkReplyWasmImplPrivate::setReplyFinished() @@ -509,7 +554,8 @@ void QNetworkReplyWasmImplPrivate::setStatusCode(int status, const QByteArray &s void QNetworkReplyWasmImplPrivate::stateChange(emscripten_fetch_t *fetch) { - auto reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData); + const auto fetchContext = static_cast<FetchContext*>(fetch->userData); + const auto reply = fetchContext->reply; if (reply && reply->state != QNetworkReplyPrivate::Aborted) { if (fetch->readyState == /*HEADERS_RECEIVED*/ 2) { size_t headerLength = emscripten_fetch_get_response_headers_length(fetch); @@ -522,7 +568,8 @@ void QNetworkReplyWasmImplPrivate::stateChange(emscripten_fetch_t *fetch) void QNetworkReplyWasmImplPrivate::downloadProgress(emscripten_fetch_t *fetch) { - auto reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData); + const auto fetchContext = static_cast<FetchContext*>(fetch->userData); + const auto reply = fetchContext->reply; if (reply && reply->state != QNetworkReplyPrivate::Aborted) { if (fetch->status < 400) { uint64_t bytes = fetch->dataOffset + fetch->numBytes; @@ -536,8 +583,18 @@ void QNetworkReplyWasmImplPrivate::downloadProgress(emscripten_fetch_t *fetch) void QNetworkReplyWasmImplPrivate::downloadFailed(emscripten_fetch_t *fetch) { - auto reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData); - if (reply) { + const auto fetchContext = static_cast<FetchContext*>(fetch->userData); + std::unique_lock lock{ fetchContext->mutex }; + + if (fetchContext->state == FetchContext::State::TO_BE_DESTROYED) { + lock.unlock(); + delete fetchContext; + return; + } else if (fetchContext->state == FetchContext::State::CANCELED) { + fetchContext->state = FetchContext::State::FINISHED; + return; + } else if (fetchContext->state == FetchContext::State::SENT) { + const auto reply = fetchContext->reply; if (reply->state != QNetworkReplyPrivate::Aborted) { QString reasonStr; if (fetch->status > 600) @@ -548,12 +605,13 @@ void QNetworkReplyWasmImplPrivate::downloadFailed(emscripten_fetch_t *fetch) reply->dataReceived(buffer); QByteArray statusText(fetch->statusText); reply->setStatusCode(fetch->status, statusText); - reply->emitReplyError(reply->statusCodeFromHttp(fetch->status, reply->request.url()), reasonStr); + reply->emitReplyError(reply->statusCodeFromHttp(fetch->status, reply->request.url()), + reasonStr); reply->setReplyFinished(); } reply->m_fetch = nullptr; + fetchContext->state = FetchContext::State::FINISHED; } - emscripten_fetch_close(fetch); } //taken from qhttpthreaddelegate.cpp |