summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@theqtcompany.com>2015-10-02 13:55:07 +0200
committerLiang Qi <liang.qi@theqtcompany.com>2015-10-02 13:55:07 +0200
commit6484afa4b7645b31e370f4eb8ea0b93fc3bf052a (patch)
tree9ff1eacd8dcb1943613785e3ad6df77bf38523bb /src
parentf11862a05591452bdad9c1abd244288a2964a036 (diff)
parent12e424f241b29ef26ad2a3a70740d8b320e9e85a (diff)
downloadqtwebsockets-6484afa4b7645b31e370f4eb8ea0b93fc3bf052a.tar.gz
Merge remote-tracking branch 'origin/5.5' into 5.6
Conflicts: tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp Change-Id: Ie4184b0788b6a0a5a85ca8e4d1547c33f7027ca0
Diffstat (limited to 'src')
-rw-r--r--src/websockets/qwebsocket.cpp2
-rw-r--r--src/websockets/qwebsocket_p.cpp43
-rw-r--r--src/websockets/qwebsocket_p.h3
-rw-r--r--src/websockets/qwebsockethandshakerequest.cpp56
-rw-r--r--src/websockets/qwebsockethandshakerequest_p.h2
-rw-r--r--src/websockets/qwebsocketserver_p.cpp8
6 files changed, 86 insertions, 28 deletions
diff --git a/src/websockets/qwebsocket.cpp b/src/websockets/qwebsocket.cpp
index 3635003..0286196 100644
--- a/src/websockets/qwebsocket.cpp
+++ b/src/websockets/qwebsocket.cpp
@@ -281,6 +281,8 @@ QWebSocket::QWebSocket(const QString &origin,
*/
QWebSocket::~QWebSocket()
{
+ Q_D(QWebSocket);
+ d->closeGoingAway();
}
/*!
diff --git a/src/websockets/qwebsocket_p.cpp b/src/websockets/qwebsocket_p.cpp
index b9504f8..1722c15 100644
--- a/src/websockets/qwebsocket_p.cpp
+++ b/src/websockets/qwebsocket_p.cpp
@@ -84,7 +84,7 @@ QWebSocketPrivate::QWebSocketPrivate(const QString &origin, QWebSocketProtocol::
QWebSocket *pWebSocket) :
QObjectPrivate(),
q_ptr(pWebSocket),
- m_pSocket(),
+ m_pSocket(Q_NULLPTR),
m_errorString(),
m_version(version),
m_resourceName(),
@@ -154,7 +154,7 @@ void QWebSocketPrivate::init()
m_pMaskGenerator->seed();
if (m_pSocket) {
- makeConnections(m_pSocket.data());
+ makeConnections(m_pSocket);
}
}
@@ -163,11 +163,18 @@ void QWebSocketPrivate::init()
*/
QWebSocketPrivate::~QWebSocketPrivate()
{
+}
+
+/*!
+ \internal
+*/
+void QWebSocketPrivate::closeGoingAway()
+{
if (!m_pSocket)
return;
if (state() == QAbstractSocket::ConnectedState)
close(QWebSocketProtocol::CloseCodeGoingAway, QWebSocket::tr("Connection closed"));
- releaseConnections(m_pSocket.data());
+ releaseConnections(m_pSocket);
}
/*!
@@ -262,7 +269,7 @@ void QWebSocketPrivate::ignoreSslErrors()
{
m_configuration.m_ignoreSslErrors = true;
if (Q_LIKELY(m_pSocket)) {
- QSslSocket *pSslSocket = qobject_cast<QSslSocket *>(m_pSocket.data());
+ QSslSocket *pSslSocket = qobject_cast<QSslSocket *>(m_pSocket);
if (Q_LIKELY(pSslSocket))
pSslSocket->ignoreSslErrors();
}
@@ -340,7 +347,7 @@ void QWebSocketPrivate::open(const QNetworkRequest &request, bool mask)
{
//just delete the old socket for the moment;
//later, we can add more 'intelligent' handling by looking at the URL
- //m_pSocket.reset();
+
Q_Q(QWebSocket);
QUrl url = request.url();
if (!url.isValid() || url.toString().contains(QStringLiteral("\r\n"))) {
@@ -348,10 +355,10 @@ void QWebSocketPrivate::open(const QNetworkRequest &request, bool mask)
Q_EMIT q->error(QAbstractSocket::ConnectionRefusedError);
return;
}
- QTcpSocket *pTcpSocket = m_pSocket.take();
- if (pTcpSocket) {
- releaseConnections(pTcpSocket);
- pTcpSocket->deleteLater();
+ if (m_pSocket) {
+ releaseConnections(m_pSocket);
+ m_pSocket->deleteLater();
+ m_pSocket = Q_NULLPTR;
}
//if (m_url != url)
if (Q_LIKELY(!m_pSocket)) {
@@ -387,15 +394,15 @@ void QWebSocketPrivate::open(const QNetworkRequest &request, bool mask)
setErrorString(message);
Q_EMIT q->error(QAbstractSocket::UnsupportedSocketOperationError);
} else {
- QSslSocket *sslSocket = new QSslSocket;
- m_pSocket.reset(sslSocket);
+ QSslSocket *sslSocket = new QSslSocket(q_ptr);
+ m_pSocket = sslSocket;
if (Q_LIKELY(m_pSocket)) {
m_pSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
m_pSocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
m_pSocket->setReadBufferSize(m_readBufferSize);
m_pSocket->setPauseMode(m_pauseMode);
- makeConnections(m_pSocket.data());
+ makeConnections(m_pSocket);
setSocketState(QAbstractSocket::ConnectingState);
sslSocket->setSslConfiguration(m_configuration.m_sslConfiguration);
@@ -416,14 +423,14 @@ void QWebSocketPrivate::open(const QNetworkRequest &request, bool mask)
} else
#endif
if (url.scheme() == QStringLiteral("ws")) {
- m_pSocket.reset(new QTcpSocket);
+ m_pSocket = new QTcpSocket(q_ptr);
if (Q_LIKELY(m_pSocket)) {
m_pSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
m_pSocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
m_pSocket->setReadBufferSize(m_readBufferSize);
m_pSocket->setPauseMode(m_pauseMode);
- makeConnections(m_pSocket.data());
+ makeConnections(m_pSocket);
setSocketState(QAbstractSocket::ConnectingState);
#ifndef QT_NO_NETWORKPROXY
m_pSocket->setProxy(m_configuration.m_proxy);
@@ -1105,8 +1112,8 @@ void QWebSocketPrivate::processStateChanged(QAbstractSocket::SocketState socketS
void QWebSocketPrivate::socketDestroyed(QObject *socket)
{
Q_ASSERT(m_pSocket);
- if (m_pSocket.data() == socket)
- m_pSocket.take();
+ if (m_pSocket == socket)
+ m_pSocket = Q_NULLPTR;
}
/*!
@@ -1117,9 +1124,9 @@ void QWebSocketPrivate::processData()
Q_ASSERT(m_pSocket);
while (m_pSocket->bytesAvailable()) {
if (state() == QAbstractSocket::ConnectingState)
- processHandshake(m_pSocket.data());
+ processHandshake(m_pSocket);
else
- m_dataProcessor.process(m_pSocket.data());
+ m_dataProcessor.process(m_pSocket);
}
}
diff --git a/src/websockets/qwebsocket_p.h b/src/websockets/qwebsocket_p.h
index 260e8e8..037df61 100644
--- a/src/websockets/qwebsocket_p.h
+++ b/src/websockets/qwebsocket_p.h
@@ -143,6 +143,7 @@ public:
QSslConfiguration sslConfiguration() const;
#endif
+ void closeGoingAway();
void close(QWebSocketProtocol::CloseCode closeCode, QString reason);
void open(const QNetworkRequest &request, bool mask);
void ping(const QByteArray &payload);
@@ -197,7 +198,7 @@ private:
qint64 writeFrames(const QList<QByteArray> &frames) Q_REQUIRED_RESULT;
qint64 writeFrame(const QByteArray &frame) Q_REQUIRED_RESULT;
- QScopedPointer<QTcpSocket> m_pSocket;
+ QTcpSocket *m_pSocket;
QString m_errorString;
QWebSocketProtocol::Version m_version;
QUrl m_resource;
diff --git a/src/websockets/qwebsockethandshakerequest.cpp b/src/websockets/qwebsockethandshakerequest.cpp
index 528cb32..e2cbaef 100644
--- a/src/websockets/qwebsockethandshakerequest.cpp
+++ b/src/websockets/qwebsockethandshakerequest.cpp
@@ -183,18 +183,49 @@ QUrl QWebSocketHandshakeRequest::requestUrl() const
}
/*!
+ Reads a line of text from the given textstream (terminated by CR/LF).
+ If an empty line was detected, an empty string is returned.
+ When an error occurs, a null string is returned.
\internal
*/
-void QWebSocketHandshakeRequest::readHandshake(QTextStream &textStream)
+static QString readLine(QTextStream &stream, int maxHeaderLineLength)
+{
+ QString line;
+ char c;
+ while (!stream.atEnd()) {
+ stream >> c;
+ if (stream.status() != QTextStream::Ok)
+ return QString();
+ if (c == char('\r')) {
+ //eat the \n character
+ stream >> c;
+ line.append(QStringLiteral(""));
+ break;
+ } else {
+ line.append(QChar::fromLatin1(c));
+ if (line.length() > maxHeaderLineLength)
+ return QString();
+ }
+ }
+ return line;
+}
+
+/*!
+ \internal
+ */
+void QWebSocketHandshakeRequest::readHandshake(QTextStream &textStream, int maxHeaderLineLength,
+ int maxHeaders)
{
- m_isValid = false;
clear();
if (Q_UNLIKELY(textStream.status() != QTextStream::Ok))
return;
- const QString requestLine = textStream.readLine();
+ const QString requestLine = readLine(textStream, maxHeaderLineLength);
+ if (requestLine.isNull()) {
+ clear();
+ return;
+ }
const QStringList tokens = requestLine.split(' ', QString::SkipEmptyParts);
if (Q_UNLIKELY(tokens.length() < 3)) {
- m_isValid = false;
clear();
return;
}
@@ -206,10 +237,13 @@ void QWebSocketHandshakeRequest::readHandshake(QTextStream &textStream)
if (Q_UNLIKELY(!conversionOk)) {
clear();
- m_isValid = false;
return;
}
- QString headerLine = textStream.readLine();
+ QString headerLine = readLine(textStream, maxHeaderLineLength);
+ if (headerLine.isNull()) {
+ clear();
+ return;
+ }
m_headers.clear();
while (!headerLine.isEmpty()) {
const QStringList headerField = headerLine.split(QStringLiteral(": "),
@@ -219,7 +253,15 @@ void QWebSocketHandshakeRequest::readHandshake(QTextStream &textStream)
return;
}
m_headers.insertMulti(headerField.at(0).toLower(), headerField.at(1));
- headerLine = textStream.readLine();
+ if (m_headers.size() > maxHeaders) {
+ clear();
+ return;
+ }
+ headerLine = readLine(textStream, maxHeaderLineLength);
+ if (headerLine.isNull()) {
+ clear();
+ return;
+ }
}
m_requestUrl = QUrl::fromEncoded(resourceName.toLatin1());
diff --git a/src/websockets/qwebsockethandshakerequest_p.h b/src/websockets/qwebsockethandshakerequest_p.h
index ad2a249..6ad5381 100644
--- a/src/websockets/qwebsockethandshakerequest_p.h
+++ b/src/websockets/qwebsockethandshakerequest_p.h
@@ -78,7 +78,7 @@ public:
QString resourceName() const;
QString host() const;
- void readHandshake(QTextStream &textStream);
+ void readHandshake(QTextStream &textStream, int maxHeaderLineLength, int maxHeaders);
private:
diff --git a/src/websockets/qwebsocketserver_p.cpp b/src/websockets/qwebsocketserver_p.cpp
index bc23674..d1750ce 100644
--- a/src/websockets/qwebsocketserver_p.cpp
+++ b/src/websockets/qwebsocketserver_p.cpp
@@ -49,6 +49,12 @@
QT_BEGIN_NAMESPACE
+//both constants are taken from the default settings of Apache
+//see: http://httpd.apache.org/docs/2.2/mod/core.html#limitrequestfieldsize and
+//http://httpd.apache.org/docs/2.2/mod/core.html#limitrequestfields
+const int MAX_HEADERLINE_LENGTH = 8 * 1024; //maximum length of a http request header line
+const int MAX_HEADERLINES = 100; //maximum number of http request header lines
+
/*!
\internal
*/
@@ -431,7 +437,7 @@ void QWebSocketServerPrivate::handshakeReceived()
QWebSocketHandshakeRequest request(pTcpSocket->peerPort(), isSecure);
QTextStream textStream(pTcpSocket);
- request.readHandshake(textStream);
+ request.readHandshake(textStream, MAX_HEADERLINE_LENGTH, MAX_HEADERLINES);
if (request.isValid()) {
QWebSocketCorsAuthenticator corsAuthenticator(request.origin());