Cleaned up code
authorKurt Pattyn <kurt.pattyn@barco.com>
Sat, 3 Aug 2013 16:49:19 +0000 (18:49 +0200)
committerKurt Pattyn <kurt.pattyn@barco.com>
Sat, 3 Aug 2013 16:49:19 +0000 (18:49 +0200)
source/dataprocessor.cpp
source/websocket.cpp
source/websocket.h
source/websocketserver.cpp

index 4c212c5..ff5c4a4 100644 (file)
 class Fragment
 {
 public:
-    Fragment();
-    Fragment(const Fragment &other);
+       Fragment();
+       Fragment(const Fragment &other);
 
-    const Fragment &operator =(const Fragment &other);
+       const Fragment &operator =(const Fragment &other);
 
-    WebSocketProtocol::CloseCode getCloseCode() const;
-    QString getCloseReason() const;
-    bool isFinalFragment() const;
-    bool isControlFragment() const;
-    bool isDataFragment() const;
-    bool isContinuationFragment() const;
-    bool hasMask() const;
-    quint32 getMask() const;    //returns 0 if no mask
-    int getRsv1() const;
-    int getRsv2() const;
-    int getRsv3() const;
-    WebSocketProtocol::OpCode getOpCode() const;
-    QByteArray getPayload() const;
+       WebSocketProtocol::CloseCode getCloseCode() const;
+       QString getCloseReason() const;
+       bool isFinalFragment() const;
+       bool isControlFragment() const;
+       bool isDataFragment() const;
+       bool isContinuationFragment() const;
+       bool hasMask() const;
+       quint32 getMask() const;    //returns 0 if no mask
+       int getRsv1() const;
+       int getRsv2() const;
+       int getRsv3() const;
+       WebSocketProtocol::OpCode getOpCode() const;
+       QByteArray getPayload() const;
 
-    void clear();       //resets all member variables, and invalidates the object
+       void clear();       //resets all member variables, and invalidates the object
 
-    bool isValid() const;
+       bool isValid() const;
 
-    static Fragment readFragment(QTcpSocket *pSocket);
+       static Fragment readFragment(QTcpSocket *pSocket);
 
 private:
-    //header
-    WebSocketProtocol::CloseCode m_closeCode;
-    QString m_closeReason;
-    bool m_isFinalFragment;
-    quint32 m_mask;
-    int m_rsv1; //reserved field 1
-    int m_rsv2; //reserved field 2
-    int m_rsv3; //reserved field 3
-    WebSocketProtocol::OpCode m_opCode;
-
-    quint8 m_length;        //length field as read from the header; this is 1 byte, which when 126 or 127, indicates a large payload
-    QByteArray m_payload;
-
-    bool m_isValid;
-
-    enum ProcessingState
-    {
-        PS_READ_HEADER,
-        PS_READ_PAYLOAD_LENGTH,
-        PS_READ_BIG_PAYLOAD_LENGTH,
-        PS_READ_MASK,
-        PS_READ_PAYLOAD,
-        PS_DISPATCH_RESULT,
-        PS_WAIT_FOR_MORE_DATA
-    };
-
-    void setError(WebSocketProtocol::CloseCode code, QString closeReason);
-    bool checkValidity();
+       //header
+       WebSocketProtocol::CloseCode m_closeCode;
+       QString m_closeReason;
+       bool m_isFinalFragment;
+       quint32 m_mask;
+       int m_rsv1; //reserved field 1
+       int m_rsv2; //reserved field 2
+       int m_rsv3; //reserved field 3
+       WebSocketProtocol::OpCode m_opCode;
+
+       quint8 m_length;        //length field as read from the header; this is 1 byte, which when 126 or 127, indicates a large payload
+       QByteArray m_payload;
+
+       bool m_isValid;
+
+       enum ProcessingState
+       {
+               PS_READ_HEADER,
+               PS_READ_PAYLOAD_LENGTH,
+               PS_READ_BIG_PAYLOAD_LENGTH,
+               PS_READ_MASK,
+               PS_READ_PAYLOAD,
+               PS_DISPATCH_RESULT,
+               PS_WAIT_FOR_MORE_DATA
+       };
+
+       void setError(WebSocketProtocol::CloseCode code, QString closeReason);
+       bool checkValidity();
 };
 
 Fragment::Fragment() :
-    m_closeCode(WebSocketProtocol::CC_NORMAL),
-    m_closeReason(),
-    m_isFinalFragment(true),
-    m_mask(0),
-    m_rsv1(0),
-    m_rsv2(0),
-    m_rsv3(0),
-    m_opCode(WebSocketProtocol::OC_RESERVED_V),
-    m_length(0),
-    m_payload(),
-    m_isValid(false)
+       m_closeCode(WebSocketProtocol::CC_NORMAL),
+       m_closeReason(),
+       m_isFinalFragment(true),
+       m_mask(0),
+       m_rsv1(0),
+       m_rsv2(0),
+       m_rsv3(0),
+       m_opCode(WebSocketProtocol::OC_RESERVED_V),
+       m_length(0),
+       m_payload(),
+       m_isValid(false)
 {
 }
 
 Fragment::Fragment(const Fragment &other) :
-    m_closeCode(other.m_closeCode),
-    m_closeReason(other.m_closeReason),
-    m_isFinalFragment(other.m_isFinalFragment),
-    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_isValid(other.m_isValid)
+       m_closeCode(other.m_closeCode),
+       m_closeReason(other.m_closeReason),
+       m_isFinalFragment(other.m_isFinalFragment),
+       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_isValid(other.m_isValid)
 {
 }
 
 const Fragment &Fragment::operator =(const Fragment &other)
 {
-    m_closeCode = other.m_closeCode;
-    m_closeReason = other.m_closeReason;
-    m_isFinalFragment = other.m_isFinalFragment;
-    m_mask = other.m_mask;
-    m_rsv1 = other.m_rsv1;
-    m_rsv2 = other.m_rsv2;
-    m_rsv3 = other.m_rsv2;
-    m_opCode = other.m_opCode;
-    m_length = other.m_length;
-    m_payload = other.m_payload;
-    m_isValid = other.m_isValid;
-
-    return *this;
+       m_closeCode = other.m_closeCode;
+       m_closeReason = other.m_closeReason;
+       m_isFinalFragment = other.m_isFinalFragment;
+       m_mask = other.m_mask;
+       m_rsv1 = other.m_rsv1;
+       m_rsv2 = other.m_rsv2;
+       m_rsv3 = other.m_rsv2;
+       m_opCode = other.m_opCode;
+       m_length = other.m_length;
+       m_payload = other.m_payload;
+       m_isValid = other.m_isValid;
+
+       return *this;
 }
 
 WebSocketProtocol::CloseCode Fragment::getCloseCode() const
 {
-    return m_closeCode;
+       return m_closeCode;
 }
 
 QString Fragment::getCloseReason() const
 {
-    return m_closeReason;
+       return m_closeReason;
 }
 
 bool Fragment::isFinalFragment() const
 {
-    return m_isFinalFragment;
+       return m_isFinalFragment;
 }
 
 bool Fragment::isControlFragment() const
 {
-    return (m_opCode & 0x08) == 0x08;
+       return (m_opCode & 0x08) == 0x08;
 }
 
 bool Fragment::isDataFragment() const
 {
-    return !isControlFragment();
+       return !isControlFragment();
 }
 
 bool Fragment::isContinuationFragment() const
 {
-    return isDataFragment() && (m_opCode == WebSocketProtocol::OC_CONTINUE);
+       return isDataFragment() && (m_opCode == WebSocketProtocol::OC_CONTINUE);
 }
 
 bool Fragment::hasMask() const
 {
-    return m_mask != 0;
+       return m_mask != 0;
 }
 
 quint32 Fragment::getMask() const
 {
-    return m_mask;
+       return m_mask;
 }
 
 int Fragment::getRsv1() const
 {
-    return m_rsv1;
+       return m_rsv1;
 }
 
 int Fragment::getRsv2() const
 {
-    return m_rsv2;
+       return m_rsv2;
 }
 
 int Fragment::getRsv3() const
 {
-    return m_rsv3;
+       return m_rsv3;
 }
 
 WebSocketProtocol::OpCode Fragment::getOpCode() const
 {
-    return m_opCode;
+       return m_opCode;
 }
 
 QByteArray Fragment::getPayload() const
 {
-    return m_payload;
+       return m_payload;
 }
 
 void Fragment::clear()
 {
-    m_closeCode = WebSocketProtocol::CC_NORMAL;
-    m_closeReason.clear();
-    m_isFinalFragment = true;
-    m_mask = 0;
-    m_rsv1 = 0;
-    m_rsv2 =0;
-    m_rsv3 = 0;
-    m_opCode = WebSocketProtocol::OC_RESERVED_V;
-    m_length = 0;
-    m_payload.clear();
-    m_isValid = false;
+       m_closeCode = WebSocketProtocol::CC_NORMAL;
+       m_closeReason.clear();
+       m_isFinalFragment = true;
+       m_mask = 0;
+       m_rsv1 = 0;
+       m_rsv2 =0;
+       m_rsv3 = 0;
+       m_opCode = WebSocketProtocol::OC_RESERVED_V;
+       m_length = 0;
+       m_payload.clear();
+       m_isValid = false;
 }
 
 bool Fragment::isValid() const
 {
-    return m_isValid;
+       return m_isValid;
 }
 
 #define WAIT_FOR_MORE_DATA(dataSizeInBytes)  { returnState = processingState; processingState = PS_WAIT_FOR_MORE_DATA; dataWaitSize = dataSizeInBytes; }
 
 Fragment Fragment::readFragment(QTcpSocket *pSocket)
 {
-    bool isDone = false;
-    qint64 bytesRead = 0;
-    Fragment fragment;
-    ProcessingState processingState = PS_READ_HEADER;
-    ProcessingState returnState = PS_READ_HEADER;
-    quint64 dataWaitSize = 0;
-    bool hasMask = false;
-    quint64 payloadLength = 0;
-
-    while (!isDone)
-    {
-        switch (processingState)
-        {
-            case PS_WAIT_FOR_MORE_DATA:
-            {
-                bool result = pSocket->waitForReadyRead(1000);
-                if (!result)                                      //timeout
-                {
-                    qDebug() << "Timeout" << dataWaitSize << "bytesAvail" << pSocket->bytesAvailable();
-                    fragment.setError(WebSocketProtocol::CC_GOING_AWAY, "Timeout when reading data from socket.");
-                    isDone = true;
-                }
-                else
-                {
-                    processingState = returnState;
-                }
-                break;
-            }
-            case PS_READ_HEADER:
-            {
-                if (pSocket->bytesAvailable() >= 2)
-                {
-                    //FIN, RSV1-3, Opcode
-                    char header[2] = {0};
-                    bytesRead = pSocket->read(header, 2);
-                    fragment.m_isFinalFragment = (header[0] & 0x80) != 0;
-                    fragment.m_rsv1 = (header[0] & 0x40);
-                    fragment.m_rsv2 = (header[0] & 0x20);
-                    fragment.m_rsv3 = (header[0] & 0x10);
-                    fragment.m_opCode = static_cast<WebSocketProtocol::OpCode>(header[0] & 0x0F);
-
-                    //Mask, PayloadLength
-                    hasMask = (header[1] & 0x80) != 0;
-                    fragment.m_length = (header[1] & 0x7F);
-
-                    switch (fragment.m_length)
-                    {
-                        case 126:
-                        {
-                            processingState = PS_READ_PAYLOAD_LENGTH;
-                            break;
-                        }
-                        case 127:
-                        {
-                            processingState = PS_READ_BIG_PAYLOAD_LENGTH;
-                            break;
-                        }
-                        default:
-                        {
-                            payloadLength = fragment.m_length;
-                            processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
-                            break;
-                        }
-                    }
-                    if (!fragment.checkValidity())
-                    {
-                        isDone = true;
-                    }
-                }
-                else
-                {
-                    WAIT_FOR_MORE_DATA(2);
-                }
-                break;
-            }
-
-            case PS_READ_PAYLOAD_LENGTH:
-            {
-                if (pSocket->bytesAvailable() >= 2)
-                {
-                    uchar length[2] = {0};
-                     //TODO: Handle return value
-                    bytesRead = pSocket->read(reinterpret_cast<char *>(length), 2);
-                    payloadLength = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(length));
-                    processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
-                }
-                else
-                {
-                    WAIT_FOR_MORE_DATA(2);
-                }
-                break;
-            }
-
-            case PS_READ_BIG_PAYLOAD_LENGTH:
-            {
-                if (pSocket->bytesAvailable() >= 8)
-                {
-                    uchar length[8] = {0};
-                    //TODO: Handle return value
-                    bytesRead = pSocket->read(reinterpret_cast<char *>(length), 8);
-                    //Most significant bit must be set to 0 as per http://tools.ietf.org/html/rfc6455#section-5.2
-                    //TODO: Do we check for that?
-                    payloadLength = qFromBigEndian<quint64>(length) & ~(1ULL << 63);
-                    processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
-                }
-                else
-                {
-                    WAIT_FOR_MORE_DATA(8);
-                }
-
-                break;
-            }
-
-            case PS_READ_MASK:
-            {
-                if (pSocket->bytesAvailable() >= 4)
-                {
-                    //TODO: Handle return value
-                    bytesRead = pSocket->read(reinterpret_cast<char *>(&fragment.m_mask), sizeof(fragment.m_mask));
-                    processingState = PS_READ_PAYLOAD;
-                }
-                else
-                {
-                    WAIT_FOR_MORE_DATA(4);
-                }
-                break;
-            }
-
-            case PS_READ_PAYLOAD:
-            {
-                // TODO: Handle large payloads
-                if (!payloadLength)
-                {
-                    processingState = PS_DISPATCH_RESULT;
-                }
-                else
-                {
-                    qint64 bytesAvailable = pSocket->bytesAvailable();
-                    if (bytesAvailable >= payloadLength)
-                    {
-                        //QByteArray payload = pSocket->read(bytesLeftToRead);
-                        fragment.m_payload = pSocket->read(payloadLength);
-                        if (hasMask)
-                        {
-                            WebSocketProtocol::mask(&fragment.m_payload, fragment.m_mask);
-                        }
-                        processingState = PS_DISPATCH_RESULT;
-                    }
-                    else
-                    {
-                        WAIT_FOR_MORE_DATA(payloadLength);
-                    }
-                }
-                break;
-            }
-
-            case PS_DISPATCH_RESULT:
-            {
-                processingState = PS_READ_HEADER;
-                isDone = true;
-                break;
-            }
-
-            default:
-            {
-                //should not come here
-                qDebug() << "DataProcessor::process: Found invalid state. This should not happen!";
-                fragment.clear();
-                isDone = true;
-                break;
-            }
-        }      //end switch
-    }
-
-    return fragment;
-}
-
-void Fragment::setError(WebSocketProtocol::CloseCode code, QString closeReason)
-{
-    clear();
-    m_closeCode = code;
-    m_closeReason = closeReason;
-    m_isValid = false;
-}
-
-bool Fragment::checkValidity()
-{
-    if (!isValid())
-    {
-        if (m_rsv1 || m_rsv2 || m_rsv3)
-        {
-            setError(WebSocketProtocol::CC_PROTOCOL_ERROR, "Rsv field is non-zero");
-        }
-        else if (WebSocketProtocol::isOpCodeReserved(m_opCode))
-        {
-            setError(WebSocketProtocol::CC_PROTOCOL_ERROR, "Used reserved opcode");
-        }
-        else if (isControlFragment())
-        {
-            if (m_length > 125)
-            {
-                setError(WebSocketProtocol::CC_PROTOCOL_ERROR, "Controle frame is larger than 125 bytes");
-            }
-            else if (!m_isFinalFragment)
-            {
-                setError(WebSocketProtocol::CC_PROTOCOL_ERROR, "Controle frames cannot be fragmented");
-            }
-            else
-            {
-                m_isValid = true;
-            }
-        }
-        else
-        {
-            m_isValid = true;
-        }
-    }
-    return m_isValid;
-}
-
-DataProcessor::DataProcessor(QObject *parent) :
-       QObject(parent),
-    m_processingState(PS_READ_HEADER),
-       m_isFinalFragment(false),
-    m_isFragmented(false),
-       m_opCode(WebSocketProtocol::OC_CLOSE),
-    m_isControlFrame(false),
-       m_hasMask(false),
-       m_mask(0),
-       m_frame(),
-       m_payloadLength(0)
-{
-}
-
-DataProcessor::~DataProcessor()
-{
-}
-
-#if 1
-
-void DataProcessor::process(QTcpSocket *pSocket)
-{
-    bool isDone = false;
-
-    while (!isDone)
-    {
-        Fragment fragment = Fragment::readFragment(pSocket);
-        if (fragment.isValid())
-        {
-            if (fragment.isControlFragment())
-            {
-                Q_EMIT frameReceived(fragment.getOpCode(), fragment.getPayload(), true);
-                isDone = true;  //exit the loop after a control frame, so we can get a chance to close the socket if necessary
-            }
-            else    //we have a dataframe
-            {
-                if (!m_isFragmented && fragment.isContinuationFragment())
-                {
-                    clear();
-                    Q_EMIT errorEncountered(WebSocketProtocol::CC_PROTOCOL_ERROR, "Received Continuation frame /*with FIN=true*/, while there is nothing to continue.");
-                    return;
-                }
-                if (m_isFragmented && fragment.isDataFragment() && !fragment.isContinuationFragment())
-                {
-                    clear();
-                    Q_EMIT errorEncountered(WebSocketProtocol::CC_PROTOCOL_ERROR, "All data frames after the initial data frame must have opcode 0");
-                    return;
-                }
-                if (!fragment.isContinuationFragment())
-                {
-                    m_opCode = fragment.getOpCode();
-                    m_isFragmented = !fragment.isFinalFragment();
-                }
-                m_frame.append(fragment.getPayload());
-                if (fragment.isFinalFragment())
-                {
-                    Q_EMIT frameReceived(m_opCode, m_frame, m_isFinalFragment);
-                    clear();
-                    isDone = true;
-                }
-            }
-        }
-        else
-        {
-            Q_EMIT errorEncountered(fragment.getCloseCode(), fragment.getCloseReason());
-            clear();
-            isDone = true;
-        }
-    }
-}
-#else
-void DataProcessor::process(QTcpSocket *pSocket)
-{
+       bool isDone = false;
        qint64 bytesRead = 0;
-    Q_UNUSED(bytesRead);       //TODO: to make gcc happy; in the future we will use the bytesRead to handle errors
-    bool isDone = false;
-    quint64 currentFrameLength = 0;
+       Fragment fragment;
+       ProcessingState processingState = PS_READ_HEADER;
+       ProcessingState returnState = PS_READ_HEADER;
+       quint64 dataWaitSize = 0;
+       bool hasMask = false;
+       quint64 payloadLength = 0;
 
        while (!isDone)
        {
-               switch (m_processingState)
+               switch (processingState)
                {
+                       case PS_WAIT_FOR_MORE_DATA:
+                       {
+                               bool result = pSocket->waitForReadyRead(1000);
+                               if (!result)                                      //timeout
+                               {
+                                       qDebug() << "Timeout" << dataWaitSize << "bytesAvail" << pSocket->bytesAvailable();
+                                       fragment.setError(WebSocketProtocol::CC_GOING_AWAY, "Timeout when reading data from socket.");
+                                       isDone = true;
+                               }
+                               else
+                               {
+                                       processingState = returnState;
+                               }
+                               break;
+                       }
                        case PS_READ_HEADER:
                        {
-                currentFrameLength = m_frame.size();
-                if (pSocket->bytesAvailable() >= 2)
+                               if (pSocket->bytesAvailable() >= 2)
                                {
                                        //FIN, RSV1-3, Opcode
-                                       char header[2];
+                                       char header[2] = {0};
                                        bytesRead = pSocket->read(header, 2);
-                    m_isFinalFragment = (header[0] & 0x80) != 0;
-                    int rsv1 = (header[0] & 0x40);
-                    int rsv2 = (header[0] & 0x20);
-                    int rsv3 = (header[0] & 0x10);
-                    if (rsv1 || rsv2 || rsv3)
-                    {
-                        clear();
-                        Q_EMIT errorEncountered(WebSocketProtocol::CC_PROTOCOL_ERROR, "Rsv field is non-zero");
-                        return;
-                    }
-                    WebSocketProtocol::OpCode opCode = static_cast<WebSocketProtocol::OpCode>(header[0] & 0x0F);
-                    m_isControlFrame = (opCode & 0x08) == 0x08;
-                    if (WebSocketProtocol::isOpCodeReserved(opCode))
-                    {
-                        clear();
-                        qDebug() << "Invalid opcode";
-                        Q_EMIT errorEncountered(WebSocketProtocol::CC_PROTOCOL_ERROR, "Used reserved opcode");
-                        return;
-                    }
-                    if ((opCode == WebSocketProtocol::OC_CONTINUE) && !m_isFragmented)
-                    {
-                        clear();
-                        qDebug() << "Continuation frame while not fragmented.";
-                        Q_EMIT errorEncountered(WebSocketProtocol::CC_PROTOCOL_ERROR, "Received Continuation frame /*with FIN=true*/, while there is nothing to continue.");
-                        return;
-                    }
-                    if (!m_isControlFrame && m_isFragmented && (opCode != WebSocketProtocol::OC_CONTINUE))
-                    {
-                        clear();
-                        qDebug() << "Continuation frame with invalid opcode.";
-                        Q_EMIT errorEncountered(WebSocketProtocol::CC_PROTOCOL_ERROR, "All data frames after the initial data frame must have opcode 0");
-                        return;
-                    }
-                    if (opCode != WebSocketProtocol::OC_CONTINUE)
-                    {
-                        m_opCode = opCode;
-                    }
-                    if (!m_isControlFrame && (opCode != WebSocketProtocol::OC_CONTINUE))
-                    {
-                        m_isFragmented = !m_isFinalFragment;
-                    }
+                                       fragment.m_isFinalFragment = (header[0] & 0x80) != 0;
+                                       fragment.m_rsv1 = (header[0] & 0x40);
+                                       fragment.m_rsv2 = (header[0] & 0x20);
+                                       fragment.m_rsv3 = (header[0] & 0x10);
+                                       fragment.m_opCode = static_cast<WebSocketProtocol::OpCode>(header[0] & 0x0F);
 
                                        //Mask, PayloadLength
-                                       m_hasMask = (header[1] & 0x80) != 0;
-                                       quint8 length = (header[1] & 0x7F);
-
-                    if (m_isControlFrame)
-                    {
-                        if (length > 125)
-                        {
-                            qDebug() << "Control frame larger than 125 bytes.";
-                            Q_EMIT errorEncountered(WebSocketProtocol::CC_PROTOCOL_ERROR, "Controle frame is larger than 125 bytes");
-                            return;
-                        }
-
-                        if (!m_isFinalFragment)
-                        {
-                            qDebug() << "Control frames cannot be fragmented.";
-                            Q_EMIT errorEncountered(WebSocketProtocol::CC_PROTOCOL_ERROR, "Controle frames cannot be fragmented");
-                            return;
-                        }
-                    }
-
-                                       switch (length)
+                                       hasMask = (header[1] & 0x80) != 0;
+                                       fragment.m_length = (header[1] & 0x7F);
+
+                                       switch (fragment.m_length)
                                        {
                                                case 126:
                                                {
-                                                       m_processingState = PS_READ_PAYLOAD_LENGTH;
+                                                       processingState = PS_READ_PAYLOAD_LENGTH;
                                                        break;
                                                }
                                                case 127:
                                                {
-                                                       m_processingState = PS_READ_BIG_PAYLOAD_LENGTH;
+                                                       processingState = PS_READ_BIG_PAYLOAD_LENGTH;
                                                        break;
                                                }
                                                default:
                                                {
-                                                       m_payloadLength = length;
-                                                       m_processingState = m_hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
+                                                       payloadLength = fragment.m_length;
+                                                       processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
                                                        break;
                                                }
                                        }
+                                       if (!fragment.checkValidity())
+                                       {
+                                               isDone = true;
+                                       }
                                }
                                else
                                {
-                                       isDone = true;
+                                       WAIT_FOR_MORE_DATA(2);
                                }
                                break;
                        }
 
                        case PS_READ_PAYLOAD_LENGTH:
                        {
-                if (pSocket->bytesAvailable() >= 2)
+                               if (pSocket->bytesAvailable() >= 2)
                                {
-                                       uchar length[2];
+                                       uchar length[2] = {0};
                                         //TODO: Handle return value
                                        bytesRead = pSocket->read(reinterpret_cast<char *>(length), 2);
-                                       m_payloadLength = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(length));
-                                       m_processingState = m_hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
+                                       payloadLength = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(length));
+                                       processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
                                }
                                else
                                {
-                                       isDone = true;
+                                       WAIT_FOR_MORE_DATA(2);
                                }
                                break;
                        }
 
                        case PS_READ_BIG_PAYLOAD_LENGTH:
                        {
-                if (pSocket->bytesAvailable() >= 8)
+                               if (pSocket->bytesAvailable() >= 8)
                                {
-                                       uchar length[8];
+                                       uchar length[8] = {0};
                                        //TODO: Handle return value
                                        bytesRead = pSocket->read(reinterpret_cast<char *>(length), 8);
                                        //Most significant bit must be set to 0 as per http://tools.ietf.org/html/rfc6455#section-5.2
                                        //TODO: Do we check for that?
-                                       m_payloadLength = qFromBigEndian<quint64>(length) & ~(1ULL << 63);
-                                       m_processingState = m_hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
+                                       payloadLength = qFromBigEndian<quint64>(length) & ~(1ULL << 63);
+                                       processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
                                }
                                else
                                {
-                                       isDone = true;
+                                       WAIT_FOR_MORE_DATA(8);
                                }
 
                                break;
@@ -637,65 +313,51 @@ void DataProcessor::process(QTcpSocket *pSocket)
 
                        case PS_READ_MASK:
                        {
-                if (pSocket->bytesAvailable() >= 4)
+                               if (pSocket->bytesAvailable() >= 4)
                                {
                                        //TODO: Handle return value
-                                       bytesRead = pSocket->read(reinterpret_cast<char *>(&m_mask), sizeof(m_mask));
-                                       m_processingState = PS_READ_PAYLOAD;
+                                       bytesRead = pSocket->read(reinterpret_cast<char *>(&fragment.m_mask), sizeof(fragment.m_mask));
+                                       processingState = PS_READ_PAYLOAD;
                                }
                                else
                                {
-                                       isDone = true;
+                                       WAIT_FOR_MORE_DATA(4);
                                }
                                break;
                        }
 
                        case PS_READ_PAYLOAD:
                        {
-                // TODO: Handle large payloads
-                //if (pSocket->bytesAvailable() >= static_cast<qint32>(m_payloadLength))
-                qint64 bytesAvailable = pSocket->bytesAvailable();
-                //qint64 bytesLeftToRead = qMin(m_payloadLength - (quint64)m_frame.size() - currentFrameLength, (quint64)bytesAvailable);
-                //qint64 bytesLeftToRead = qMin(m_payloadLength, (quint64)bytesAvailable);
-                //if (bytesLeftToRead > 0)
-                if (bytesAvailable >= m_payloadLength)
+                               // TODO: Handle large payloads
+                               if (!payloadLength)
+                               {
+                                       processingState = PS_DISPATCH_RESULT;
+                               }
+                               else
                                {
-                    //QByteArray payload = pSocket->read(bytesLeftToRead);
-                    QByteArray payload = pSocket->read(m_payloadLength);
-                                       if (m_hasMask)
+                                       quint64 bytesAvailable = static_cast<quint64>(pSocket->bytesAvailable());
+                                       if (bytesAvailable >= payloadLength)
                                        {
-                                               WebSocketProtocol::mask(&payload, m_mask);
+                                               //QByteArray payload = pSocket->read(bytesLeftToRead);
+                                               fragment.m_payload = pSocket->read(payloadLength);
+                                               if (hasMask)
+                                               {
+                                                       WebSocketProtocol::mask(&fragment.m_payload, fragment.m_mask);
+                                               }
+                                               processingState = PS_DISPATCH_RESULT;
+                                       }
+                                       else
+                                       {
+                                               WAIT_FOR_MORE_DATA(payloadLength);
                                        }
-                                       m_frame.append(payload);
-                }
-                else if (m_payloadLength > 0)
-                {
-                    //qDebug() <<  "Waiting for ready read";
-                    pSocket->waitForReadyRead(1000);
-                    //qDebug() <<  "Waited for ready read" << m_frame.size();
-                    //isDone = true;  //wait for more to be read
-                    break;
-                }
-                if (m_frame.size() == (m_payloadLength + currentFrameLength))
-                {
-                    m_processingState = m_isFinalFragment ? PS_DISPATCH_RESULT : PS_READ_HEADER;
-                }
-                else
-                               {
-                    isDone = true;  //more to read
                                }
-                /*if ((m_frame.size() % (64 * 1000)) == 0)
-                {
-                    qDebug() << "framesize=" << m_frame.size() << pSocket->bytesAvailable();
-                }*/
                                break;
                        }
 
                        case PS_DISPATCH_RESULT:
                        {
-                Q_EMIT frameReceived(m_opCode, m_frame, m_isFinalFragment);
-                               m_processingState = PS_READ_HEADER;
-                               m_frame.clear();
+                               processingState = PS_READ_HEADER;
+                               isDone = true;
                                break;
                        }
 
@@ -703,18 +365,133 @@ void DataProcessor::process(QTcpSocket *pSocket)
                        {
                                //should not come here
                                qDebug() << "DataProcessor::process: Found invalid state. This should not happen!";
+                               fragment.clear();
                                isDone = true;
                                break;
                        }
                }       //end switch
-       }       //end while
+       }
+
+       return fragment;
+}
+
+void Fragment::setError(WebSocketProtocol::CloseCode code, QString closeReason)
+{
+       clear();
+       m_closeCode = code;
+       m_closeReason = closeReason;
+       m_isValid = false;
+}
+
+bool Fragment::checkValidity()
+{
+       if (!isValid())
+       {
+               if (m_rsv1 || m_rsv2 || m_rsv3)
+               {
+                       setError(WebSocketProtocol::CC_PROTOCOL_ERROR, "Rsv field is non-zero");
+               }
+               else if (WebSocketProtocol::isOpCodeReserved(m_opCode))
+               {
+                       setError(WebSocketProtocol::CC_PROTOCOL_ERROR, "Used reserved opcode");
+               }
+               else if (isControlFragment())
+               {
+                       if (m_length > 125)
+                       {
+                               setError(WebSocketProtocol::CC_PROTOCOL_ERROR, "Controle frame is larger than 125 bytes");
+                       }
+                       else if (!m_isFinalFragment)
+                       {
+                               setError(WebSocketProtocol::CC_PROTOCOL_ERROR, "Controle frames cannot be fragmented");
+                       }
+                       else
+                       {
+                               m_isValid = true;
+                       }
+               }
+               else
+               {
+                       m_isValid = true;
+               }
+       }
+       return m_isValid;
+}
+
+DataProcessor::DataProcessor(QObject *parent) :
+       QObject(parent),
+       m_processingState(PS_READ_HEADER),
+       m_isFinalFragment(false),
+       m_isFragmented(false),
+       m_opCode(WebSocketProtocol::OC_CLOSE),
+       m_isControlFrame(false),
+       m_hasMask(false),
+       m_mask(0),
+       m_frame(),
+       m_payloadLength(0)
+{
+}
+
+DataProcessor::~DataProcessor()
+{
 }
-#endif
+
+void DataProcessor::process(QTcpSocket *pSocket)
+{
+       bool isDone = false;
+
+       while (!isDone)
+       {
+               Fragment fragment = Fragment::readFragment(pSocket);
+               if (fragment.isValid())
+               {
+                       if (fragment.isControlFragment())
+                       {
+                               Q_EMIT frameReceived(fragment.getOpCode(), fragment.getPayload(), true);
+                               isDone = true;  //exit the loop after a control frame, so we can get a chance to close the socket if necessary
+                       }
+                       else    //we have a dataframe
+                       {
+                               if (!m_isFragmented && fragment.isContinuationFragment())
+                               {
+                                       clear();
+                                       Q_EMIT errorEncountered(WebSocketProtocol::CC_PROTOCOL_ERROR, "Received Continuation frame /*with FIN=true*/, while there is nothing to continue.");
+                                       return;
+                               }
+                               if (m_isFragmented && fragment.isDataFragment() && !fragment.isContinuationFragment())
+                               {
+                                       clear();
+                                       Q_EMIT errorEncountered(WebSocketProtocol::CC_PROTOCOL_ERROR, "All data frames after the initial data frame must have opcode 0");
+                                       return;
+                               }
+                               if (!fragment.isContinuationFragment())
+                               {
+                                       m_opCode = fragment.getOpCode();
+                                       m_isFragmented = !fragment.isFinalFragment();
+                               }
+                               m_frame.append(fragment.getPayload());
+                               if (fragment.isFinalFragment())
+                               {
+                                       Q_EMIT frameReceived(m_opCode, m_frame, m_isFinalFragment);
+                                       clear();
+                                       isDone = true;
+                               }
+                       }
+               }
+               else
+               {
+                       Q_EMIT errorEncountered(fragment.getCloseCode(), fragment.getCloseReason());
+                       clear();
+                       isDone = true;
+               }
+       }
+}
+
 void DataProcessor::clear()
 {
        m_processingState = PS_READ_HEADER;
        m_isFinalFragment = false;
-    m_isFragmented = false;
+       m_isFragmented = false;
        m_opCode = WebSocketProtocol::OC_CLOSE;
        m_hasMask = false;
        m_mask = 0;
index 3e3f7bc..f467544 100644 (file)
@@ -3,7 +3,6 @@
 #include "handshakeresponse.h"
 #include <QUrl>
 #include <QTcpSocket>
-#include <QSharedData>
 #include <QByteArray>
 #include <QtEndian>
 #include <QCryptographicHash>
@@ -118,50 +117,50 @@ WebSocket *WebSocket::upgradeFrom(QTcpSocket *pTcpSocket,
 
 void WebSocket::close(WebSocketProtocol::CloseCode closeCode, QString reason)
 {
-    if (!m_isClosingHandshakeSent)
+       if (!m_isClosingHandshakeSent)
        {
-        quint32 maskingKey = 0;
-        if (m_mustMask)
-        {
-            maskingKey = generateMaskingKey();
-        }
-        quint16 code = qToBigEndian<quint16>(closeCode);
-        QByteArray payload;
-        payload.append(static_cast<const char *>(static_cast<const void *>(&code)), 2);
-        if (!reason.isEmpty())
+               quint32 maskingKey = 0;
+               if (m_mustMask)
+               {
+                       maskingKey = generateMaskingKey();
+               }
+               quint16 code = qToBigEndian<quint16>(closeCode);
+               QByteArray payload;
+               payload.append(static_cast<const char *>(static_cast<const void *>(&code)), 2);
+               if (!reason.isEmpty())
+               {
+                       payload.append(reason.toUtf8());
+               }
+               if (m_mustMask)
                {
-            payload.append(reason.toUtf8());
+                       WebSocketProtocol::mask(payload.data(), payload.size(), maskingKey);
                }
-        if (m_mustMask)
-        {
-            WebSocketProtocol::mask(payload.data(), payload.size(), maskingKey);
-        }
-        QByteArray frame = getFrameHeader(WebSocketProtocol::OC_CLOSE, payload.size(), maskingKey, true);
-        frame.append(payload);
-        m_pSocket->write(frame);
+               QByteArray frame = getFrameHeader(WebSocketProtocol::OC_CLOSE, payload.size(), maskingKey, true);
+               frame.append(payload);
+               m_pSocket->write(frame);
 
                m_isClosingHandshakeSent = true;
 
-        //qDebug() << "Sent closing handshake";
+               //qDebug() << "Sent closing handshake";
 
                setSocketState(QAbstractSocket::ClosingState);
-        //Q_EMIT aboutToClose();
+               //Q_EMIT aboutToClose();
        }
-    //if (m_isClosingHandshakeSent && m_isClosingHandshakeReceived)
+       //if (m_isClosingHandshakeSent && m_isClosingHandshakeReceived)
        {
-        //qDebug() << "Closing tcp socket";
+               //qDebug() << "Closing tcp socket";
                setSocketState(QAbstractSocket::UnconnectedState);
-        m_pSocket->flush();
+               m_pSocket->flush();
                m_pSocket->close();
-        Q_EMIT disconnected();
-    }
+               Q_EMIT disconnected();
+       }
 }
 
 void WebSocket::open(const QUrl &url, bool mask)
 {
        m_dataProcessor.clear();
-    m_isClosingHandshakeReceived = false;
-    m_isClosingHandshakeSent = false;
+       m_isClosingHandshakeReceived = false;
+       m_isClosingHandshakeSent = false;
 
        setRequestUrl(url);
        //resourcename cannot contain the scheme, host and port for socket.io
@@ -239,7 +238,7 @@ void WebSocket::makeConnections(const QTcpSocket *pTcpSocket)
        connect(pTcpSocket, SIGNAL(readyRead()), this, SLOT(processData()));
 
        connect(&m_dataProcessor, SIGNAL(frameReceived(WebSocketProtocol::OpCode, QByteArray, bool)), this, SLOT(processFrame(WebSocketProtocol::OpCode, QByteArray, bool)));
-    connect(&m_dataProcessor, SIGNAL(errorEncountered(WebSocketProtocol::CloseCode,QString)), this, SLOT(close(WebSocketProtocol::CloseCode,QString)));
+       connect(&m_dataProcessor, SIGNAL(errorEncountered(WebSocketProtocol::CloseCode,QString)), this, SLOT(close(WebSocketProtocol::CloseCode,QString)));
 }
 
 void WebSocket::releaseConnections(const QTcpSocket *pTcpSocket)
@@ -344,23 +343,23 @@ qint64 WebSocket::doWriteFrames(const QByteArray &data, bool isBinary)
        const WebSocketProtocol::OpCode firstOpCode = isBinary ? WebSocketProtocol::OC_BINARY : WebSocketProtocol::OC_TEXT;
 
        int numFrames = data.size() / MAX_FRAME_SIZE_IN_BYTES;
-    QByteArray tmpData(data);
-    tmpData.detach();
-    char *payload = tmpData.data();
-    quint64 sizeLeft = static_cast<quint64>(data.size()) % MAX_FRAME_SIZE_IN_BYTES;
+       QByteArray tmpData(data);
+       tmpData.detach();
+       char *payload = tmpData.data();
+       quint64 sizeLeft = static_cast<quint64>(data.size()) % MAX_FRAME_SIZE_IN_BYTES;
        if (sizeLeft)
        {
                ++numFrames;
        }
-    if (numFrames == 0)     //catch the case where the payload is zero bytes; in that case, we still need to send a frame
-    {
-        //qDebug() << "No data to send";
-        numFrames = 1;
-    }
+       if (numFrames == 0)     //catch the case where the payload is zero bytes; in that case, we still need to send a frame
+       {
+               //qDebug() << "No data to send";
+               numFrames = 1;
+       }
        quint64 currentPosition = 0;
        qint64 bytesWritten = 0;
-    qint64 payloadWritten = 0;
-    quint64 bytesLeft = data.size();
+       qint64 payloadWritten = 0;
+       quint64 bytesLeft = data.size();
 
        for (int i = 0; i < numFrames; ++i)
        {
@@ -373,44 +372,44 @@ qint64 WebSocket::doWriteFrames(const QByteArray &data, bool isBinary)
                bool isLastFrame = (i == (numFrames - 1));
                bool isFirstFrame = (i == 0);
 
-        //quint64 size = isLastFrame ? sizeLeft : MAX_FRAME_SIZE_IN_BYTES;
-        quint64 size = qMin(bytesLeft, MAX_FRAME_SIZE_IN_BYTES);
+               //quint64 size = isLastFrame ? sizeLeft : MAX_FRAME_SIZE_IN_BYTES;
+               quint64 size = qMin(bytesLeft, MAX_FRAME_SIZE_IN_BYTES);
                WebSocketProtocol::OpCode opcode = isFirstFrame ? firstOpCode : WebSocketProtocol::OC_CONTINUE;
 
                //write header
                bytesWritten += m_pSocket->write(getFrameHeader(opcode, size, maskingKey, isLastFrame));
 
                //write payload
-        if (size > 0)
-        {
-            char *currentData = payload + currentPosition;
-            if (m_mustMask)
-            {
-                //WARNING: currentData is written over
-                WebSocketProtocol::mask(currentData, size, maskingKey);
-            }
-            qint64 written = m_pSocket->write(currentData, static_cast<qint64>(size));
-            if (written > 0)
-            {
-                bytesWritten += written;
-                payloadWritten += written;
-            }
-            else
-            {
-                qDebug() << "WebSocket::doWriteFrames: Error writing bytes to socket:" << m_pSocket->errorString();
-                m_pSocket->flush();
-                break;
-            }
-        }
+               if (size > 0)
+               {
+                       char *currentData = payload + currentPosition;
+                       if (m_mustMask)
+                       {
+                               //WARNING: currentData is written over
+                               WebSocketProtocol::mask(currentData, size, maskingKey);
+                       }
+                       qint64 written = m_pSocket->write(currentData, static_cast<qint64>(size));
+                       if (written > 0)
+                       {
+                               bytesWritten += written;
+                               payloadWritten += written;
+                       }
+                       else
+                       {
+                               qDebug() << "WebSocket::doWriteFrames: Error writing bytes to socket:" << m_pSocket->errorString();
+                               m_pSocket->flush();
+                               break;
+                       }
+               }
                currentPosition += size;
-        bytesLeft -= size;
+               bytesLeft -= size;
+       }
+       if (payloadWritten != data.size())
+       {
+               qDebug() << "Bytes written" << payloadWritten << "!=" << "data size:" << data.size();
        }
-    if (payloadWritten != data.size())
-    {
-        qDebug() << "Bytes written" << payloadWritten << "!=" << "data size:" << data.size();
-    }
-    //return bytesWritten;
-    return payloadWritten;
+       //return bytesWritten;
+       return payloadWritten;
 }
 
 quint32 WebSocket::generateRandomNumber() const
@@ -460,21 +459,21 @@ qint64 WebSocket::writeFrame(const QByteArray &frame)
 
 QString readLine(QTcpSocket *pSocket)
 {
-    QString line;
-    char c;
-    while (pSocket->getChar(&c))
-    {
-        if (c == '\r')
-        {
-            pSocket->getChar(&c);
-            break;
-        }
-        else
-        {
-            line.append(QChar(c));
-        }
-    }
-    return line;
+       QString line;
+       char c;
+       while (pSocket->getChar(&c))
+       {
+               if (c == '\r')
+               {
+                       pSocket->getChar(&c);
+                       break;
+               }
+               else
+               {
+                       line.append(QChar(c));
+               }
+       }
+       return line;
 }
 
 //called for a server handshake response
@@ -485,95 +484,95 @@ void WebSocket::processHandshake(QTcpSocket *pSocket)
                return;
        }
 
-    bool ok = false;
-    const QString regExpStatusLine("^(HTTP/1.1)\\s([0-9]+)\\s(.*)");
-    const QRegExp regExp(regExpStatusLine);
-    //QString statusLine = textStream.readLine();
-    QString statusLine = readLine(pSocket);
-    QString httpProtocol;
-    int httpStatusCode;
-    QString httpStatusMessage;
-    if (regExp.indexIn(statusLine) != -1)
-    {
-        QStringList tokens = regExp.capturedTexts();
-        tokens.removeFirst();  //remove the search string
-        if (tokens.length() == 3)
-        {
-            httpProtocol = tokens[0];
-            httpStatusCode = tokens[1].toInt();
-            httpStatusMessage = tokens[2].trimmed();
-            ok = true;
-        }
-    }
-    if (!ok)
-    {
-        qDebug() << "WebSocket::processHandshake: Invalid statusline in response:" << statusLine;
-    }
-    else
-    {
-        //QString headerLine = textStream.readLine();
-        QString headerLine = readLine(pSocket);
-        QMap<QString, QString> headers;
-        while (!headerLine.isEmpty())
-        {
-            QStringList headerField = headerLine.split(QString(": "), QString::SkipEmptyParts);
-            headers.insertMulti(headerField[0], headerField[1]);
-            headerLine = readLine(pSocket);
-        }
-
-        QString acceptKey = headers.value("Sec-WebSocket-Accept", "");
-        QString upgrade = headers.value("Upgrade", "");
-        QString connection = headers.value("Connection", "");
-        QString extensions = headers.value("Sec-WebSocket-Extensions", "");
-        QString protocol = headers.value("Sec-WebSocket-Protocol", "");
-        QString version = headers.value("Sec-WebSocket-Version", "");
-
-        if (httpStatusCode == 101)     //HTTP/1.1 101 Switching Protocols
-        {
-            //do not check the httpStatusText right now
-            ok = !(acceptKey.isEmpty() ||
-                   (httpProtocol.toLower() != "http/1.1") ||
-                   (upgrade.toLower() != "websocket") ||
-                   (connection.toLower() != "upgrade"));
-            if (ok)
-            {
-                QString accept = calculateAcceptKey(m_key);
-                ok = (accept == acceptKey);
-                if (!ok)
-                {
-                    qDebug() << "WebSocket::processHandshake: Accept-Key received from server" << qPrintable(acceptKey) << "does not match the client key" << qPrintable(accept);
-                }
-            }
-            else
-            {
-                qDebug() << "WebSocket::processHandshake: Invalid statusline in response:" << statusLine;
-            }
-        }
-        else if (httpStatusCode == 400)        //HTTP/1.1 400 Bad Request
-        {
-            if (!version.isEmpty())
-            {
-                QStringList versions = version.split(", ", QString::SkipEmptyParts);
-                if (!versions.contains("13"))
-                {
-                    //if needed to switch protocols, then we are finished here
-                    //because we cannot handle other protocols than the RFC one (v13)
-                    qDebug() << "WebSocket::processHandshake: Server requests a version that we don't support:" << versions;
-                    ok = false;
-                }
-                else
-                {
-                    //we tried v13, but something different went wrong
-                    qDebug() << "WebSocket::processHandshake: Unknown error condition encountered. Aborting connection.";
-                    ok = false;
-                }
-            }
-        }
-        else
-        {
-            qDebug() << "WebSocket::processHandshake: Unhandled http status code" << httpStatusCode;
-            ok = false;
-        }
+       bool ok = false;
+       const QString regExpStatusLine("^(HTTP/1.1)\\s([0-9]+)\\s(.*)");
+       const QRegExp regExp(regExpStatusLine);
+       //QString statusLine = textStream.readLine();
+       QString statusLine = readLine(pSocket);
+       QString httpProtocol;
+       int httpStatusCode;
+       QString httpStatusMessage;
+       if (regExp.indexIn(statusLine) != -1)
+       {
+               QStringList tokens = regExp.capturedTexts();
+               tokens.removeFirst();   //remove the search string
+               if (tokens.length() == 3)
+               {
+                       httpProtocol = tokens[0];
+                       httpStatusCode = tokens[1].toInt();
+                       httpStatusMessage = tokens[2].trimmed();
+                       ok = true;
+               }
+       }
+       if (!ok)
+       {
+               qDebug() << "WebSocket::processHandshake: Invalid statusline in response:" << statusLine;
+       }
+       else
+       {
+               //QString headerLine = textStream.readLine();
+               QString headerLine = readLine(pSocket);
+               QMap<QString, QString> headers;
+               while (!headerLine.isEmpty())
+               {
+                       QStringList headerField = headerLine.split(QString(": "), QString::SkipEmptyParts);
+                       headers.insertMulti(headerField[0], headerField[1]);
+                       headerLine = readLine(pSocket);
+               }
+
+               QString acceptKey = headers.value("Sec-WebSocket-Accept", "");
+               QString upgrade = headers.value("Upgrade", "");
+               QString connection = headers.value("Connection", "");
+               QString extensions = headers.value("Sec-WebSocket-Extensions", "");
+               QString protocol = headers.value("Sec-WebSocket-Protocol", "");
+               QString version = headers.value("Sec-WebSocket-Version", "");
+
+               if (httpStatusCode == 101)      //HTTP/1.1 101 Switching Protocols
+               {
+                       //do not check the httpStatusText right now
+                       ok = !(acceptKey.isEmpty() ||
+                                  (httpProtocol.toLower() != "http/1.1") ||
+                                  (upgrade.toLower() != "websocket") ||
+                                  (connection.toLower() != "upgrade"));
+                       if (ok)
+                       {
+                               QString accept = calculateAcceptKey(m_key);
+                               ok = (accept == acceptKey);
+                               if (!ok)
+                               {
+                                       qDebug() << "WebSocket::processHandshake: Accept-Key received from server" << qPrintable(acceptKey) << "does not match the client key" << qPrintable(accept);
+                               }
+                       }
+                       else
+                       {
+                               qDebug() << "WebSocket::processHandshake: Invalid statusline in response:" << statusLine;
+                       }
+               }
+               else if (httpStatusCode == 400) //HTTP/1.1 400 Bad Request
+               {
+                       if (!version.isEmpty())
+                       {
+                               QStringList versions = version.split(", ", QString::SkipEmptyParts);
+                               if (!versions.contains("13"))
+                               {
+                                       //if needed to switch protocols, then we are finished here
+                                       //because we cannot handle other protocols than the RFC one (v13)
+                                       qDebug() << "WebSocket::processHandshake: Server requests a version that we don't support:" << versions;
+                                       ok = false;
+                               }
+                               else
+                               {
+                                       //we tried v13, but something different went wrong
+                                       qDebug() << "WebSocket::processHandshake: Unknown error condition encountered. Aborting connection.";
+                                       ok = false;
+                               }
+                       }
+               }
+               else
+               {
+                       qDebug() << "WebSocket::processHandshake: Unhandled http status code" << httpStatusCode;
+                       ok = false;
+               }
 
                if (!ok)
                {
@@ -591,7 +590,7 @@ void WebSocket::processHandshake(QTcpSocket *pSocket)
 void WebSocket::processStateChanged(QAbstractSocket::SocketState socketState)
 {
        QAbstractSocket::SocketState webSocketState = this->state();
-    //qDebug() << "State changed to:" << webSocketState << "tpcsocketstate:" << socketState;
+       //qDebug() << "State changed to:" << webSocketState << "tpcsocketstate:" << socketState;
        switch (socketState)
        {
                case QAbstractSocket::ConnectedState:
@@ -599,7 +598,7 @@ void WebSocket::processStateChanged(QAbstractSocket::SocketState socketState)
                        if (webSocketState == QAbstractSocket::ConnectingState)
                        {
                                m_key = generateKey();
-                QString handshake = createHandShakeRequest(m_resourceName, m_requestUrl.host() + ":" + QString::number(m_requestUrl.port(80)), getOrigin(), "", "", m_key);
+                               QString handshake = createHandShakeRequest(m_resourceName, m_requestUrl.host() + ":" + QString::number(m_requestUrl.port(80)), getOrigin(), "", "", m_key);
                                m_pSocket->write(handshake.toLatin1());
                        }
                        break;
@@ -608,9 +607,9 @@ void WebSocket::processStateChanged(QAbstractSocket::SocketState socketState)
                {
                        if (webSocketState == QAbstractSocket::ConnectedState)
                        {
-                close(WebSocketProtocol::CC_GOING_AWAY);
+                               close(WebSocketProtocol::CC_GOING_AWAY);
                                setSocketState(QAbstractSocket::ClosingState);
-                //Q_EMIT aboutToClose();
+                               //Q_EMIT aboutToClose();
                        }
                        break;
                }
@@ -650,52 +649,52 @@ void WebSocket::processStateChanged(QAbstractSocket::SocketState socketState)
 //if our socket was already upgraded, then we need to process websocket data
 void WebSocket::processData()
 {
-    while (m_pSocket->bytesAvailable())
-    {
-        if (state() == QAbstractSocket::ConnectingState)
-        {
-            processHandshake(m_pSocket);
-        }
-        else
-        {
-            m_dataProcessor.process(m_pSocket);
-        }
-    }
+       while (m_pSocket->bytesAvailable())
+       {
+               if (state() == QAbstractSocket::ConnectingState)
+               {
+                       processHandshake(m_pSocket);
+               }
+               else
+               {
+                       m_dataProcessor.process(m_pSocket);
+               }
+       }
 }
 
 void WebSocket::processFrame(WebSocketProtocol::OpCode opCode, QByteArray frame, bool isLastFrame)
 {
-    //qDebug() << "Processing frame:" << frame << "opcode:" << opCode;
-    switch (opCode)
+       //qDebug() << "Processing frame:" << frame << "opcode:" << opCode;
+       switch (opCode)
        {
                case WebSocketProtocol::OC_BINARY:
                {
-            Q_EMIT binaryFrameReceived(frame, isLastFrame);
+                       Q_EMIT binaryFrameReceived(frame, isLastFrame);
                        break;
                }
                case WebSocketProtocol::OC_TEXT:
-        {
-        //qDebug() << "Processing text frame:" << frame << "opcode:" << opCode;
-            Q_EMIT textFrameReceived(QString::fromLatin1(frame), isLastFrame);
+               {
+               //qDebug() << "Processing text frame:" << frame << "opcode:" << opCode;
+                       Q_EMIT textFrameReceived(QString::fromLatin1(frame), isLastFrame);
                        break;
                }
                case WebSocketProtocol::OC_PING:
                {
-        //qDebug() << "Processing ping frame:" << frame;
-            quint32 maskingKey = 0;
-            if (m_mustMask)
-            {
-                maskingKey = generateMaskingKey();
-            }
-            m_pSocket->write(getFrameHeader(WebSocketProtocol::OC_PONG, frame.size(), maskingKey, true));
-            if (frame.size() > 0)
-            {
-                if (m_mustMask)
-                {
-                    WebSocketProtocol::mask(&frame, maskingKey);
-                }
-                m_pSocket->write(frame);
-            }
+               //qDebug() << "Processing ping frame:" << frame;
+                       quint32 maskingKey = 0;
+                       if (m_mustMask)
+                       {
+                               maskingKey = generateMaskingKey();
+                       }
+                       m_pSocket->write(getFrameHeader(WebSocketProtocol::OC_PONG, frame.size(), maskingKey, true));
+                       if (frame.size() > 0)
+                       {
+                               if (m_mustMask)
+                               {
+                                       WebSocketProtocol::mask(&frame, maskingKey);
+                               }
+                               m_pSocket->write(frame);
+                       }
                        break;
                }
                case WebSocketProtocol::OC_PONG:
@@ -705,20 +704,20 @@ void WebSocket::processFrame(WebSocketProtocol::OpCode opCode, QByteArray frame,
                }
                case WebSocketProtocol::OC_CLOSE:
                {
-            quint16 closeCode = WebSocketProtocol::CC_NORMAL;
-            QString closeReason;
-            if (frame.size() > 0)   //close frame can have no close code nor reason
-            {
-                closeCode = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(frame.constData()));
-                closeReason = QString::fromUtf8(frame.remove(0, 2));
-                //qDebug() << "Received closing handshake with code" << closeCode;
-                if (!WebSocketProtocol::isCloseCodeValid(closeCode))
-                {
-                    closeCode = WebSocketProtocol::CC_PROTOCOL_ERROR;
-                }
-                m_isClosingHandshakeReceived = true;
-            }
-            close(static_cast<WebSocketProtocol::CloseCode>(closeCode), closeReason);
+                       quint16 closeCode = WebSocketProtocol::CC_NORMAL;
+                       QString closeReason;
+                       if (frame.size() > 0)   //close frame can have no close code nor reason
+                       {
+                               closeCode = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(frame.constData()));
+                               closeReason = QString::fromUtf8(frame.remove(0, 2));
+                               //qDebug() << "Received closing handshake with code" << closeCode;
+                               if (!WebSocketProtocol::isCloseCodeValid(closeCode))
+                               {
+                                       closeCode = WebSocketProtocol::CC_PROTOCOL_ERROR;
+                               }
+                               m_isClosingHandshakeReceived = true;
+                       }
+                       close(static_cast<WebSocketProtocol::CloseCode>(closeCode), closeReason);
                        break;
                }
                case WebSocketProtocol::OC_CONTINUE:
@@ -779,27 +778,27 @@ QString WebSocket::createHandShakeRequest(QString resourceName,
 
 QAbstractSocket::SocketState WebSocket::state() const
 {
-    return m_socketState;
+       return m_socketState;
 }
 
 bool WebSocket::waitForConnected(int msecs)
 {
-    bool retVal = false;
-    if (m_pSocket)
-    {
-        retVal = m_pSocket->waitForConnected(msecs);
-    }
-    return retVal;
+       bool retVal = false;
+       if (m_pSocket)
+       {
+               retVal = m_pSocket->waitForConnected(msecs);
+       }
+       return retVal;
 }
 
 bool WebSocket::waitForDisconnected(int msecs)
 {
-    bool retVal = true;
-    if (m_pSocket)
-    {
-        retVal = m_pSocket->waitForDisconnected(msecs);
-    }
-    return retVal;
+       bool retVal = true;
+       if (m_pSocket)
+       {
+               retVal = m_pSocket->waitForDisconnected(msecs);
+       }
+       return retVal;
 }
 
 void WebSocket::setSocketState(QAbstractSocket::SocketState state)
@@ -813,88 +812,88 @@ void WebSocket::setSocketState(QAbstractSocket::SocketState state)
 
 QHostAddress WebSocket::localAddress() const
 {
-    QHostAddress address;
-    if (m_pSocket)
-    {
-        address = m_pSocket->localAddress();
-    }
-    return address;
+       QHostAddress address;
+       if (m_pSocket)
+       {
+               address = m_pSocket->localAddress();
+       }
+       return address;
 }
 
 quint16 WebSocket::localPort() const
 {
-    quint16 port = 0;
-    if (m_pSocket)
-    {
-        port = m_pSocket->localPort();
-    }
-    return port;
+       quint16 port = 0;
+       if (m_pSocket)
+       {
+               port = m_pSocket->localPort();
+       }
+       return port;
 }
 
 QHostAddress WebSocket::peerAddress() const
 {
-    QHostAddress peer;
-    if (m_pSocket)
-    {
-        peer = m_pSocket->peerAddress();
-    }
-    return peer;
+       QHostAddress peer;
+       if (m_pSocket)
+       {
+               peer = m_pSocket->peerAddress();
+       }
+       return peer;
 }
 
 QString WebSocket::peerName() const
 {
-    QString name;
-    if (m_pSocket)
-    {
-        name = m_pSocket->peerName();
-    }
-    return name;
+       QString name;
+       if (m_pSocket)
+       {
+               name = m_pSocket->peerName();
+       }
+       return name;
 }
 
 quint16 WebSocket::peerPort() const
 {
-    quint16 port = 0;
-    if (m_pSocket)
-    {
-        port = m_pSocket->peerPort();
-    }
-    return port;
+       quint16 port = 0;
+       if (m_pSocket)
+       {
+               port = m_pSocket->peerPort();
+       }
+       return port;
 }
 
 QNetworkProxy WebSocket::proxy() const
 {
-    QNetworkProxy proxy;
-    if (m_pSocket)
-    {
-        proxy = m_pSocket->proxy();
-    }
-    return proxy;
+       QNetworkProxy proxy;
+       if (m_pSocket)
+       {
+               proxy = m_pSocket->proxy();
+       }
+       return proxy;
 }
 
 qint64 WebSocket::readBufferSize() const
 {
-    qint64 readBuffer = 0;
-    if (m_pSocket)
-    {
-        readBuffer = m_pSocket->readBufferSize();
-    }
-    return readBuffer;
+       qint64 readBuffer = 0;
+       if (m_pSocket)
+       {
+               readBuffer = m_pSocket->readBufferSize();
+       }
+       return readBuffer;
 }
 
 void WebSocket::setProxy(const QNetworkProxy &networkProxy)
 {
-    if (m_pSocket)
-    {
-        m_pSocket->setProxy(networkProxy);
-    }
+       if (m_pSocket)
+       {
+               m_pSocket->setProxy(networkProxy);
+       }
 }
 
 bool WebSocket::isValid()
 {
-    bool valid = false;
-    if (m_pSocket)
-    {
-        valid = m_pSocket->isValid();
-    }
-    return valid;
+       bool valid = false;
+       if (m_pSocket)
+       {
+               valid = m_pSocket->isValid();
+       }
+       return valid;
 }
index 469eef1..e6ae9ef 100644 (file)
 
 #include <QUrl>
 #include <QAbstractSocket>
-#include <QSharedDataPointer>
 #include <QHostAddress>
 #include "websocketprotocol.h"
 #include "dataprocessor.h"
-#include <QTcpSocket>
 #include <QNetworkProxy>
 #include <QTime>
 
 class HandshakeRequest;
 class HandshakeResponse;
+class QTcpSocket;
 
 class WebSocket:public QObject
 {
@@ -67,11 +66,11 @@ public:
        QString getExtension();
 
        //WebSocket functionality
-    /**
-     * @brief Sends a text message over the websocket
-     * @param message The message to send
-     * @return The number of bytes that have been sent
-     */
+       /**
+        * @brief Sends a text message over the websocket
+        * @param message The message to send
+        * @return The number of bytes that have been sent
+        */
        qint64 send(const char *message);
        qint64 send(const QString &message);    //send data as text
        qint64 send(const QByteArray &data);    //send data as binary
index 3140b54..30aea84 100644 (file)
@@ -1,9 +1,6 @@
 #include "websocketserver.h"
 #include <QTcpServer>
-#include <QTextStream>
-#include <QUrl>
 #include <QTcpSocket>
-#include <QDateTime>
 #include <QNetworkProxy>
 #include "websocketprotocol.h"
 #include "handshakerequest.h"