aboutsummaryrefslogtreecommitdiff
path: root/lib/jobs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/jobs')
-rw-r--r--lib/jobs/basejob.cpp96
-rw-r--r--lib/jobs/basejob.h30
2 files changed, 72 insertions, 54 deletions
diff --git a/lib/jobs/basejob.cpp b/lib/jobs/basejob.cpp
index 470250bf..2519713e 100644
--- a/lib/jobs/basejob.cpp
+++ b/lib/jobs/basejob.cpp
@@ -35,6 +35,47 @@ using namespace Quotient;
using std::chrono::seconds, std::chrono::milliseconds;
using namespace std::chrono_literals;
+BaseJob::StatusCode BaseJob::Status::fromHttpCode(int httpCode)
+{
+ if (httpCode / 10 == 41) // 41x errors
+ return httpCode == 410 ? IncorrectRequestError : NotFoundError;
+ switch (httpCode) {
+ case 401:
+ return Unauthorised;
+ // clang-format off
+ case 403: case 407: // clang-format on
+ return ContentAccessError;
+ case 404:
+ return NotFoundError;
+ // clang-format off
+ case 400: case 405: case 406: case 426: case 428: case 505: // clang-format on
+ case 494: // Unofficial nginx "Request header too large"
+ case 497: // Unofficial nginx "HTTP request sent to HTTPS port"
+ return IncorrectRequestError;
+ case 429:
+ return TooManyRequestsError;
+ case 501:
+ case 510:
+ return RequestNotImplementedError;
+ case 511:
+ return NetworkAuthRequiredError;
+ default:
+ return NetworkError;
+ }
+}
+
+QDebug BaseJob::Status::dumpToLog(QDebug dbg) const
+{
+ QDebugStateSaver _s(dbg);
+ dbg.noquote().nospace();
+ if (auto* const k = QMetaEnum::fromType<StatusCode>().valueToKey(code)) {
+ const QByteArray b = k;
+ dbg << b.mid(b.lastIndexOf(':'));
+ } else
+ dbg << code;
+ return dbg << ": " << message;
+}
+
struct NetworkReplyDeleter : public QScopedPointerDeleteLater {
static inline void cleanup(QNetworkReply* reply)
{
@@ -232,7 +273,13 @@ void BaseJob::Private::sendRequest()
// Pipelining doesn't fly quite well with SSL, occasionally crashing at
// what seems like an attempt to write to a closed channel.
// req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
- req.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, true);
+ req.setAttribute(
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
+ QNetworkRequest::Http2AllowedAttribute
+#else
+ QNetworkRequest::HTTP2AllowedAttribute
+#endif
+ , true);
Q_ASSERT(req.url().isValid());
for (auto it = requestHeaders.cbegin(); it != requestHeaders.cend(); ++it)
req.setRawHeader(it.key(), it.value());
@@ -316,8 +363,6 @@ void BaseJob::sendRequest()
<< "Request could not start:" << d->dumpRequest();
}
-void BaseJob::checkReply() { setStatus(doCheckReply(d->reply.data())); }
-
void BaseJob::gotReply()
{
checkReply();
@@ -363,47 +408,6 @@ bool checkContentType(const QByteArray& type, const QByteArrayList& patterns)
return false;
}
-BaseJob::StatusCode BaseJob::Status::fromHttpCode(int httpCode)
-{
- if (httpCode / 10 == 41) // 41x errors
- return httpCode == 410 ? IncorrectRequestError : NotFoundError;
- switch (httpCode) {
- case 401:
- return Unauthorised;
- // clang-format off
- case 403: case 407: // clang-format on
- return ContentAccessError;
- case 404:
- return NotFoundError;
- // clang-format off
- case 400: case 405: case 406: case 426: case 428: case 505: // clang-format on
- case 494: // Unofficial nginx "Request header too large"
- case 497: // Unofficial nginx "HTTP request sent to HTTPS port"
- return IncorrectRequestError;
- case 429:
- return TooManyRequestsError;
- case 501: case 510:
- return RequestNotImplementedError;
- case 511:
- return NetworkAuthRequiredError;
- default:
- return NetworkError;
- }
-}
-
-QDebug BaseJob::Status::dumpToLog(QDebug dbg) const
-{
- QDebugStateSaver _s(dbg);
- dbg.noquote().nospace();
- if (auto* const k = QMetaEnum::fromType<StatusCode>().valueToKey(code)) {
- const QByteArray b = k;
- dbg << b.mid(b.lastIndexOf(':'));
- } else
- dbg << code;
- return dbg << ": " << message;
-
-}
-
BaseJob::Status BaseJob::doCheckReply(QNetworkReply* reply) const
{
// QNetworkReply error codes seem to be flawed when it comes to HTTP;
@@ -440,6 +444,8 @@ BaseJob::Status BaseJob::doCheckReply(QNetworkReply* reply) const
return Status::fromHttpCode(httpCode, message);
}
+void BaseJob::checkReply() { setStatus(doCheckReply(d->reply.data())); }
+
BaseJob::Status BaseJob::parseReply(QNetworkReply* reply)
{
d->rawResponse = reply->readAll();
@@ -602,6 +608,8 @@ QByteArray BaseJob::rawData(int bytesAtMost) const
: d->rawResponse;
}
+const QByteArray& BaseJob::rawData() const { return d->rawResponse; }
+
QString BaseJob::rawDataSample(int bytesAtMost) const
{
auto data = rawData(bytesAtMost);
diff --git a/lib/jobs/basejob.h b/lib/jobs/basejob.h
index 2049f59c..010aca78 100644
--- a/lib/jobs/basejob.h
+++ b/lib/jobs/basejob.h
@@ -157,11 +157,16 @@ public:
/** Short human-friendly message on the job status */
QString statusCaption() const;
- /** Get raw response body as received from the server
- * \param bytesAtMost return this number of leftmost bytes, or -1
- * to return the entire response
+ /*! Get first bytes of the raw response body as received from the server
+ *
+ * \param bytesAtMost the number of leftmost bytes to return
+ *
+ * \sa rawDataSample
*/
- QByteArray rawData(int bytesAtMost = -1) const;
+ QByteArray rawData(int bytesAtMost) const;
+
+ /*! Access the whole response body as received from the server */
+ const QByteArray& rawData() const;
/** Get UI-friendly sample of raw data
*
@@ -170,6 +175,8 @@ public:
* recommended to present a sample of raw data as "details" next to
* error messages. Note that the default \p bytesAtMost value is
* also tailored to UI cases.
+ *
+ * \sa rawData
*/
QString rawDataSample(int bytesAtMost = 65535) const;
@@ -322,6 +329,7 @@ protected:
* on retries.
*/
virtual void doPrepare();
+
/*! Postprocessing after the network request has been sent
*
* This method is called every time the job receives a running
@@ -331,13 +339,15 @@ protected:
virtual void onSentRequest(QNetworkReply*);
virtual void beforeAbandon(QNetworkReply*);
- /**
- * Used by gotReply() to check the received reply for general
- * issues such as network errors or access denial.
- * Returning anything except NoError/Success prevents
- * further parseReply()/parseJson() invocation.
+ /*! \brief Check the pending or received reply for upfront issues
+ *
+ * This is invoked when headers are first received and also once
+ * the complete reply is obtained; the base implementation checks the HTTP
+ * headers to detect general issues such as network errors or access denial.
+ * It cannot read the response body (use parseReply/parseError to check
+ * for problems in the body). Returning anything except NoError/Success
+ * prevents further processing of the reply.
*
- * @param reply the reply received from the server
* @return the result of checking the reply
*
* @see gotReply