| /**************************************************************************** |
| ** |
| ** Copyright (C) 2018 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtNetwork module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #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 <private/qnetworkaccessmanager_p.h> |
| #include <private/qnetworkfile_p.h> |
| |
| #include <emscripten.h> |
| #include <emscripten/bind.h> |
| #include <emscripten/val.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) |
| , downloadBufferReadPosition(0) |
| , downloadBufferCurrentSize(0) |
| , totalDownloadSize(0) |
| , percentFinished(0) |
| { |
| } |
| |
| 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()); |
| } |
| |
| QNetworkReplyWasmImpl::QNetworkReplyWasmImpl(QObject *parent) |
| : QNetworkReply(*new QNetworkReplyWasmImplPrivate(), parent) |
| { |
| Q_D( QNetworkReplyWasmImpl); |
| d->state = QNetworkReplyPrivate::Idle; |
| } |
| |
| QNetworkReplyWasmImpl::~QNetworkReplyWasmImpl() |
| { |
| } |
| |
| QByteArray QNetworkReplyWasmImpl::methodName() const |
| { |
| const Q_D( QNetworkReplyWasmImpl); |
| switch (operation()) { |
| case QNetworkAccessManager::HeadOperation: |
| return "HEAD"; |
| case QNetworkAccessManager::GetOperation: |
| return "GET"; |
| case QNetworkAccessManager::PutOperation: |
| return "PUT"; |
| case QNetworkAccessManager::PostOperation: |
| return "POST"; |
| case QNetworkAccessManager::DeleteOperation: |
| return "DELETE"; |
| case QNetworkAccessManager::CustomOperation: |
| return d->request.attribute(QNetworkRequest::CustomVerbAttribute).toByteArray(); |
| default: |
| break; |
| } |
| return QByteArray(); |
| } |
| |
| void QNetworkReplyWasmImpl::close() |
| { |
| QNetworkReply::close(); |
| setFinished(true); |
| emit finished(); |
| } |
| |
| void QNetworkReplyWasmImpl::abort() |
| { |
| Q_D( QNetworkReplyWasmImpl); |
| if (d->state == QNetworkReplyPrivate::Finished || d->state == QNetworkReplyPrivate::Aborted) |
| return; |
| |
| setError(QNetworkReply::OperationCanceledError, QStringLiteral("Operation canceled")); |
| |
| d->doAbort(); |
| |
| close(); |
| d->state = QNetworkReplyPrivate::Aborted; |
| } |
| |
| qint64 QNetworkReplyWasmImpl::bytesAvailable() const |
| { |
| Q_D(const QNetworkReplyWasmImpl); |
| |
| return QNetworkReply::bytesAvailable() + d->downloadBufferCurrentSize - d->downloadBufferReadPosition; |
| } |
| |
| bool QNetworkReplyWasmImpl::isSequential() const |
| { |
| return true; |
| } |
| |
| qint64 QNetworkReplyWasmImpl::size() const |
| { |
| return QNetworkReply::size(); |
| } |
| |
| /*! |
| \internal |
| */ |
| qint64 QNetworkReplyWasmImpl::readData(char *data, qint64 maxlen) |
| { |
| Q_D(QNetworkReplyWasmImpl); |
| |
| qint64 howMuch = qMin(maxlen, (d->downloadBuffer.size() - d->downloadBufferReadPosition)); |
| memcpy(data, d->downloadBuffer.constData() + d->downloadBufferReadPosition, howMuch); |
| d->downloadBufferReadPosition += howMuch; |
| |
| return howMuch; |
| } |
| |
| void QNetworkReplyWasmImplPrivate::setup(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *data) |
| { |
| Q_Q(QNetworkReplyWasmImpl); |
| |
| outgoingData = data; |
| request = req; |
| url = request.url(); |
| operation = op; |
| |
| q->QIODevice::open(QIODevice::ReadOnly); |
| if (outgoingData && outgoingData->isSequential()) { |
| bool bufferingDisallowed = |
| request.attribute(QNetworkRequest::DoNotBufferUploadDataAttribute, false).toBool(); |
| |
| if (bufferingDisallowed) { |
| // if a valid content-length header for the request was supplied, we can disable buffering |
| // if not, we will buffer anyway |
| if (!request.header(QNetworkRequest::ContentLengthHeader).isValid()) { |
| state = Buffering; |
| _q_bufferOutgoingData(); |
| return; |
| } |
| } else { |
| // doSendRequest will be called when the buffering has finished. |
| state = Buffering; |
| _q_bufferOutgoingData(); |
| return; |
| } |
| } |
| // No outgoing data (POST, ..) |
| doSendRequest(); |
| } |
| |
| void QNetworkReplyWasmImplPrivate::setReplyAttributes(quintptr data, int statusCode, const QString &statusReason) |
| { |
| QNetworkReplyWasmImplPrivate *handler = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(data); |
| Q_ASSERT(handler); |
| |
| handler->q_func()->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, statusCode); |
| if (!statusReason.isEmpty()) |
| handler->q_func()->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, statusReason); |
| } |
| |
| void QNetworkReplyWasmImplPrivate::doAbort() const |
| { |
| m_xhr.call<void>("abort"); |
| } |
| |
| void QNetworkReplyWasmImplPrivate::doSendRequest() |
| { |
| Q_Q(QNetworkReplyWasmImpl); |
| totalDownloadSize = 0; |
| |
| m_xhr = val::global("XMLHttpRequest").new_(); |
| std::string verb = q->methodName().toStdString(); |
| |
| m_xhr.call<void>("open", verb, request.url().toString().toStdString()); |
| |
| 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")); |
| |
| m_xhr.set("data-handler", val(quintptr(reinterpret_cast<void *>(this)))); |
| |
| QByteArray contentType = request.rawHeader("Content-Type"); |
| |
| // handle extra data |
| val dataToSend = val::null(); |
| QByteArray extraData; |
| |
| if (outgoingData) // data from post request |
| extraData = outgoingData->readAll(); |
| |
| if (!extraData.isEmpty()) { |
| dataToSend = val(typed_memory_view(extraData.size(), |
| reinterpret_cast<const unsigned char *> |
| (extraData.constData()))); |
| } |
| 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()); |
| } |
| m_xhr.call<void>("send", dataToSend); |
| } |
| |
| void QNetworkReplyWasmImplPrivate::emitReplyError(QNetworkReply::NetworkError errorCode, const QString &errorString) |
| { |
| Q_UNUSED(errorCode) |
| Q_Q(QNetworkReplyWasmImpl); |
| |
| q->setError(errorCode, errorString); |
| emit q->error(errorCode); |
| |
| q->setFinished(true); |
| emit q->finished(); |
| } |
| |
| void QNetworkReplyWasmImplPrivate::emitDataReadProgress(qint64 bytesReceived, qint64 bytesTotal) |
| { |
| Q_Q(QNetworkReplyWasmImpl); |
| |
| totalDownloadSize = bytesTotal; |
| |
| percentFinished = (bytesReceived / bytesTotal) * 100; |
| |
| emit q->downloadProgress(bytesReceived, bytesTotal); |
| } |
| |
| void QNetworkReplyWasmImplPrivate::dataReceived(const QByteArray &buffer, int bufferSize) |
| { |
| Q_Q(QNetworkReplyWasmImpl); |
| |
| if (bufferSize > 0) |
| q->setReadBufferSize(bufferSize); |
| |
| bytesDownloaded = bufferSize; |
| |
| if (percentFinished != 100) |
| downloadBufferCurrentSize += bufferSize; |
| else |
| downloadBufferCurrentSize = bufferSize; |
| |
| totalDownloadSize = downloadBufferCurrentSize; |
| |
| downloadBuffer.append(buffer, bufferSize); |
| |
| emit q->readyRead(); |
| |
| if (downloadBufferCurrentSize == totalDownloadSize) { |
| q->setFinished(true); |
| emit q->readChannelFinished(); |
| emit q->finished(); |
| } |
| } |
| |
| //taken from qnetworkrequest.cpp |
| static int parseHeaderName(const QByteArray &headerName) |
| { |
| if (headerName.isEmpty()) |
| return -1; |
| |
| switch (tolower(headerName.at(0))) { |
| case 'c': |
| if (qstricmp(headerName.constData(), "content-type") == 0) |
| return QNetworkRequest::ContentTypeHeader; |
| else if (qstricmp(headerName.constData(), "content-length") == 0) |
| return QNetworkRequest::ContentLengthHeader; |
| else if (qstricmp(headerName.constData(), "cookie") == 0) |
| return QNetworkRequest::CookieHeader; |
| break; |
| |
| case 'l': |
| if (qstricmp(headerName.constData(), "location") == 0) |
| return QNetworkRequest::LocationHeader; |
| else if (qstricmp(headerName.constData(), "last-modified") == 0) |
| return QNetworkRequest::LastModifiedHeader; |
| break; |
| |
| case 's': |
| if (qstricmp(headerName.constData(), "set-cookie") == 0) |
| return QNetworkRequest::SetCookieHeader; |
| else if (qstricmp(headerName.constData(), "server") == 0) |
| return QNetworkRequest::ServerHeader; |
| break; |
| |
| case 'u': |
| if (qstricmp(headerName.constData(), "user-agent") == 0) |
| return QNetworkRequest::UserAgentHeader; |
| break; |
| } |
| |
| return -1; // nothing found |
| } |
| |
| |
| void QNetworkReplyWasmImplPrivate::headersReceived(const QString &bufferString) |
| { |
| Q_Q(QNetworkReplyWasmImpl); |
| |
| if (!bufferString.isEmpty()) { |
| QStringList headers = bufferString.split(QString::fromUtf8("\r\n"), QString::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); |
| if (headerName.isEmpty() || headersValue.isEmpty()) |
| continue; |
| |
| int headerIndex = parseHeaderName(headerName.toLocal8Bit()); |
| |
| if (headerIndex == -1) |
| q->setRawHeader(headerName.toLocal8Bit(), headersValue.toLocal8Bit()); |
| else |
| q->setHeader(static_cast<QNetworkRequest::KnownHeaders>(headerIndex), (QVariant)headersValue); |
| } |
| } |
| emit q->metaDataChanged(); |
| } |
| |
| void QNetworkReplyWasmImplPrivate::_q_bufferOutgoingDataFinished() |
| { |
| Q_Q(QNetworkReplyWasmImpl); |
| |
| // make sure this is only called once, ever. |
| //_q_bufferOutgoingData may call it or the readChannelFinished emission |
| if (state != Buffering) |
| return; |
| |
| // disconnect signals |
| QObject::disconnect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData())); |
| QObject::disconnect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished())); |
| |
| // finally, start the request |
| doSendRequest(); |
| } |
| |
| void QNetworkReplyWasmImplPrivate::_q_bufferOutgoingData() |
| { |
| Q_Q(QNetworkReplyWasmImpl); |
| |
| if (!outgoingDataBuffer) { |
| // first call, create our buffer |
| outgoingDataBuffer = QSharedPointer<QRingBuffer>::create(); |
| |
| QObject::connect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData())); |
| QObject::connect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished())); |
| } |
| |
| qint64 bytesBuffered = 0; |
| qint64 bytesToBuffer = 0; |
| |
| // read data into our buffer |
| forever { |
| bytesToBuffer = outgoingData->bytesAvailable(); |
| // unknown? just try 2 kB, this also ensures we always try to read the EOF |
| if (bytesToBuffer <= 0) |
| bytesToBuffer = 2*1024; |
| |
| char *dst = outgoingDataBuffer->reserve(bytesToBuffer); |
| bytesBuffered = outgoingData->read(dst, bytesToBuffer); |
| |
| if (bytesBuffered == -1) { |
| // EOF has been reached. |
| outgoingDataBuffer->chop(bytesToBuffer); |
| |
| _q_bufferOutgoingDataFinished(); |
| break; |
| } else if (bytesBuffered == 0) { |
| // nothing read right now, just wait until we get called again |
| outgoingDataBuffer->chop(bytesToBuffer); |
| |
| break; |
| } else { |
| // don't break, try to read() again |
| outgoingDataBuffer->chop(bytesToBuffer - bytesBuffered); |
| } |
| } |
| } |
| |
| //taken from qhttpthreaddelegate.cpp |
| QNetworkReply::NetworkError QNetworkReplyWasmImplPrivate::statusCodeFromHttp(int httpStatusCode, const QUrl &url) |
| { |
| QNetworkReply::NetworkError code; |
| // we've got an error |
| switch (httpStatusCode) { |
| case 400: // Bad Request |
| code = QNetworkReply::ProtocolInvalidOperationError; |
| break; |
| |
| case 401: // Authorization required |
| code = QNetworkReply::AuthenticationRequiredError; |
| break; |
| |
| case 403: // Access denied |
| code = QNetworkReply::ContentAccessDenied; |
| break; |
| |
| case 404: // Not Found |
| code = QNetworkReply::ContentNotFoundError; |
| break; |
| |
| case 405: // Method Not Allowed |
| code = QNetworkReply::ContentOperationNotPermittedError; |
| break; |
| |
| case 407: |
| code = QNetworkReply::ProxyAuthenticationRequiredError; |
| break; |
| |
| case 409: // Resource Conflict |
| code = QNetworkReply::ContentConflictError; |
| break; |
| |
| case 410: // Content no longer available |
| code = QNetworkReply::ContentGoneError; |
| break; |
| |
| case 418: // I'm a teapot |
| code = QNetworkReply::ProtocolInvalidOperationError; |
| break; |
| |
| case 500: // Internal Server Error |
| code = QNetworkReply::InternalServerError; |
| break; |
| |
| case 501: // Server does not support this functionality |
| code = QNetworkReply::OperationNotImplementedError; |
| break; |
| |
| case 503: // Service unavailable |
| code = QNetworkReply::ServiceUnavailableError; |
| break; |
| |
| default: |
| if (httpStatusCode > 500) { |
| // some kind of server error |
| code = QNetworkReply::UnknownServerError; |
| } else if (httpStatusCode >= 400) { |
| // content error we did not handle above |
| code = QNetworkReply::UnknownContentError; |
| } else { |
| qWarning("QNetworkAccess: got HTTP status code %d which is not expected from url: \"%s\"", |
| httpStatusCode, qPrintable(url.toString())); |
| code = QNetworkReply::ProtocolFailure; |
| } |
| }; |
| |
| return code; |
| } |
| |
| QT_END_NAMESPACE |