diff options
Diffstat (limited to 'src/network/access/qnetworkreplywasmimpl.cpp')
-rw-r--r-- | src/network/access/qnetworkreplywasmimpl.cpp | 127 |
1 files changed, 100 insertions, 27 deletions
diff --git a/src/network/access/qnetworkreplywasmimpl.cpp b/src/network/access/qnetworkreplywasmimpl.cpp index 2e0f865ccb..c02f0b4e61 100644 --- a/src/network/access/qnetworkreplywasmimpl.cpp +++ b/src/network/access/qnetworkreplywasmimpl.cpp @@ -9,6 +9,8 @@ #include <QtCore/qcoreapplication.h> #include <QtCore/qfileinfo.h> #include <QtCore/qthread.h> +#include <QtCore/private/qoffsetstringarray_p.h> +#include <QtCore/private/qtools_p.h> #include <private/qnetworkaccessmanager_p.h> #include <private/qnetworkfile_p.h> @@ -18,6 +20,41 @@ QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + +namespace { + +static constexpr auto BannedHeaders = qOffsetStringArray( + "accept-charset", + "accept-encoding", + "access-control-request-headers", + "access-control-request-method", + "connection", + "content-length", + "cookie", + "cookie2", + "date", + "dnt", + "expect", + "host", + "keep-alive", + "origin", + "referer", + "te", + "trailer", + "transfer-encoding", + "upgrade", + "via" +); + +bool isUnsafeHeader(QLatin1StringView header) noexcept +{ + return header.startsWith("proxy-"_L1, Qt::CaseInsensitive) + || header.startsWith("sec-"_L1, Qt::CaseInsensitive) + || BannedHeaders.contains(header, Qt::CaseInsensitive); +} +} // namespace + QNetworkReplyWasmImplPrivate::QNetworkReplyWasmImplPrivate() : QNetworkReplyPrivate() , managerPrivate(0) @@ -25,7 +62,7 @@ QNetworkReplyWasmImplPrivate::QNetworkReplyWasmImplPrivate() , downloadBufferCurrentSize(0) , totalDownloadSize(0) , percentFinished(0) - , m_fetch(0) + , m_fetch(nullptr) { } @@ -42,6 +79,9 @@ QNetworkReplyWasmImpl::QNetworkReplyWasmImpl(QObject *parent) QNetworkReplyWasmImpl::~QNetworkReplyWasmImpl() { + if (isRunning()) + abort(); + close(); } QByteArray QNetworkReplyWasmImpl::methodName() const @@ -68,22 +108,38 @@ QByteArray QNetworkReplyWasmImpl::methodName() const void QNetworkReplyWasmImpl::close() { + Q_D(QNetworkReplyWasmImpl); + + if (d->state != QNetworkReplyPrivate::Aborted && + d->state != QNetworkReplyPrivate::Finished && + d->state != QNetworkReplyPrivate::Idle) { + d->state = QNetworkReplyPrivate::Finished; + d->setCanceled(); + } + QNetworkReply::close(); - setFinished(true); - emit finished(); } void QNetworkReplyWasmImpl::abort() { Q_D(QNetworkReplyWasmImpl); + if (d->state == QNetworkReplyPrivate::Finished || d->state == QNetworkReplyPrivate::Aborted) return; d->state = QNetworkReplyPrivate::Aborted; - d->m_fetch->userData = nullptr; + d->setCanceled(); +} - d->emitReplyError(QNetworkReply::OperationCanceledError, QStringLiteral("Operation canceled")); - close(); +void QNetworkReplyWasmImplPrivate::setCanceled() +{ + Q_Q(QNetworkReplyWasmImpl); + if (m_fetch) + m_fetch->userData = nullptr; + + emitReplyError(QNetworkReply::OperationCanceledError, QStringLiteral("Operation canceled")); + q->setFinished(true); + emit q->finished(); } qint64 QNetworkReplyWasmImpl::bytesAvailable() const @@ -175,15 +231,22 @@ void QNetworkReplyWasmImplPrivate::doSendRequest() QList<QByteArray> headersData = request.rawHeaderList(); int arrayLength = getArraySize(headersData.count()); - const char* customHeaders[arrayLength]; + const char *customHeaders[arrayLength]; + QStringList trimmedHeaders; if (headersData.count() > 0) { int i = 0; - for (int j = 0; j < headersData.count(); j++) { - customHeaders[i] = headersData[j].constData(); - i += 1; - customHeaders[i] = request.rawHeader(headersData[j]).constData(); - i += 1; + 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; @@ -224,6 +287,7 @@ void QNetworkReplyWasmImplPrivate::doSendRequest() attr.attributes -= EMSCRIPTEN_FETCH_PERSIST_FILE; } + attr.withCredentials = request.attribute(QNetworkRequest::UseCredentialsAttribute, false).toBool(); attr.onsuccess = QNetworkReplyWasmImplPrivate::downloadSucceeded; attr.onerror = QNetworkReplyWasmImplPrivate::downloadFailed; attr.onprogress = QNetworkReplyWasmImplPrivate::downloadProgress; @@ -231,11 +295,12 @@ void QNetworkReplyWasmImplPrivate::doSendRequest() attr.timeoutMSecs = request.transferTimeout(); attr.userData = reinterpret_cast<void *>(this); - QString dPath = QStringLiteral("/home/web_user/") + request.url().fileName(); + QString dPath = "/home/web_user/"_L1 + request.url().fileName(); QByteArray destinationPath = dPath.toUtf8(); attr.destinationPath = destinationPath.constData(); - m_fetch = emscripten_fetch(&attr, request.url().toString().toUtf8()); + m_fetch = emscripten_fetch(&attr, request.url().toString().toUtf8().constData()); + state = Working; } void QNetworkReplyWasmImplPrivate::emitReplyError(QNetworkReply::NetworkError errorCode, const QString &errorString) @@ -252,15 +317,16 @@ void QNetworkReplyWasmImplPrivate::emitDataReadProgress(qint64 bytesReceived, qi totalDownloadSize = bytesTotal; - percentFinished = (bytesReceived / bytesTotal) * 100; + percentFinished = bytesTotal ? (bytesReceived / bytesTotal) * 100 : 100; emit q->downloadProgress(bytesReceived, bytesTotal); } -void QNetworkReplyWasmImplPrivate::dataReceived(const QByteArray &buffer, int bufferSize) +void QNetworkReplyWasmImplPrivate::dataReceived(const QByteArray &buffer) { Q_Q(QNetworkReplyWasmImpl); + const qsizetype bufferSize = buffer.size(); if (bufferSize > 0) q->setReadBufferSize(bufferSize); @@ -273,7 +339,7 @@ void QNetworkReplyWasmImplPrivate::dataReceived(const QByteArray &buffer, int bu totalDownloadSize = downloadBufferCurrentSize; - downloadBuffer.append(buffer, bufferSize); + downloadBuffer.append(buffer); emit q->readyRead(); } @@ -284,32 +350,36 @@ static int parseHeaderName(const QByteArray &headerName) if (headerName.isEmpty()) return -1; - switch (tolower(headerName.at(0))) { + auto is = [&](const char *what) { + return qstrnicmp(headerName.data(), headerName.size(), what) == 0; + }; + + switch (QtMiscUtils::toAsciiLower(headerName.front())) { case 'c': - if (qstricmp(headerName.constData(), "content-type") == 0) + if (is("content-type")) return QNetworkRequest::ContentTypeHeader; - else if (qstricmp(headerName.constData(), "content-length") == 0) + else if (is("content-length")) return QNetworkRequest::ContentLengthHeader; - else if (qstricmp(headerName.constData(), "cookie") == 0) + else if (is("cookie")) return QNetworkRequest::CookieHeader; break; case 'l': - if (qstricmp(headerName.constData(), "location") == 0) + if (is("location")) return QNetworkRequest::LocationHeader; - else if (qstricmp(headerName.constData(), "last-modified") == 0) + else if (is("last-modified")) return QNetworkRequest::LastModifiedHeader; break; case 's': - if (qstricmp(headerName.constData(), "set-cookie") == 0) + if (is("set-cookie")) return QNetworkRequest::SetCookieHeader; - else if (qstricmp(headerName.constData(), "server") == 0) + else if (is("server")) return QNetworkRequest::ServerHeader; break; case 'u': - if (qstricmp(headerName.constData(), "user-agent") == 0) + if (is("user-agent")) return QNetworkRequest::UserAgentHeader; break; } @@ -411,7 +481,7 @@ void QNetworkReplyWasmImplPrivate::downloadSucceeded(emscripten_fetch_t *fetch) if (reply) { if (reply->state != QNetworkReplyPrivate::Aborted) { QByteArray buffer(fetch->data, fetch->numBytes); - reply->dataReceived(buffer, buffer.size()); + reply->dataReceived(buffer); QByteArray statusText(fetch->statusText); reply->setStatusCode(fetch->status, statusText); reply->setReplyFinished(); @@ -424,6 +494,7 @@ void QNetworkReplyWasmImplPrivate::downloadSucceeded(emscripten_fetch_t *fetch) void QNetworkReplyWasmImplPrivate::setReplyFinished() { Q_Q(QNetworkReplyWasmImpl); + state = QNetworkReplyPrivate::Finished; q->setFinished(true); emit q->readChannelFinished(); emit q->finished(); @@ -473,6 +544,8 @@ void QNetworkReplyWasmImplPrivate::downloadFailed(emscripten_fetch_t *fetch) reasonStr = QStringLiteral("Operation canceled"); else reasonStr = QString::fromUtf8(fetch->statusText); + QByteArray buffer(fetch->data, fetch->numBytes); + reply->dataReceived(buffer); QByteArray statusText(fetch->statusText); reply->setStatusCode(fetch->status, statusText); reply->emitReplyError(reply->statusCodeFromHttp(fetch->status, reply->request.url()), reasonStr); |