summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMilian Wolff <milian.wolff@kdab.com>2014-01-31 17:39:19 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-03-06 23:55:11 +0100
commit6547d3305a872163158510cae5b8fc61efb8bca0 (patch)
tree8a51312a8c598207c53e1027169c52f0d214d06b
parent6b3569c2cb761afe4eba626067b7c686eda866e6 (diff)
downloadqtwebchannel-6547d3305a872163158510cae5b8fc61efb8bca0.tar.gz
Port code to QtWebSockets.
This removes the custom WebSocket server implementation and replaces it by a dependency on the QtWebSockets module. Sadly, the QtWebSocket module does not yet support custom protocols. Also, there is quite some boiler plate code required, something which I want to simplify upstream in the QtWebSockets module later. Change-Id: I8066418fb1857d23b8593c443bc9a98ded917a99 Reviewed-by: Kurt Pattyn <pattyn.kurt@gmail.com> Reviewed-by: Frederik Gladhorn <frederik.gladhorn@digia.com>
-rw-r--r--src/webchannel/qwebchannel.js3
-rw-r--r--src/webchannel/qwebchannelsocket.cpp61
-rw-r--r--src/webchannel/qwebchannelsocket_p.h16
-rw-r--r--src/webchannel/qwebsocketserver.cpp430
-rw-r--r--src/webchannel/qwebsocketserver_p.h163
-rw-r--r--src/webchannel/qwebsockettransport.cpp4
-rw-r--r--src/webchannel/webchannel.pro4
-rw-r--r--sync.profile5
8 files changed, 68 insertions, 618 deletions
diff --git a/src/webchannel/qwebchannel.js b/src/webchannel/qwebchannel.js
index 887c5a0..9aa174b 100644
--- a/src/webchannel/qwebchannel.js
+++ b/src/webchannel/qwebchannel.js
@@ -101,7 +101,8 @@ var QWebChannel = function(baseUrlOrSocket, initCallback, rawChannel)
} else {
///TODO: use ssl?
var socketUrl = "ws://" + baseUrlOrSocket;
- this.socket = new WebSocket(socketUrl, "QWebChannel");
+ ///TODO: use QWebChannel protocol, once custom protcols are supported by QtWebSocket
+ this.socket = new WebSocket(socketUrl /*, "QWebChannel" */);
this.socket.onopen = this.initialized
this.socket.onclose = function()
diff --git a/src/webchannel/qwebchannelsocket.cpp b/src/webchannel/qwebchannelsocket.cpp
index b3daf8f..e6a58c8 100644
--- a/src/webchannel/qwebchannelsocket.cpp
+++ b/src/webchannel/qwebchannelsocket.cpp
@@ -44,18 +44,26 @@
#include <QUuid>
#include <QDebug>
+#include <QtWebSockets/QWebSocket>
+
QT_BEGIN_NAMESPACE
QWebChannelSocket::QWebChannelSocket(QObject *parent)
- : QWebSocketServer(parent)
+ : QWebSocketServer(QStringLiteral("QWebChannel Server"), NonSecureMode, parent)
, m_messageHandler(Q_NULLPTR)
, m_useSecret(true)
, m_starting(false)
{
- connect(this, SIGNAL(error(QAbstractSocket::SocketError)),
+ connect(this, SIGNAL(acceptError(QAbstractSocket::SocketError)),
SLOT(socketError()));
- connect(this, SIGNAL(textDataReceived(QString)),
- SLOT(messageReceived(QString)));
+ connect(this, SIGNAL(newConnection()),
+ SLOT(validateNewConnection()));
+}
+
+QWebChannelSocket::~QWebChannelSocket()
+{
+ close();
+ qDeleteAll(m_clients);
}
void QWebChannelSocket::initLater()
@@ -66,13 +74,29 @@ void QWebChannelSocket::initLater()
m_starting = true;
}
-bool QWebChannelSocket::isValid(const HeaderData &connection)
+void QWebChannelSocket::sendMessage(const QString &message)
+{
+ foreach (QWebSocket *client, m_clients) {
+ client->sendTextMessage(message);
+ }
+}
+
+void QWebChannelSocket::validateNewConnection()
{
- if (!QWebSocketServer::isValid(connection)) {
- return false;
+ QWebSocket *client = nextPendingConnection();
+ // FIXME: client->protocol() != QStringLiteral("QWebChannel")
+ // protocols are not supported in QtWebSockets yet...
+ if (m_useSecret && client->requestUrl().path() != m_secret)
+ {
+ client->close(QWebSocketProtocol::CloseCodeBadOperation);
+ client->deleteLater();
+ } else {
+ connect(client, SIGNAL(textMessageReceived(QString)),
+ SLOT(messageReceived(QString)));
+ connect(client, SIGNAL(disconnected()),
+ SLOT(clientDisconnected()));
+ m_clients << client;
}
- return connection.protocol == QByteArrayLiteral("QWebChannel")
- && connection.path == m_secret;
}
void QWebChannelSocket::init()
@@ -81,9 +105,9 @@ void QWebChannelSocket::init()
m_starting = false;
if (m_useSecret) {
- m_secret = QUuid::createUuid().toByteArray();
+ m_secret = QUuid::createUuid().toString();
// replace { by /
- m_secret[0] = '/';
+ m_secret[0] = QLatin1Char('/');
// chop of trailing }
m_secret.chop(1);
}
@@ -93,7 +117,7 @@ void QWebChannelSocket::init()
return;
}
- m_baseUrl = QStringLiteral("127.0.0.1:%1%2").arg(port()).arg(QString::fromLatin1(m_secret));
+ m_baseUrl = QStringLiteral("127.0.0.1:%1%2").arg(serverPort()).arg(m_secret);
emit initialized();
emit baseUrlChanged(m_baseUrl);
}
@@ -108,6 +132,19 @@ void QWebChannelSocket::messageReceived(const QString &message)
if (m_messageHandler) {
m_messageHandler->handleMessage(message);
}
+ emit textDataReceived(message);
+}
+
+void QWebChannelSocket::clientDisconnected()
+{
+ QWebSocket *client = qobject_cast<QWebSocket*>(sender());
+ if (!client) {
+ return;
+ }
+ const int idx = m_clients.indexOf(client);
+ Q_ASSERT(idx != -1);
+ m_clients.remove(idx);
+ client->deleteLater();
}
QT_END_NAMESPACE
diff --git a/src/webchannel/qwebchannelsocket_p.h b/src/webchannel/qwebchannelsocket_p.h
index 9d6cde5..74f5c48 100644
--- a/src/webchannel/qwebchannelsocket_p.h
+++ b/src/webchannel/qwebchannelsocket_p.h
@@ -42,7 +42,8 @@
#ifndef QWEBCHANNELSOCKET_P_H
#define QWEBCHANNELSOCKET_P_H
-#include "qwebsocketserver_p.h"
+#include <QtWebSockets/QWebSocketServer>
+
#include "qwebchanneltransportinterface.h"
QT_BEGIN_NAMESPACE
@@ -51,7 +52,7 @@ class QWebChannelSocket : public QWebSocketServer
{
Q_OBJECT
public:
- QByteArray m_secret;
+ QString m_secret;
QString m_baseUrl;
QWebChannelMessageHandlerInterface *m_messageHandler;
@@ -59,21 +60,26 @@ public:
bool m_starting;
explicit QWebChannelSocket(QObject *parent = 0);
+ virtual ~QWebChannelSocket();
void initLater();
+ void sendMessage(const QString &message);
signals:
void failed(const QString &reason);
void initialized();
void baseUrlChanged(const QString &baseUrl);
-
-protected:
- bool isValid(const HeaderData &connection) Q_DECL_OVERRIDE;
+ void textDataReceived(const QString &message);
private slots:
+ void validateNewConnection();
void init();
void socketError();
void messageReceived(const QString &message);
+ void clientDisconnected();
+
+private:
+ QVector<QWebSocket*> m_clients;
};
QT_END_NAMESPACE
diff --git a/src/webchannel/qwebsocketserver.cpp b/src/webchannel/qwebsocketserver.cpp
deleted file mode 100644
index 5a5b5a7..0000000
--- a/src/webchannel/qwebsocketserver.cpp
+++ /dev/null
@@ -1,430 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com>
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtWebChannel module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwebsocketserver_p.h"
-
-#include <QTcpServer>
-#include <QTcpSocket>
-#include <QCryptographicHash>
-#include <QtEndian>
-
-#include <limits>
-
-QT_BEGIN_NAMESPACE
-
-namespace {
-template<typename T>
-inline static void appendBytes(QByteArray& data, T value)
-{
- data.append(reinterpret_cast<const char*>(&value), sizeof(value));
-}
-
-inline static void unmask(QByteArray& data, char mask[4])
-{
- for (int i = 0; i < data.size(); ++i) {
- int j = i % 4;
- data[i] = data[i] ^ mask[j];
- }
-}
-
-inline static char bitMask(int bit)
-{
- return 1 << bit;
-}
-
-// see: http://tools.ietf.org/html/rfc6455#page-28
-static const char FIN_BIT = bitMask(7);
-static const char MASKED_BIT = bitMask(7);
-static const char OPCODE_RANGE = bitMask(4) - 1;
-static const char PAYLOAD_RANGE = bitMask(7) - 1;
-static const char EXTENDED_PAYLOAD = 126;
-static const char EXTENDED_LONG_PAYLOAD = 127;
-}
-
-QWebSocketServer::QWebSocketServer(QObject* parent)
-: QObject(parent)
-, m_server(new QTcpServer(this))
-{
- connect(m_server, SIGNAL(newConnection()),
- SLOT(newConnection()));
- connect(m_server, SIGNAL(acceptError(QAbstractSocket::SocketError)),
- SIGNAL(error(QAbstractSocket::SocketError)));
-}
-
-QWebSocketServer::~QWebSocketServer()
-{
- close();
-}
-
-bool QWebSocketServer::listen(const QHostAddress& address, quint16 port)
-{
- return m_server->listen(address, port);
-}
-
-void QWebSocketServer::close()
-{
- sendFrame(Frame::ConnectionClose, QByteArray());
- m_server->close();
-}
-
-quint16 QWebSocketServer::port() const
-{
- return m_server->serverPort();
-}
-
-QHostAddress QWebSocketServer::address() const
-{
- return m_server->serverAddress();
-}
-
-QString QWebSocketServer::errorString() const
-{
- return m_server->errorString();
-}
-
-void QWebSocketServer::newConnection()
-{
- if (!m_server->hasPendingConnections())
- return;
-
- QTcpSocket* connection = m_server->nextPendingConnection();
- m_connections.insert(connection, Connection());
- connect(connection, SIGNAL(readyRead()),
- SLOT(readSocketData()));
- connect(connection, SIGNAL(error(QAbstractSocket::SocketError)),
- SIGNAL(error(QAbstractSocket::SocketError)));
- connect(connection, SIGNAL(disconnected()),
- SLOT(disconnected()));
-}
-
-void QWebSocketServer::disconnected()
-{
- QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
- Q_ASSERT(socket);
-
- m_connections.remove(socket);
-}
-
-static const QByteArray headerSwitchProtocols = QByteArrayLiteral("HTTP/1.1 101 Switching Protocols");
-static const QByteArray headerGet = QByteArrayLiteral("GET ");
-static const QByteArray headerHTTP = QByteArrayLiteral("HTTP/1.1");
-static const QByteArray headerHost = QByteArrayLiteral("Host: ");
-static const QByteArray headerUpgrade = QByteArrayLiteral("Upgrade: websocket");
-static const QByteArray headerConnection = QByteArrayLiteral("Connection: Upgrade");
-static const QByteArray headerSecKey = QByteArrayLiteral("Sec-WebSocket-Key: ");
-static const QByteArray headerSecProtocol = QByteArrayLiteral("Sec-WebSocket-Protocol: ");
-static const QByteArray headerSecVersion = QByteArrayLiteral("Sec-WebSocket-Version: 13");
-static const QByteArray headerSecAccept = QByteArrayLiteral("Sec-WebSocket-Accept: ");
-static const QByteArray headerOrigin = QByteArrayLiteral("Origin: ");
-static const QByteArray headerMagicKey = QByteArrayLiteral("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
-static const QByteArray headerEOL = QByteArrayLiteral("\r\n");
-static const QByteArray httpBadRequest = QByteArrayLiteral("HTTP/1.1 400 Bad Request\r\n");
-
-void QWebSocketServer::readSocketData()
-{
- QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
- Q_ASSERT(socket);
-
- Connection& connection = m_connections[socket];
-
- if (!connection.header.wasUpgraded) {
- readHeaderData(socket, connection.header);
- }
-
- if (connection.header.wasUpgraded) {
- while (socket->bytesAvailable()) {
- if (!readFrameData(socket, connection.currentFrame)) {
- close(socket, connection.header);
- }
- }
- }
-}
-
-void QWebSocketServer::readHeaderData(QTcpSocket* socket, HeaderData& header)
-{
- while (socket->canReadLine()) {
- QByteArray line = socket->readLine().trimmed();
- if (line.isEmpty()) {
- // finalize
- if (isValid(header)) {
- upgrade(socket, header);
- } else {
- close(socket, header);
- }
- break;
- } else if (line.startsWith(headerGet) && line.endsWith(headerHTTP)) {
- header.path = line.mid(headerGet.size(), line.size() - headerGet.size() - headerHTTP.size()).trimmed();
- } else if (line.startsWith(headerHost)) {
- header.host = line.mid(headerHost.size()).trimmed();
- } else if (line.startsWith(headerSecKey)) {
- header.key = line.mid(headerSecKey.size()).trimmed();
- } else if (line.startsWith(headerOrigin)) {
- header.origin = line.mid(headerOrigin.size()).trimmed();
- } else if (line.startsWith(headerSecProtocol)) {
- header.protocol = line.mid(headerSecProtocol.size()).trimmed();
- } else if (line == headerUpgrade) {
- header.hasUpgrade = true;
- } else if (line == headerConnection) {
- header.hasConnection = true;
- } else if (line == headerSecVersion) {
- header.hasVersion = true;
- } else {
- header.otherHeaders << line;
- }
- }
-}
-
-// see: http://tools.ietf.org/html/rfc6455#page-28
-bool QWebSocketServer::readFrameData(QTcpSocket* socket, Frame& frame)
-{
- int bytesAvailable = socket->bytesAvailable();
- if (frame.state == Frame::ReadStart) {
- if (bytesAvailable < 2) {
- return true;
- }
- uchar buffer[2];
- socket->read(reinterpret_cast<char*>(buffer), 2);
- bytesAvailable -= 2;
- frame.fin = buffer[0] & FIN_BIT;
- // skip rsv1, rsv2, rsv3
- // last four bits are the opcode
- quint8 opcode = buffer[0] & OPCODE_RANGE;
- if (opcode != Frame::ContinuationFrame && opcode != Frame::BinaryFrame &&
- opcode != Frame::ConnectionClose && opcode != Frame::TextFrame &&
- opcode != Frame::Ping && opcode != Frame::Pong)
- {
- qWarning() << "invalid opcode: " << opcode;
- return false;
- }
- frame.opcode = static_cast<Frame::Opcode>(opcode);
- // test first, i.e. highest bit for mask
- frame.masked = buffer[1] & MASKED_BIT;
- if (!frame.masked) {
- qWarning() << "unmasked frame received";
- return false;
- }
- // final seven bits are the payload length
- frame.length = static_cast<quint8>(buffer[1] & PAYLOAD_RANGE);
- if (frame.length == EXTENDED_PAYLOAD) {
- frame.state = Frame::ReadExtendedPayload;
- } else if (frame.length == EXTENDED_LONG_PAYLOAD) {
- frame.state = Frame::ReadExtendedLongPayload;
- } else {
- frame.state = Frame::ReadMask;
- }
- }
- if (frame.state == Frame::ReadExtendedPayload) {
- if (bytesAvailable < 2) {
- return true;
- }
- uchar buffer[2];
- socket->read(reinterpret_cast<char*>(buffer), 2);
- bytesAvailable -= 2;
- frame.length = qFromBigEndian<quint16>(buffer);
- frame.state = Frame::ReadMask;
- }
- if (frame.state == Frame::ReadExtendedLongPayload) {
- if (bytesAvailable < 8) {
- return true;
- }
- uchar buffer[8];
- socket->read(reinterpret_cast<char*>(buffer), 8);
- bytesAvailable -= 8;
- quint64 longSize = qFromBigEndian<quint64>(buffer);
- // QByteArray uses int for size type so limit ourselves to that size as well
- if (longSize > static_cast<quint64>(std::numeric_limits<int>::max())) {
- return false;
- }
- frame.length = static_cast<int>(longSize);
- frame.state = Frame::ReadMask;
- }
- if (frame.state == Frame::ReadMask) {
- if (bytesAvailable < 4) {
- return true;
- }
- socket->read(frame.mask, 4);
- bytesAvailable -= 4;
- frame.state = Frame::ReadData;
- frame.data.reserve(frame.length);
- }
- if (frame.state == Frame::ReadData && (bytesAvailable || !frame.length)) {
- frame.data.append(socket->read(qMin(frame.length - frame.data.size(), bytesAvailable)));
- if (frame.data.size() == frame.length) {
- frame.state = Frame::ReadStart;
- handleFrame(socket, frame);
- }
- }
- return true;
-}
-
-void QWebSocketServer::handleFrame(QTcpSocket* socket, Frame& frame)
-{
- unmask(frame.data, frame.mask);
-
- // fragmentation support - see http://tools.ietf.org/html/rfc6455#page-33
- if (!frame.fin) {
- if (frame.opcode != Frame::ContinuationFrame) {
- frame.initialOpcode = frame.opcode;
- }
- frame.fragments += frame.data;
- } else if (frame.fin && frame.opcode == Frame::ContinuationFrame) {
- frame.opcode = frame.initialOpcode;
- frame.data = frame.fragments + frame.data;
- } // otherwise if it's fin and a non-continuation frame its a single-frame message
-
- switch (frame.opcode) {
- case Frame::ContinuationFrame:
- // do nothing
- break;
- case Frame::Ping:
- socket->write(frameHeader(Frame::Pong, 0));
- break;
- case Frame::Pong:
- emit pongReceived();
- break;
- case Frame::ConnectionClose:
- ///TODO: handle?
- qWarning("Unhandled connection close frame");
- break;
- case Frame::BinaryFrame:
- emit binaryDataReceived(frame.data);
- break;
- case Frame::TextFrame:
- emit textDataReceived(QString::fromUtf8(frame.data));
- break;
- }
-
- if (frame.fin) {
- frame = Frame();
- }
-}
-
-bool QWebSocketServer::isValid(const HeaderData& header)
-{
- return !header.path.isEmpty() && !header.host.isEmpty() && !header.key.isEmpty()
- && header.hasUpgrade && header.hasConnection && header.hasVersion;
-}
-
-void QWebSocketServer::close(QTcpSocket* socket, const HeaderData& header)
-{
- if (header.wasUpgraded) {
- //TODO: implement this properly - see http://tools.ietf.org/html/rfc6455#page-36
- socket->write(frameHeader(Frame::Frame::ConnectionClose, 0));
- } else {
- socket->write(httpBadRequest);
- }
- socket->close();
-}
-
-void QWebSocketServer::upgrade(QTcpSocket* socket, HeaderData& header)
-{
- socket->write(headerSwitchProtocols);
- socket->write(headerEOL);
-
- socket->write(headerUpgrade);
- socket->write(headerEOL);
-
- socket->write(headerConnection);
- socket->write(headerEOL);
-
- socket->write(headerSecAccept);
- socket->write(QCryptographicHash::hash( header.key + headerMagicKey, QCryptographicHash::Sha1 ).toBase64());
- socket->write(headerEOL);
-
- if (!header.protocol.isEmpty()) {
- socket->write(headerSecProtocol);
- socket->write(header.protocol);
- socket->write(headerEOL);
- }
-
- socket->write(headerEOL);
-
- header.wasUpgraded = true;
-}
-
-void QWebSocketServer::sendMessage(const QByteArray& message) const
-{
- sendFrame(Frame::TextFrame, message);
-}
-
-void QWebSocketServer::sendFrame(Frame::Opcode opcode, const QByteArray& data) const
-{
- if (m_connections.isEmpty()) {
- return;
- }
- const QByteArray& header = frameHeader(opcode, data.size());
- QHash< QTcpSocket*, Connection >::const_iterator it = m_connections.constBegin();
- while (it != m_connections.constEnd()) {
- if (it.value().header.wasUpgraded) {
- it.key()->write(header);
- it.key()->write(data);
- }
- ++it;
- }
-}
-
-// see: http://tools.ietf.org/html/rfc6455#page-28
-QByteArray QWebSocketServer::frameHeader(QWebSocketServer::Frame::Opcode opcode, const int dataSize) const
-{
- // we only support single frames for now
- Q_ASSERT(opcode != Frame::ContinuationFrame);
-
- QByteArray header;
- header.reserve(4);
- header.append(FIN_BIT | opcode);
- if (dataSize < EXTENDED_PAYLOAD) {
- header.append(static_cast<char>(dataSize));
- } else if (dataSize < std::numeric_limits<quint16>::max()) {
- header.append(EXTENDED_PAYLOAD);
- appendBytes(header, qToBigEndian<quint16>(dataSize));
- } else {
- header.append(EXTENDED_LONG_PAYLOAD);
- appendBytes(header, qToBigEndian<quint64>(dataSize));
- }
- return header;
-}
-
-void QWebSocketServer::ping() const
-{
- sendFrame(Frame::Ping, QByteArray());
-}
-
-QT_END_NAMESPACE
diff --git a/src/webchannel/qwebsocketserver_p.h b/src/webchannel/qwebsocketserver_p.h
deleted file mode 100644
index 34c9ec2..0000000
--- a/src/webchannel/qwebsocketserver_p.h
+++ /dev/null
@@ -1,163 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com>
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtWebChannel module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWEBSOCKET_H
-#define QWEBSOCKET_H
-
-#include <QObject>
-#include <QHostAddress>
-
-QT_BEGIN_NAMESPACE
-
-class QTcpServer;
-class QTcpSocket;
-
-class QWebSocketServer : public QObject
-{
- Q_OBJECT
-
-public:
- explicit QWebSocketServer(QObject* parent = 0);
- virtual ~QWebSocketServer();
-
- bool listen(const QHostAddress& address = QHostAddress::LocalHost, quint16 port = 0);
- void close();
-
- QHostAddress address() const;
- quint16 port() const;
-
- QString errorString() const;
-
-signals:
- void opened();
- void error(QAbstractSocket::SocketError);
- void textDataReceived(const QString& data);
- void binaryDataReceived(const QByteArray& data);
- void pongReceived();
-
-public slots:
- void sendMessage(const QByteArray& message) const;
- void ping() const;
-
-private slots:
- void newConnection();
- void readSocketData();
- void disconnected();
-
-protected:
- struct HeaderData
- {
- HeaderData()
- : hasVersion(false)
- , hasUpgrade(false)
- , hasConnection(false)
- , wasUpgraded(false)
- {
- }
- QByteArray path;
- QByteArray host;
- QByteArray origin;
- QByteArray key;
- QByteArray protocol;
- QVector<QByteArray> otherHeaders;
- // no bitmap here - we only have few of these objects
- bool hasVersion;
- bool hasUpgrade;
- bool hasConnection;
- bool wasUpgraded;
- };
- virtual bool isValid(const HeaderData& connection);
-
-private:
- struct Frame
- {
- enum State {
- ReadStart,
- ReadExtendedPayload,
- ReadExtendedLongPayload,
- ReadMask,
- ReadData,
- Finished
- };
- enum Opcode {
- ContinuationFrame = 0x0,
- TextFrame = 0x1,
- BinaryFrame = 0x2,
- ConnectionClose = 0x8,
- Ping = 0x9,
- Pong = 0xA
- };
- // no bitmap here - we only have a few of these objects
- State state;
- Opcode opcode;
- bool fin;
- bool masked;
- ///NOTE: standard says unsigned 64bit integer but QByteArray only supports 'int' size
- int length;
- char mask[4];
- QByteArray data;
- // fragmentation support
- Opcode initialOpcode;
- QByteArray fragments;
- };
- struct Connection
- {
- HeaderData header;
- Frame currentFrame;
- };
-
- void readHeaderData(QTcpSocket* socket, HeaderData& header);
- void close(QTcpSocket* socket, const HeaderData& header);
- void upgrade(QTcpSocket* socket, HeaderData& header);
- bool readFrameData(QTcpSocket* socket, Frame& frame);
- void handleFrame(QTcpSocket* socket, Frame& frame);
-
- void sendFrame(Frame::Opcode opcode, const QByteArray& data) const;
- void sendFrame(QTcpSocket* socket, Frame::Opcode opcode, const QByteArray& data) const;
- QByteArray frameHeader(Frame::Opcode opcode, const int dataSize) const;
-
- QTcpServer* m_server;
- QHash<QTcpSocket*, Connection> m_connections;
-};
-
-QT_END_NAMESPACE
-
-#endif // QWEBSOCKET_H
diff --git a/src/webchannel/qwebsockettransport.cpp b/src/webchannel/qwebsockettransport.cpp
index be991a8..9c9ef97 100644
--- a/src/webchannel/qwebsockettransport.cpp
+++ b/src/webchannel/qwebsockettransport.cpp
@@ -67,12 +67,12 @@ QWebSocketTransport::~QWebSocketTransport()
void QWebSocketTransport::sendMessage(const QByteArray &message) const
{
- d->sendMessage(message);
+ d->sendMessage(QString::fromUtf8(message));
}
void QWebSocketTransport::sendMessage(const QString &message) const
{
- d->sendMessage(message.toUtf8());
+ d->sendMessage(message);
}
void QWebSocketTransport::setMessageHandler(QWebChannelMessageHandlerInterface *handler)
diff --git a/src/webchannel/webchannel.pro b/src/webchannel/webchannel.pro
index 279eb37..f04e3eb 100644
--- a/src/webchannel/webchannel.pro
+++ b/src/webchannel/webchannel.pro
@@ -1,5 +1,5 @@
TARGET = QtWebChannel
-QT = core network
+QT = core network websockets
CONFIG += warn_on strict_flags
load(qt_module)
@@ -18,7 +18,6 @@ PUBLIC_HEADERS += \
PRIVATE_HEADERS += \
qwebchannel_p.h \
qmetaobjectpublisher_p.h \
- qwebsocketserver_p.h \
qwebchannelsocket_p.h \
variantargument_p.h \
signalhandler_p.h
@@ -26,7 +25,6 @@ PRIVATE_HEADERS += \
SOURCES += \
qwebchannel.cpp \
qmetaobjectpublisher.cpp \
- qwebsocketserver.cpp \
qwebchannelsocket.cpp \
qwebsockettransport.cpp
diff --git a/sync.profile b/sync.profile
index 36c410b..da8a563 100644
--- a/sync.profile
+++ b/sync.profile
@@ -11,9 +11,10 @@
# - an empty string to use the same branch under test (dependencies will become "refs/heads/master" if we are in the master branch)
#
%dependencies = (
- "qtbase" => "",
+ "qtbase" => "stable",
+ "qtwebsockets" => "dev",
# optional dependencies:
- "qtdeclarative" => "",
+ "qtdeclarative" => "stable",
# TODO: disabled for now as it breaks CI builds on OSX
# requires changes to qtqa scripts as discussed with sifalt, sahumada, tronical
# "qtwebkit" => "",