/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef HTTP2SRV_H #define HTTP2SRV_H #include #include #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE struct Http2Setting { Http2::Settings identifier; quint32 value = 0; Http2Setting(Http2::Settings ident, quint32 v) : identifier(ident), value(v) {} }; using Http2Settings = std::vector; class Http2Server : public QTcpServer { Q_OBJECT public: Http2Server(bool clearText, const Http2Settings &serverSettings, const Http2Settings &clientSettings); ~Http2Server(); // To be called before server started: void enablePushPromise(bool enabled, const QByteArray &path = QByteArray()); void setResponseBody(const QByteArray &body); void emulateGOAWAY(int timeout); // Invokables, since we can call them from the main thread, // but server (can) work on its own thread. Q_INVOKABLE void startServer(); Q_INVOKABLE void sendServerSettings(); Q_INVOKABLE void sendGOAWAY(quint32 streamID, quint32 error, quint32 lastStreamID); Q_INVOKABLE void sendRST_STREAM(quint32 streamID, quint32 error); Q_INVOKABLE void sendDATA(quint32 streamID, quint32 windowSize); Q_INVOKABLE void sendWINDOW_UPDATE(quint32 streamID, quint32 delta); Q_INVOKABLE void handleConnectionPreface(); Q_INVOKABLE void handleIncomingFrame(); Q_INVOKABLE void handleSETTINGS(); Q_INVOKABLE void handleDATA(); Q_INVOKABLE void handleWINDOW_UPDATE(); Q_INVOKABLE void sendResponse(quint32 streamID, bool emptyBody); private: void processRequest(); Q_SIGNALS: void serverStarted(quint16 port); // Error/success notifications: void clientPrefaceOK(); void clientPrefaceError(); void serverSettingsAcked(); void invalidFrame(); void invalidRequest(quint32 streamID); void decompressionFailed(quint32 streamID); void receivedRequest(quint32 streamID); void receivedData(quint32 streamID); void windowUpdate(quint32 streamID); private slots: void connectionEstablished(); void readReady(); private: void incomingConnection(qintptr socketDescriptor) Q_DECL_OVERRIDE; quint32 clientSetting(Http2::Settings identifier, quint32 defaultValue); QScopedPointer socket; // Connection preface: bool waitingClientPreface = false; bool waitingClientSettings = false; bool settingsSent = false; bool waitingClientAck = false; Http2Settings serverSettings; std::map expectedClientSettings; bool connectionError = false; Http2::FrameReader reader; Http2::Frame inboundFrame; Http2::FrameWriter writer; using FrameSequence = std::vector; FrameSequence continuedRequest; std::map streamWindows; HPack::Decoder decoder{HPack::FieldLookupTable::DefaultSize}; HPack::Encoder encoder{HPack::FieldLookupTable::DefaultSize, true}; using Http2Requests = std::map; Http2Requests activeRequests; // 'remote half-closed' streams to keep // track of streams with END_STREAM set: std::set closedStreams; // streamID + offset in response body to send. std::map suspendedStreams; // We potentially reset this once (see sendServerSettings) // and do not change later: quint32 sessionRecvWindowSize = Http2::defaultSessionWindowSize; // This changes in the range [0, sessionRecvWindowSize] // while handling DATA frames: quint32 sessionCurrRecvWindow = sessionRecvWindowSize; // This we potentially update only once (sendServerSettings). quint32 streamRecvWindowSize = Http2::defaultSessionWindowSize; QByteArray responseBody; bool clearTextHTTP2 = false; bool pushPromiseEnabled = false; quint32 lastPromisedStream = 0; QByteArray pushPath; bool testingGOAWAY = false; int goawayTimeout = 0; protected slots: void ignoreErrorSlot(); }; QT_END_NAMESPACE #endif