diff options
author | Uwe Klotz <uklotz@mixxx.org> | 2021-01-05 15:26:54 +0100 |
---|---|---|
committer | Uwe Klotz <uklotz@mixxx.org> | 2021-01-05 15:35:31 +0100 |
commit | 98cf0cd4c667300256909d3ab9ede5d3e6860ab6 (patch) | |
tree | ed731fdcb8a8801f92dfaa3511cc7701480224a6 /src/network | |
parent | 0dab49f0e56c4bf14c5bc1f22b5fa0750736d299 (diff) |
JsonWebTask: Read QNetworkReply content only once
QNetworkReply::readAll() must only be invoked once and consumes the
response!
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/jsonwebtask.cpp | 64 |
1 files changed, 36 insertions, 28 deletions
diff --git a/src/network/jsonwebtask.cpp b/src/network/jsonwebtask.cpp index 0bcef44626..ebc97ffd98 100644 --- a/src/network/jsonwebtask.cpp +++ b/src/network/jsonwebtask.cpp @@ -57,44 +57,48 @@ QMimeType readContentType( return contentType; } -bool readJsonContent( +/// Returns std::nullopt on success and the raw payload otherwise. +/// The JSON content is assigned to the output parameter jsonContent. +std::optional<std::pair<QMimeType, QByteArray>> readJsonContent( QNetworkReply* reply, QJsonDocument* jsonContent) { DEBUG_ASSERT(reply); DEBUG_ASSERT(jsonContent); DEBUG_ASSERT(JSON_MIME_TYPE.isValid()); + QByteArray contentBytes = reply->readAll(); const auto contentType = readContentType(reply); if (contentType != JSON_MIME_TYPE) { kLogger.warning() << "Unexpected content type" << contentType; - return false; + return std::make_pair(contentType, contentBytes); } - QByteArray jsonData = reply->readAll(); - if (jsonData.isEmpty()) { - kLogger.warning() - << "Empty reply"; - return false; + if (contentBytes.isEmpty()) { + VERIFY_OR_DEBUG_ASSERT(jsonContent->isEmpty()) { + *jsonContent = QJsonDocument{}; + } + kLogger.info() << "Empty JSON network reply"; + return std::nullopt; } QJsonParseError parseError; - const auto jsonDoc = QJsonDocument::fromJson( - jsonData, + const auto jsonDocument = QJsonDocument::fromJson( + contentBytes, &parseError); // QJsonDocument::fromJson() returns a non-null document // if parsing succeeds and otherwise null on error. The // parse error must only be evaluated if the returned // document is null! - if (jsonDoc.isNull() && + if (jsonDocument.isNull() && parseError.error != QJsonParseError::NoError) { kLogger.warning() << "Failed to parse JSON data:" << parseError.errorString() << "at offset" << parseError.offset; - return false; + return std::make_pair(contentType, contentBytes); } - *jsonContent = jsonDoc; - return true; + *jsonContent = jsonDocument; + return std::nullopt; } // TODO: Allow to customize headers and attributes? @@ -270,23 +274,27 @@ QNetworkReply* JsonWebTask::doStartNetworkRequest( void JsonWebTask::doNetworkReplyFinished( QNetworkReply* finishedNetworkReply, HttpStatusCode statusCode) { - QJsonDocument content; + DEBUG_ASSERT(finishedNetworkReply); + QJsonDocument jsonContent; + auto webResponse = WebResponse{ + finishedNetworkReply->url(), + statusCode}; if (statusCode != kHttpStatusCodeInvalid && - finishedNetworkReply->bytesAvailable() > 0 && - !readJsonContent(finishedNetworkReply, &content)) { - onFinishedCustom(CustomWebResponse{ - WebResponse{ - finishedNetworkReply->url(), - statusCode}, - readContentType(finishedNetworkReply), - finishedNetworkReply->readAll()}); - } else { - onFinished(JsonWebResponse{ - WebResponse{ - finishedNetworkReply->url(), - statusCode}, - std::move(content)}); + finishedNetworkReply->bytesAvailable() > 0) { + auto contentTypeAndBytes = readJsonContent(finishedNetworkReply, &jsonContent); + if (contentTypeAndBytes) { + // Failed to read JSON content + DEBUG_ASSERT(jsonContent.isEmpty()); // still empty + onFinishedCustom(CustomWebResponse{ + std::move(webResponse), + std::move(contentTypeAndBytes->first), + std::move(contentTypeAndBytes->second)}); + return; + } } + onFinished(JsonWebResponse{ + std::move(webResponse), + std::move(jsonContent)}); } void JsonWebTask::emitFailed( |