diff options
author | Liang Qi <liang.qi@theqtcompany.com> | 2015-10-20 21:12:53 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@theqtcompany.com> | 2015-10-20 21:12:53 +0200 |
commit | c2201fad153a64f1c6da84390de4316aedf3a2cd (patch) | |
tree | 0a499309b34087ff7390d77f3a6e8c0266cdd213 /src/websockets | |
parent | d0f71b3feaca6923e89f85993f13cc9da0923412 (diff) | |
parent | b59b0634715c13a191b678a0652ea4e3274865fa (diff) | |
download | qtwebsockets-c2201fad153a64f1c6da84390de4316aedf3a2cd.tar.gz |
Merge remote-tracking branch 'origin/5.6' into dev
Change-Id: I8d2c4b0982623839b880a9d8fbe7f5ee69d33ad3
Diffstat (limited to 'src/websockets')
-rw-r--r-- | src/websockets/doc/qtwebsockets.qdocconf | 8 | ||||
-rw-r--r-- | src/websockets/qmaskgenerator.h | 2 | ||||
-rw-r--r-- | src/websockets/qsslserver_p.h | 11 | ||||
-rw-r--r-- | src/websockets/qwebsocket.cpp | 2 | ||||
-rw-r--r-- | src/websockets/qwebsocket_p.cpp | 43 | ||||
-rw-r--r-- | src/websockets/qwebsocket_p.h | 3 | ||||
-rw-r--r-- | src/websockets/qwebsocketframe.cpp | 54 | ||||
-rw-r--r-- | src/websockets/qwebsocketframe_p.h | 26 | ||||
-rw-r--r-- | src/websockets/qwebsockethandshakerequest.cpp | 56 | ||||
-rw-r--r-- | src/websockets/qwebsockethandshakerequest_p.h | 2 | ||||
-rw-r--r-- | src/websockets/qwebsocketprotocol_p.h | 11 | ||||
-rw-r--r-- | src/websockets/qwebsocketserver_p.cpp | 8 |
12 files changed, 148 insertions, 78 deletions
diff --git a/src/websockets/doc/qtwebsockets.qdocconf b/src/websockets/doc/qtwebsockets.qdocconf index 002898c..4504d30 100644 --- a/src/websockets/doc/qtwebsockets.qdocconf +++ b/src/websockets/doc/qtwebsockets.qdocconf @@ -4,7 +4,7 @@ project = QtWebSockets description = Qt WebSockets Reference Documentation version = $QT_VERSION -examplesinstallpath = websockets +examplesinstallpath = qtwebsockets/websockets qhp.projects = QtWebSockets @@ -56,7 +56,11 @@ examples.fileextensions += "*.html" imagedirs += ../../../examples/websockets/doc/images \ images -manifestmeta.thumbnail.names += "QtWebSockets/*" +#add generic thumbnail images for example documentation that does not have an image. +manifestmeta.thumbnail.names += "QtWebSockets/Echo Client*" \ + "QtWebSockets/QML*" \ + "QtWebSockets/SSL*" \ + "QtWebSockets/Simple*" navigation.landingpage = "Qt WebSockets" navigation.cppclassespage = "Qt WebSockets C++ Classes" diff --git a/src/websockets/qmaskgenerator.h b/src/websockets/qmaskgenerator.h index a155340..4a13b1d 100644 --- a/src/websockets/qmaskgenerator.h +++ b/src/websockets/qmaskgenerator.h @@ -34,7 +34,7 @@ #ifndef QMASKGENERATOR_H #define QMASKGENERATOR_H -#include <QObject> +#include <QtCore/QObject> #include "QtWebSockets/qwebsockets_global.h" QT_BEGIN_NAMESPACE diff --git a/src/websockets/qsslserver_p.h b/src/websockets/qsslserver_p.h index 18e1a19..bb8c7f9 100644 --- a/src/websockets/qsslserver_p.h +++ b/src/websockets/qsslserver_p.h @@ -34,6 +34,17 @@ #ifndef QSSLSERVER_P_H #define QSSLSERVER_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtNetwork/QTcpServer> #include <QtNetwork/QSslError> #include <QtNetwork/QSslConfiguration> 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/qwebsocketframe.cpp b/src/websockets/qwebsocketframe.cpp index d533921..b76fa5c 100644 --- a/src/websockets/qwebsocketframe.cpp +++ b/src/websockets/qwebsocketframe.cpp @@ -61,14 +61,14 @@ QT_BEGIN_NAMESPACE QWebSocketFrame::QWebSocketFrame() : m_closeCode(QWebSocketProtocol::CloseCodeNormal), m_closeReason(), - m_isFinalFrame(true), m_mask(0), - m_rsv1(0), - m_rsv2(0), - m_rsv3(0), m_opCode(QWebSocketProtocol::OpCodeReservedC), m_length(0), m_payload(), + m_isFinalFrame(true), + m_rsv1(false), + m_rsv2(false), + m_rsv3(false), m_isValid(false) { } @@ -79,14 +79,14 @@ QWebSocketFrame::QWebSocketFrame() : QWebSocketFrame::QWebSocketFrame(const QWebSocketFrame &other) : m_closeCode(other.m_closeCode), m_closeReason(other.m_closeReason), - m_isFinalFrame(other.m_isFinalFrame), m_mask(other.m_mask), - m_rsv1(other.m_rsv1), - m_rsv2(other.m_rsv2), - m_rsv3(other.m_rsv3), m_opCode(other.m_opCode), m_length(other.m_length), m_payload(other.m_payload), + m_isFinalFrame(other.m_isFinalFrame), + m_rsv1(other.m_rsv1), + m_rsv2(other.m_rsv2), + m_rsv3(other.m_rsv3), m_isValid(other.m_isValid) { } @@ -118,14 +118,14 @@ QWebSocketFrame &QWebSocketFrame::operator =(const QWebSocketFrame &other) QWebSocketFrame::QWebSocketFrame(QWebSocketFrame &&other) : m_closeCode(qMove(other.m_closeCode)), m_closeReason(qMove(other.m_closeReason)), - m_isFinalFrame(qMove(other.m_isFinalFrame)), m_mask(qMove(other.m_mask)), - m_rsv1(qMove(other.m_rsv1)), - m_rsv2(qMove(other.m_rsv2)), - m_rsv3(qMove(other.m_rsv3)), m_opCode(qMove(other.m_opCode)), m_length(qMove(other.m_length)), m_payload(qMove(other.m_payload)), + m_isFinalFrame(qMove(other.m_isFinalFrame)), + m_rsv1(qMove(other.m_rsv1)), + m_rsv2(qMove(other.m_rsv2)), + m_rsv3(qMove(other.m_rsv3)), m_isValid(qMove(other.m_isValid)) {} @@ -239,30 +239,6 @@ quint32 QWebSocketFrame::mask() const /*! \internal */ -int QWebSocketFrame::rsv1() const -{ - return m_rsv1; -} - -/*! - \internal - */ -int QWebSocketFrame::rsv2() const -{ - return m_rsv2; -} - -/*! - \internal - */ -int QWebSocketFrame::rsv3() const -{ - return m_rsv3; -} - -/*! - \internal - */ QWebSocketProtocol::OpCode QWebSocketFrame::opCode() const { return m_opCode; @@ -287,9 +263,9 @@ void QWebSocketFrame::clear() m_closeReason.clear(); m_isFinalFrame = true; m_mask = 0; - m_rsv1 = 0; - m_rsv2 = 0; - m_rsv3 = 0; + m_rsv1 = false; + m_rsv2 = false; + m_rsv3 = false; m_opCode = QWebSocketProtocol::OpCodeReservedC; m_length = 0; m_payload.clear(); diff --git a/src/websockets/qwebsocketframe_p.h b/src/websockets/qwebsocketframe_p.h index 131775b..46bc510 100644 --- a/src/websockets/qwebsocketframe_p.h +++ b/src/websockets/qwebsocketframe_p.h @@ -34,6 +34,17 @@ #ifndef QWEBSOCKETFRAME_P_H #define QWEBSOCKETFRAME_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtCore/QString> #include <QtCore/QByteArray> #include <QtCore/QCoreApplication> @@ -75,9 +86,9 @@ public: bool isContinuationFrame() const; bool hasMask() const; quint32 mask() const; //returns 0 if no mask - int rsv1() const; - int rsv2() const; - int rsv3() const; + inline bool rsv1() const { return m_rsv1; } + inline bool rsv2() const { return m_rsv2; } + inline bool rsv3() const { return m_rsv3; } QWebSocketProtocol::OpCode opCode() const; QByteArray payload() const; @@ -90,16 +101,15 @@ public: private: QWebSocketProtocol::CloseCode m_closeCode; QString m_closeReason; - bool m_isFinalFrame; quint32 m_mask; - int m_rsv1; - int m_rsv2; - int m_rsv3; QWebSocketProtocol::OpCode m_opCode; - quint8 m_length; QByteArray m_payload; + bool m_isFinalFrame; + bool m_rsv1; + bool m_rsv2; + bool m_rsv3; bool m_isValid; enum ProcessingState 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/qwebsocketprotocol_p.h b/src/websockets/qwebsocketprotocol_p.h index bf56332..9aab8ce 100644 --- a/src/websockets/qwebsocketprotocol_p.h +++ b/src/websockets/qwebsocketprotocol_p.h @@ -34,6 +34,17 @@ #ifndef QWEBSOCKETPROTOCOL_P_H #define QWEBSOCKETPROTOCOL_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtCore/qglobal.h> #include "QtWebSockets/qwebsocketprotocol.h" 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()); |