summaryrefslogtreecommitdiff
path: root/src/network/access/qhttpnetworkreply.cpp
diff options
context:
space:
mode:
authorØystein Heskestad <oystein.heskestad@qt.io>2021-08-03 16:31:52 +0200
committerØystein Heskestad <oystein.heskestad@qt.io>2021-09-09 16:55:50 +0200
commit9a602e68cf9dd29638027894032b6052c0526426 (patch)
tree288622ec0b595a7ecbd33413c3ff0a2b13e9b9c3 /src/network/access/qhttpnetworkreply.cpp
parent1fb242ba9f9b7d96c34acafadac3815821ea2f7d (diff)
downloadqtbase-9a602e68cf9dd29638027894032b6052c0526426.tar.gz
Move QNAM's http header parsing into separate class
Fixes: QTBUG-80701 Change-Id: I43f5e102c15d121dba74e07e3cd4bb8aded1c763 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src/network/access/qhttpnetworkreply.cpp')
-rw-r--r--src/network/access/qhttpnetworkreply.cpp133
1 files changed, 49 insertions, 84 deletions
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
index 0ad5ee372e..7582ce179f 100644
--- a/src/network/access/qhttpnetworkreply.cpp
+++ b/src/network/access/qhttpnetworkreply.cpp
@@ -103,7 +103,7 @@ void QHttpNetworkReply::setContentLength(qint64 length)
QList<QPair<QByteArray, QByteArray> > QHttpNetworkReply::header() const
{
- return d_func()->fields;
+ return d_func()->parser.headers();
}
QByteArray QHttpNetworkReply::headerField(const QByteArray &name, const QByteArray &defaultValue) const
@@ -117,6 +117,12 @@ void QHttpNetworkReply::setHeaderField(const QByteArray &name, const QByteArray
d->setHeaderField(name, data);
}
+void QHttpNetworkReply::appendHeaderField(const QByteArray &name, const QByteArray &data)
+{
+ Q_D(QHttpNetworkReply);
+ d->appendHeaderField(name, data);
+}
+
void QHttpNetworkReply::parseHeader(const QByteArray &header)
{
Q_D(QHttpNetworkReply);
@@ -137,13 +143,13 @@ void QHttpNetworkReply::setRequest(const QHttpNetworkRequest &request)
int QHttpNetworkReply::statusCode() const
{
- return d_func()->statusCode;
+ return d_func()->parser.getStatusCode();
}
void QHttpNetworkReply::setStatusCode(int code)
{
Q_D(QHttpNetworkReply);
- d->statusCode = code;
+ d->parser.setStatusCode(code);
}
QString QHttpNetworkReply::errorString() const
@@ -158,7 +164,12 @@ QNetworkReply::NetworkError QHttpNetworkReply::errorCode() const
QString QHttpNetworkReply::reasonPhrase() const
{
- return d_func()->reasonPhrase;
+ return d_func()->parser.getReasonPhrase();
+}
+
+void QHttpNetworkReply::setReasonPhrase(const QString &reason)
+{
+ d_func()->parser.setReasonPhrase(reason);
}
void QHttpNetworkReply::setErrorString(const QString &error)
@@ -169,12 +180,22 @@ void QHttpNetworkReply::setErrorString(const QString &error)
int QHttpNetworkReply::majorVersion() const
{
- return d_func()->majorVersion;
+ return d_func()->parser.getMajorVersion();
}
int QHttpNetworkReply::minorVersion() const
{
- return d_func()->minorVersion;
+ return d_func()->parser.getMinorVersion();
+}
+
+void QHttpNetworkReply::setMajorVersion(int version)
+{
+ d_func()->parser.setMajorVersion(version);
+}
+
+void QHttpNetworkReply::setMinorVersion(int version)
+{
+ d_func()->parser.setMinorVersion(version);
}
qint64 QHttpNetworkReply::bytesAvailable() const
@@ -248,7 +269,8 @@ void QHttpNetworkReply::setReadBufferSize(qint64 size)
bool QHttpNetworkReply::supportsUserProvidedDownloadBuffer()
{
Q_D(QHttpNetworkReply);
- return (!d->isChunked() && !d->autoDecompress && d->bodyLength > 0 && d->statusCode == 200);
+ return !d->isChunked() && !d->autoDecompress &&
+ d->bodyLength > 0 && d->parser.getStatusCode() == 200;
}
void QHttpNetworkReply::setUserProvidedDownloadBuffer(char* b)
@@ -314,9 +336,8 @@ QHttpNetworkConnection* QHttpNetworkReply::connection()
QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl)
: QHttpNetworkHeaderPrivate(newUrl)
, state(NothingDoneState)
- , ssl(false)
- , statusCode(100),
- majorVersion(0), minorVersion(0), bodyLength(0), contentRead(0), totalProgress(0),
+ , ssl(false),
+ bodyLength(0), contentRead(0), totalProgress(0),
chunkedTransferEncoding(false),
connectionCloseEnabled(true),
forceConnectionCloseEnabled(false),
@@ -342,7 +363,6 @@ QHttpNetworkReplyPrivate::~QHttpNetworkReplyPrivate() = default;
void QHttpNetworkReplyPrivate::clearHttpLayerInformation()
{
state = NothingDoneState;
- statusCode = 100;
bodyLength = 0;
contentRead = 0;
totalProgress = 0;
@@ -350,7 +370,7 @@ void QHttpNetworkReplyPrivate::clearHttpLayerInformation()
currentChunkRead = 0;
lastChunkRead = false;
connectionCloseEnabled = true;
- fields.clear();
+ parser.clear();
}
// TODO: Isn't everything HTTP layer related? We don't need to set connection and connectionChannel to 0 at all
@@ -384,15 +404,12 @@ void QHttpNetworkReplyPrivate::removeAutoDecompressHeader()
// The header "Content-Encoding = gzip" is retained.
// Content-Length is removed since the actual one sent by the server is for compressed data
QByteArray name("content-length");
- QList<QPair<QByteArray, QByteArray> >::Iterator it = fields.begin(),
- end = fields.end();
- while (it != end) {
- if (name.compare(it->first, Qt::CaseInsensitive) == 0) {
- removedContentLength = strtoull(it->second.constData(), nullptr, 0);
- fields.erase(it);
- break;
- }
- ++it;
+ QByteArray contentLength = parser.firstHeaderField(name);
+ bool parseOk = false;
+ qint64 value = contentLength.toLongLong(&parseOk);
+ if (parseOk) {
+ removedContentLength = value;
+ parser.removeHeaderField(name);
}
}
@@ -463,38 +480,7 @@ qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket)
bool QHttpNetworkReplyPrivate::parseStatus(const QByteArray &status)
{
- // from RFC 2616:
- // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
- // HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
- // that makes: 'HTTP/n.n xxx Message'
- // byte count: 0123456789012
-
- static const int minLength = 11;
- static const int dotPos = 6;
- static const int spacePos = 8;
- static const char httpMagic[] = "HTTP/";
-
- if (status.length() < minLength
- || !status.startsWith(httpMagic)
- || status.at(dotPos) != '.'
- || status.at(spacePos) != ' ') {
- // I don't know how to parse this status line
- return false;
- }
-
- // optimize for the valid case: defer checking until the end
- majorVersion = status.at(dotPos - 1) - '0';
- minorVersion = status.at(dotPos + 1) - '0';
-
- int i = spacePos;
- int j = status.indexOf(' ', i + 1); // j == -1 || at(j) == ' ' so j+1 == 0 && j+1 <= length()
- const QByteArray code = status.mid(i + 1, j - i - 1);
-
- bool ok;
- statusCode = code.toInt(&ok);
- reasonPhrase = QString::fromLatin1(status.constData() + j + 1);
-
- return ok && uint(majorVersion) <= 9 && uint(minorVersion) <= 9;
+ return parser.parseStatus(status);
}
qint64 QHttpNetworkReplyPrivate::readHeader(QAbstractSocket *socket)
@@ -553,7 +539,7 @@ qint64 QHttpNetworkReplyPrivate::readHeader(QAbstractSocket *socket)
// check for explicit indication of close or the implicit connection close of HTTP/1.0
connectionCloseEnabled = (connectionHeaderField.toLower().contains("close") ||
headerField("proxy-connection").toLower().contains("close")) ||
- (majorVersion == 1 && minorVersion == 0 &&
+ (parser.getMajorVersion() == 1 && parser.getMinorVersion() == 0 &&
(connectionHeaderField.isEmpty() && !headerField("proxy-connection").toLower().contains("keep-alive")));
}
return bytes;
@@ -561,34 +547,12 @@ qint64 QHttpNetworkReplyPrivate::readHeader(QAbstractSocket *socket)
void QHttpNetworkReplyPrivate::parseHeader(const QByteArray &header)
{
- // see rfc2616, sec 4 for information about HTTP/1.1 headers.
- // allows relaxed parsing here, accepts both CRLF & LF line endings
- int i = 0;
- while (i < header.count()) {
- int j = header.indexOf(':', i); // field-name
- if (j == -1)
- break;
- const QByteArray field = header.mid(i, j - i).trimmed();
- j++;
- // any number of LWS is allowed before and after the value
- QByteArray value;
- do {
- i = header.indexOf('\n', j);
- if (i == -1)
- break;
- if (!value.isEmpty())
- value += ' ';
- // check if we have CRLF or only LF
- bool hasCR = (i && header[i-1] == '\r');
- int length = i -(hasCR ? 1: 0) - j;
- value += header.mid(j, length).trimmed();
- j = ++i;
- } while (i < header.count() && (header.at(i) == ' ' || header.at(i) == '\t'));
- if (i == -1)
- break; // something is wrong
-
- fields.append(qMakePair(field, value));
- }
+ parser.parseHeaders(header);
+}
+
+void QHttpNetworkReplyPrivate::appendHeaderField(const QByteArray &name, const QByteArray &data)
+{
+ parser.appendHeaderField(name, data);
}
bool QHttpNetworkReplyPrivate::isChunked()
@@ -811,7 +775,7 @@ bool QHttpNetworkReplyPrivate::isRedirecting() const
{
// We're in the process of redirecting - if the HTTP status code says so and
// followRedirect is switched on
- return (QHttpNetworkReply::isHttpRedirect(statusCode)
+ return (QHttpNetworkReply::isHttpRedirect(parser.getStatusCode())
&& request.isFollowRedirects());
}
@@ -819,11 +783,12 @@ bool QHttpNetworkReplyPrivate::shouldEmitSignals()
{
// for 401 & 407 don't emit the data signals. Content along with these
// responses are sent only if the authentication fails.
- return (statusCode != 401 && statusCode != 407);
+ return parser.getStatusCode() != 401 && parser.getStatusCode() != 407;
}
bool QHttpNetworkReplyPrivate::expectContent()
{
+ int statusCode = parser.getStatusCode();
// check whether we can expect content after the headers (rfc 2616, sec4.4)
if ((statusCode >= 100 && statusCode < 200)
|| statusCode == 204 || statusCode == 304)