diff options
Diffstat (limited to 'src/network/access')
-rw-r--r-- | src/network/access/qhttp2protocolhandler.cpp | 6 | ||||
-rw-r--r-- | src/network/access/qhttp2protocolhandler_p.h | 1 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkconnectionchannel.cpp | 3 | ||||
-rw-r--r-- | src/network/access/qnetworkaccessmanager.cpp | 25 | ||||
-rw-r--r-- | src/network/access/qnetworkreply.cpp | 2 | ||||
-rw-r--r-- | src/network/access/qnetworkreplyfileimpl.cpp | 8 | ||||
-rw-r--r-- | src/network/access/qnetworkreplywasmimpl.cpp | 311 | ||||
-rw-r--r-- | src/network/access/qnetworkreplywasmimpl_p.h | 14 |
8 files changed, 148 insertions, 222 deletions
diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp index efbeb17d39..ac90714132 100644 --- a/src/network/access/qhttp2protocolhandler.cpp +++ b/src/network/access/qhttp2protocolhandler.cpp @@ -220,6 +220,12 @@ void QHttp2ProtocolHandler::handleConnectionClosure() goingAway = true; } +void QHttp2ProtocolHandler::ensureClientPrefaceSent() +{ + if (!prefaceSent) + sendClientPreface(); +} + void QHttp2ProtocolHandler::_q_uploadDataReadyRead() { if (!sender()) // QueuedConnection, firing after sender (byte device) was deleted. diff --git a/src/network/access/qhttp2protocolhandler_p.h b/src/network/access/qhttp2protocolhandler_p.h index 43fdb136cd..14deabd70b 100644 --- a/src/network/access/qhttp2protocolhandler_p.h +++ b/src/network/access/qhttp2protocolhandler_p.h @@ -93,6 +93,7 @@ public: QHttp2ProtocolHandler &operator = (QHttp2ProtocolHandler &&rhs) = delete; Q_INVOKABLE void handleConnectionClosure(); + Q_INVOKABLE void ensureClientPrefaceSent(); private slots: void _q_uploadDataReadyRead(); diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 4ea98ff978..ba05e75794 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -478,6 +478,9 @@ void QHttpNetworkConnectionChannel::allDone() QHttp2ProtocolHandler *h2c = static_cast<QHttp2ProtocolHandler *>(protocolHandler.data()); QMetaObject::invokeMethod(h2c, "_q_receiveReply", Qt::QueuedConnection); QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); + // If we only had one request sent with H2 allowed, we may fail to send + // a client preface and SETTINGS, which is required by RFC 7540, 3.2. + QMetaObject::invokeMethod(h2c, "ensureClientPrefaceSent", Qt::QueuedConnection); return; } else { // Ok, whatever happened, we do not try HTTP/2 anymore ... diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 62cc760ada..63a816b9dc 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -1211,16 +1211,7 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera bool isLocalFile = req.url().isLocalFile(); QString scheme = req.url().scheme(); -#ifdef Q_OS_WASM - // Support http, https, and relateive urls - if (scheme == QLatin1String("http") || scheme == QLatin1String("https") || scheme.isEmpty()) { - QNetworkReplyWasmImpl *reply = new QNetworkReplyWasmImpl(this); - QNetworkReplyWasmImplPrivate *priv = reply->d_func(); - priv->manager = this; - priv->setup(op, req, outgoingData); - return reply; - } -#endif +#ifndef Q_OS_WASM // fast path for GET on file:// URLs // The QNetworkAccessFileBackend will right now only be used for PUT @@ -1273,7 +1264,7 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera if (!d->statusMonitor.isMonitoring() && !d->statusMonitor.start()) qWarning(lcNetMon, "failed to start network status monitoring"); } - +#endif QNetworkRequest request = req; if (!request.header(QNetworkRequest::ContentLengthHeader).isValid() && outgoingData && !outgoingData->isSequential()) { @@ -1291,6 +1282,16 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera request.setHeader(QNetworkRequest::CookieHeader, QVariant::fromValue(cookies)); } } +#ifdef Q_OS_WASM + // Support http, https, and relative urls + if (scheme == QLatin1String("http") || scheme == QLatin1String("https") || scheme.isEmpty()) { + QNetworkReplyWasmImpl *reply = new QNetworkReplyWasmImpl(this); + QNetworkReplyWasmImplPrivate *priv = reply->d_func(); + priv->manager = this; + priv->setup(op, request, outgoingData); + return reply; + } +#endif #if QT_CONFIG(http) // Since Qt 5 we use the new QNetworkReplyHttpImpl @@ -1632,7 +1633,7 @@ void QNetworkAccessManagerPrivate::proxyAuthenticationRequired(const QUrl &url, } } -#if defined(Q_OS_OSX) +#if defined(Q_OS_MACOS) //now we try to get the username and password from keychain //if not successful signal will be emitted QString username; diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp index 6784bc734d..30e4e290ea 100644 --- a/src/network/access/qnetworkreply.cpp +++ b/src/network/access/qnetworkreply.cpp @@ -868,7 +868,7 @@ void QNetworkReply::setRequest(const QNetworkRequest &request) Sets the error condition to be \a errorCode. The human-readable message is set with \a errorString. - Calling setError() does not emit the error(QNetworkReply::NetworkError) + Calling setError() does not emit the errorOccurred(QNetworkReply::NetworkError) signal. \sa error(), errorString() diff --git a/src/network/access/qnetworkreplyfileimpl.cpp b/src/network/access/qnetworkreplyfileimpl.cpp index afab8ffd94..68fac55feb 100644 --- a/src/network/access/qnetworkreplyfileimpl.cpp +++ b/src/network/access/qnetworkreplyfileimpl.cpp @@ -89,7 +89,7 @@ QNetworkReplyFileImpl::QNetworkReplyFileImpl(QNetworkAccessManager *manager, con // we handle only local files QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Request for opening non-local file %1").arg(url.toString()); setError(QNetworkReply::ProtocolInvalidOperationError, msg); - QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection, Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ProtocolInvalidOperationError)); fileOpenFinished(false); return; @@ -134,7 +134,7 @@ QNetworkReplyFileImpl::QNetworkReplyFileImpl(QNetworkAccessManager *manager, con if (fi.isDir()) { QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Cannot open %1: Path is a directory").arg(url.toString()); setError(QNetworkReply::ContentOperationNotPermittedError, msg); - QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + QMetaObject::invokeMethod(this, "errorOccured", Qt::QueuedConnection, Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ContentOperationNotPermittedError)); QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); return; @@ -149,11 +149,11 @@ QNetworkReplyFileImpl::QNetworkReplyFileImpl(QNetworkAccessManager *manager, con if (fi.exists()) { setError(QNetworkReply::ContentAccessDenied, msg); - QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection, Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ContentAccessDenied)); } else { setError(QNetworkReply::ContentNotFoundError, msg); - QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection, Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ContentNotFoundError)); } QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); diff --git a/src/network/access/qnetworkreplywasmimpl.cpp b/src/network/access/qnetworkreplywasmimpl.cpp index 8c0f9bdf55..af8b39bab6 100644 --- a/src/network/access/qnetworkreplywasmimpl.cpp +++ b/src/network/access/qnetworkreplywasmimpl.cpp @@ -50,180 +50,10 @@ #include <private/qnetworkfile_p.h> #include <emscripten.h> -#include <emscripten/bind.h> -#include <emscripten/val.h> +#include <emscripten/fetch.h> QT_BEGIN_NAMESPACE -using namespace emscripten; - -static void q_requestErrorCallback(val event) -{ - if (event.isNull() || event.isUndefined()) - return; - - val xhr = event["target"]; - if (xhr.isNull() || xhr.isUndefined()) - return; - - quintptr func = xhr["data-handler"].as<quintptr>(); - QNetworkReplyWasmImplPrivate *reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(func); - Q_ASSERT(reply); - - int statusCode = xhr["status"].as<int>(); - - QString reasonStr = QString::fromStdString(xhr["statusText"].as<std::string>()); - - reply->setReplyAttributes(func, statusCode, reasonStr); - - if (statusCode >= 400 && !reasonStr.isEmpty()) - reply->emitReplyError(reply->statusCodeFromHttp(statusCode, reply->request.url()), reasonStr); -} - -static void q_progressCallback(val event) -{ - if (event.isNull() || event.isUndefined()) - return; - - val xhr = event["target"]; - if (xhr.isNull() || xhr.isUndefined()) - return; - - QNetworkReplyWasmImplPrivate *reply = - reinterpret_cast<QNetworkReplyWasmImplPrivate*>(xhr["data-handler"].as<quintptr>()); - Q_ASSERT(reply); - - if (xhr["status"].as<int>() < 400) - reply->emitDataReadProgress(event["loaded"].as<int>(), event["total"].as<int>()); -} - -static void q_loadCallback(val event) -{ - if (event.isNull() || event.isUndefined()) - return; - - val xhr = event["target"]; - if (xhr.isNull() || xhr.isUndefined()) - return; - - QNetworkReplyWasmImplPrivate *reply = - reinterpret_cast<QNetworkReplyWasmImplPrivate*>(xhr["data-handler"].as<quintptr>()); - Q_ASSERT(reply); - - int status = xhr["status"].as<int>(); - if (status >= 300) { - q_requestErrorCallback(event); - return; - } - QString statusText = QString::fromStdString(xhr["statusText"].as<std::string>()); - int readyState = xhr["readyState"].as<int>(); - - if (status == 200 || status == 203) { - QString responseString; - const std::string responseType = xhr["responseType"].as<std::string>(); - if (responseType.length() == 0 || responseType == "document" || responseType == "text") { - responseString = QString::fromStdWString(xhr["responseText"].as<std::wstring>()); - } else if (responseType == "json") { - responseString = - QString::fromStdWString(val::global("JSON").call<std::wstring>("stringify", xhr["response"])); - } else if (responseType == "arraybuffer" || responseType == "blob") { - // handle this data in the FileReader, triggered by the call to readAsArrayBuffer - val blob = xhr["response"]; - if (blob.isNull() || blob.isUndefined()) - return; - - val reader = val::global("FileReader").new_(); - if (reader.isNull() || reader.isUndefined()) - return; - - reader.set("onload", val::module_property("qt_QNetworkReplyWasmImplPrivate_readBinary")); - reader.set("data-handler", xhr["data-handler"]); - - reader.call<void>("readAsArrayBuffer", blob); - val::global("Module").delete_(reader); - } - - - if (readyState == 4) { // done - reply->setReplyAttributes(xhr["data-handler"].as<quintptr>(), status, statusText); - if (!responseString.isEmpty()) { - QByteArray responseStringArray = responseString.toUtf8(); - reply->dataReceived(responseStringArray, responseStringArray.size()); - } - } - } - if (status >= 400 && !statusText.isEmpty()) - reply->emitReplyError(reply->statusCodeFromHttp(status, reply->request.url()), statusText); -} - -static void q_responseHeadersCallback(val event) -{ - if (event.isNull() || event.isUndefined()) - return; - - val xhr = event["target"]; - if (xhr.isNull() || xhr.isUndefined()) - return; - - if (xhr["readyState"].as<int>() == 2) { // HEADERS_RECEIVED - std::string responseHeaders = xhr.call<std::string>("getAllResponseHeaders"); - if (!responseHeaders.empty()) { - QNetworkReplyWasmImplPrivate *reply = - reinterpret_cast<QNetworkReplyWasmImplPrivate*>(xhr["data-handler"].as<quintptr>()); - Q_ASSERT(reply); - - reply->headersReceived(QString::fromStdString(responseHeaders)); - } - } -} - -static void q_readBinary(val event) -{ - if (event.isNull() || event.isUndefined()) - return; - - val fileReader = event["target"]; - if (fileReader.isNull() || fileReader.isUndefined()) - return; - - QNetworkReplyWasmImplPrivate *reply = - reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fileReader["data-handler"].as<quintptr>()); - Q_ASSERT(reply); - - if (reply->state == QNetworkReplyPrivate::Finished || reply->state == QNetworkReplyPrivate::Aborted) - return; - - // Set up source typed array - val result = fileReader["result"]; // ArrayBuffer - if (result.isNull() || result.isUndefined()) - return; - - val Uint8Array = val::global("Uint8Array"); - val sourceTypedArray = Uint8Array.new_(result); - - // Allocate and set up destination typed array - const quintptr size = result["byteLength"].as<quintptr>(); - QByteArray buffer(size, Qt::Uninitialized); - - val destinationTypedArray = Uint8Array.new_(val::module_property("HEAPU8")["buffer"], - reinterpret_cast<quintptr>(buffer.data()), size); - destinationTypedArray.call<void>("set", sourceTypedArray); - reply->dataReceived(buffer, buffer.size()); - - event.delete_(fileReader); - Uint8Array.delete_(sourceTypedArray); - - QCoreApplication::processEvents(); -} - -EMSCRIPTEN_BINDINGS(qtNetworkModule) { - function("qt_QNetworkReplyWasmImplPrivate_requestErrorCallback", q_requestErrorCallback); - function("qt_QNetworkReplyWasmImplPrivate_progressCallback", q_progressCallback); - function("qt_QNetworkReplyWasmImplPrivate_loadCallback", q_loadCallback); - function("qt_QNetworkReplyWasmImplPrivate_responseHeadersCallback", q_responseHeadersCallback); - function("qt_QNetworkReplyWasmImplPrivate_readBinary", q_readBinary); -} - QNetworkReplyWasmImplPrivate::QNetworkReplyWasmImplPrivate() : QNetworkReplyPrivate() , managerPrivate(0) @@ -236,11 +66,7 @@ QNetworkReplyWasmImplPrivate::QNetworkReplyWasmImplPrivate() QNetworkReplyWasmImplPrivate::~QNetworkReplyWasmImplPrivate() { - m_xhr.set("onerror", val::null()); - m_xhr.set("onload", val::null()); - m_xhr.set("onprogress", val::null()); - m_xhr.set("onreadystatechange", val::null()); - m_xhr.set("data-handler", val::null()); + emscripten_fetch_close(m_fetch); } QNetworkReplyWasmImpl::QNetworkReplyWasmImpl(QObject *parent) @@ -373,7 +199,11 @@ void QNetworkReplyWasmImplPrivate::setReplyAttributes(quintptr data, int statusC void QNetworkReplyWasmImplPrivate::doAbort() const { - m_xhr.call<void>("abort"); + emscripten_fetch_close(m_fetch); +} + +constexpr int getArraySize (int factor) { + return 2 * factor + 1; } void QNetworkReplyWasmImplPrivate::doSendRequest() @@ -381,38 +211,68 @@ void QNetworkReplyWasmImplPrivate::doSendRequest() Q_Q(QNetworkReplyWasmImpl); totalDownloadSize = 0; - m_xhr = val::global("XMLHttpRequest").new_(); - std::string verb = q->methodName().toStdString(); + emscripten_fetch_attr_t attr; + emscripten_fetch_attr_init(&attr); + strcpy(attr.requestMethod, q->methodName().constData()); - m_xhr.call<void>("open", verb, request.url().toString().toStdString()); + QList<QByteArray> headersData = request.rawHeaderList(); + int arrayLength = getArraySize(headersData.count()); - m_xhr.set("onerror", val::module_property("qt_QNetworkReplyWasmImplPrivate_requestErrorCallback")); - m_xhr.set("onload", val::module_property("qt_QNetworkReplyWasmImplPrivate_loadCallback")); - m_xhr.set("onprogress", val::module_property("qt_QNetworkReplyWasmImplPrivate_progressCallback")); - m_xhr.set("onreadystatechange", val::module_property("qt_QNetworkReplyWasmImplPrivate_responseHeadersCallback")); + if (headersData.count() > 0) { + const char* customHeaders[arrayLength]; + int i = 0; + for (i; i < headersData.count() * 2; (i = i + 2)) { + customHeaders[i] = headersData[i].constData(); + customHeaders[i + 1] = request.rawHeader(headersData[i]).constData(); + } + customHeaders[i] = nullptr; + attr.requestHeaders = customHeaders; + } - m_xhr.set("data-handler", val(quintptr(reinterpret_cast<void *>(this)))); + if (outgoingData) { // data from post request + // handle extra data + QByteArray extraData; + extraData = outgoingData->readAll(); // is there a size restriction here? + if (!extraData.isEmpty()) { + attr.requestData = extraData.constData(); + attr.requestDataSize = extraData.size(); + } + } - QByteArray contentType = request.rawHeader("Content-Type"); + // username & password + if (!request.url().userInfo().isEmpty()) { + attr.userName = request.url().userName().toUtf8(); + attr.password = request.url().password().toUtf8(); + } - // handle extra data - val dataToSend = val::null(); - QByteArray extraData; + attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY | EMSCRIPTEN_FETCH_PERSIST_FILE | EMSCRIPTEN_FETCH_REPLACE; - if (outgoingData) // data from post request - extraData = outgoingData->readAll(); + QNetworkRequest::CacheLoadControl CacheLoadControlAttribute = + (QNetworkRequest::CacheLoadControl)request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(); - if (!extraData.isEmpty()) { - dataToSend = val(typed_memory_view(extraData.size(), - reinterpret_cast<const unsigned char *> - (extraData.constData()))); + if (CacheLoadControlAttribute == QNetworkRequest::AlwaysCache) { + attr.attributes += EMSCRIPTEN_FETCH_NO_DOWNLOAD; } - m_xhr.set("responseType", val("blob")); - // set request headers - for (auto header : request.rawHeaderList()) { - m_xhr.call<void>("setRequestHeader", header.toStdString(), request.rawHeader(header).toStdString()); + if (CacheLoadControlAttribute == QNetworkRequest::PreferCache) { + attr.attributes += EMSCRIPTEN_FETCH_APPEND; } - m_xhr.call<void>("send", dataToSend); + + if (CacheLoadControlAttribute == QNetworkRequest::AlwaysNetwork || + request.attribute(QNetworkRequest::CacheSaveControlAttribute, false).toBool()) { + attr.attributes -= EMSCRIPTEN_FETCH_PERSIST_FILE; + } + + attr.onsuccess = QNetworkReplyWasmImplPrivate::downloadSucceeded; + attr.onerror = QNetworkReplyWasmImplPrivate::downloadFailed; + attr.onprogress = QNetworkReplyWasmImplPrivate::downloadProgress; + attr.onreadystatechange = QNetworkReplyWasmImplPrivate::stateChange; + attr.timeoutMSecs = 2 * 6000; // FIXME + attr.userData = reinterpret_cast<void *>(this); + + QString dPath = QStringLiteral("/home/web_user/") + request.url().fileName(); + attr.destinationPath = dPath.toUtf8(); + + m_fetch = emscripten_fetch(&attr, request.url().toString().toUtf8()); } void QNetworkReplyWasmImplPrivate::emitReplyError(QNetworkReply::NetworkError errorCode, const QString &errorString) @@ -511,7 +371,6 @@ void QNetworkReplyWasmImplPrivate::headersReceived(const QString &bufferString) if (!bufferString.isEmpty()) { QStringList headers = bufferString.split(QString::fromUtf8("\r\n"), Qt::SkipEmptyParts); - for (int i = 0; i < headers.size(); i++) { QString headerName = headers.at(i).split(QString::fromUtf8(": ")).at(0); QString headersValue = headers.at(i).split(QString::fromUtf8(": ")).at(1); @@ -589,6 +448,56 @@ void QNetworkReplyWasmImplPrivate::_q_bufferOutgoingData() } } +void QNetworkReplyWasmImplPrivate::downloadSucceeded(emscripten_fetch_t *fetch) +{ + QByteArray buffer(fetch->data, fetch->numBytes); + + QNetworkReplyWasmImplPrivate *reply = + reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData); + if (reply) { + reply->dataReceived(buffer, buffer.size()); + } +} + +void QNetworkReplyWasmImplPrivate::stateChange(emscripten_fetch_t *fetch) +{ + if (fetch->readyState == /*HEADERS_RECEIVED*/ 2) { + size_t headerLength = emscripten_fetch_get_response_headers_length(fetch); + char *dst = nullptr; + emscripten_fetch_get_response_headers(fetch, dst, headerLength + 1); + std::string str = dst; + QNetworkReplyWasmImplPrivate *reply = + reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData); + reply->headersReceived(QString::fromStdString(str)); + } +} + +void QNetworkReplyWasmImplPrivate::downloadProgress(emscripten_fetch_t *fetch) +{ + QNetworkReplyWasmImplPrivate *reply = + reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData); + Q_ASSERT(reply); + + if (fetch->status < 400) + reply->emitDataReadProgress((fetch->dataOffset + fetch->numBytes), fetch->totalBytes); +} + +void QNetworkReplyWasmImplPrivate::downloadFailed(emscripten_fetch_t *fetch) +{ + QNetworkReplyWasmImplPrivate *reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData); + Q_ASSERT(reply); + + QString reasonStr = QString::fromUtf8(fetch->statusText); + + reply->setReplyAttributes(reinterpret_cast<quintptr>(fetch->userData), fetch->status, reasonStr); + + if (fetch->status >= 400 && !reasonStr.isEmpty()) + reply->emitReplyError(reply->statusCodeFromHttp(fetch->status, reply->request.url()), reasonStr); + + if (fetch->status >= 400) + emscripten_fetch_close(fetch); // Also free data on failure. +} + //taken from qhttpthreaddelegate.cpp QNetworkReply::NetworkError QNetworkReplyWasmImplPrivate::statusCodeFromHttp(int httpStatusCode, const QUrl &url) { diff --git a/src/network/access/qnetworkreplywasmimpl_p.h b/src/network/access/qnetworkreplywasmimpl_p.h index e1e6bf4e24..5463ce8a98 100644 --- a/src/network/access/qnetworkreplywasmimpl_p.h +++ b/src/network/access/qnetworkreplywasmimpl_p.h @@ -61,8 +61,7 @@ #include <private/qabstractfileengine_p.h> #include <emscripten.h> -#include <emscripten/html5.h> -#include <emscripten/val.h> +#include <emscripten/fetch.h> QT_BEGIN_NAMESPACE @@ -135,10 +134,17 @@ public: QIODevice *outgoingData; QSharedPointer<QRingBuffer> outgoingDataBuffer; - emscripten::val m_xhr = emscripten::val::null(); - void doAbort() const; + void doAbort() const; + + static void downloadProgress(emscripten_fetch_t *fetch); + static void downloadFailed(emscripten_fetch_t *fetch); + static void downloadSucceeded(emscripten_fetch_t *fetch); + static void stateChange(emscripten_fetch_t *fetch); static QNetworkReply::NetworkError statusCodeFromHttp(int httpStatusCode, const QUrl &url); + + emscripten_fetch_t *m_fetch; + Q_DECLARE_PUBLIC(QNetworkReplyWasmImpl) }; |