1 /* 2 * Copyright (C) 2016-2018 Daniel Nicoletti <dantti12@gmail.com> 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 #ifndef PROTOCOLHTTP_H 19 #define PROTOCOLHTTP_H 20 21 #include <QObject> 22 23 #include "protocol.h" 24 #include "socket.h" 25 26 #include <Cutelyst/Context> 27 28 namespace Cutelyst { 29 class Server; 30 class Socket; 31 class ProtoRequestHttp final : public ProtocolData, public Cutelyst::EngineRequest 32 { 33 Q_GADGET 34 public: 35 enum WebSocketPhase 36 { 37 WebSocketPhaseHeaders, 38 WebSocketPhaseSize, 39 WebSocketPhaseMask, 40 WebSocketPhasePayload, 41 }; 42 Q_ENUM(WebSocketPhase) 43 44 enum OpCode 45 { 46 OpCodeContinue = 0x0, 47 OpCodeText = 0x1, 48 OpCodeBinary = 0x2, 49 OpCodeReserved3 = 0x3, 50 OpCodeReserved4 = 0x4, 51 OpCodeReserved5 = 0x5, 52 OpCodeReserved6 = 0x6, 53 OpCodeReserved7 = 0x7, 54 OpCodeClose = 0x8, 55 OpCodePing = 0x9, 56 OpCodePong = 0xA, 57 OpCodeReservedB = 0xB, 58 OpCodeReservedC = 0xC, 59 OpCodeReservedD = 0xD, 60 OpCodeReservedE = 0xE, 61 OpCodeReservedF = 0xF 62 }; 63 Q_ENUM(OpCode) 64 65 ProtoRequestHttp(Socket *sock, int bufferSize); 66 ~ProtoRequestHttp() override; 67 68 void setupNewConnection(Socket *sock) override final; 69 70 bool writeHeaders(quint16 status, const Cutelyst::Headers &headers) override final; 71 72 qint64 doWrite(const char *data, qint64 len) override final; doWrite(const QByteArray & data)73 inline qint64 doWrite(const QByteArray &data) { 74 return doWrite(data.constData(), data.size()); 75 } 76 77 void processingFinished() override final; 78 79 bool webSocketSendTextMessage(const QString &message) override final; 80 81 bool webSocketSendBinaryMessage(const QByteArray &message) override final; 82 83 bool webSocketSendPing(const QByteArray &payload) override final; 84 85 bool webSocketClose(quint16 code, const QString &reason) override final; 86 resetData()87 inline void resetData() override final { 88 ProtocolData::resetData(); 89 90 // EngineRequest 91 if (status & EngineRequest::Async) { 92 context->deleteLater(); 93 } else { 94 delete context; 95 } 96 context = nullptr; 97 body = nullptr; 98 99 elapsed.invalidate(); 100 status = InitialState; 101 102 websocketUpgraded = false; 103 last = 0; 104 beginLine = 0; 105 106 serverAddress = sock->serverAddress; 107 remoteAddress = sock->remoteAddress; 108 remotePort = sock->remotePort; 109 isSecure = sock->isSecure; 110 } 111 112 virtual void socketDisconnected() override final; 113 114 QByteArray websocket_message; 115 QByteArray websocket_payload; 116 quint64 websocket_payload_size = 0; 117 quint32 websocket_need = 0; 118 quint32 websocket_mask = 0; 119 int last = 0; 120 int beginLine = 0; 121 int websocket_start_of_frame = 0; 122 int websocket_phase = 0; 123 quint8 websocket_continue_opcode = 0; 124 quint8 websocket_finn_opcode = 0; 125 bool websocketUpgraded = false; 126 127 protected: 128 bool webSocketHandshakeDo(const QString &key, const QString &origin, const QString &protocol) override final; 129 }; 130 131 class ProtocolHttp2; 132 class ProtocolWebSocket; 133 class ProtocolHttp final : public Protocol 134 { 135 public: 136 ProtocolHttp(Server *wsgi, ProtocolHttp2 *upgradeH2c = nullptr); 137 ~ProtocolHttp() override; 138 139 Type type() const override; 140 141 void parse(Socket *sock, QIODevice *io) const override final; 142 143 ProtocolData *createData(Socket *sock) const override final; 144 145 private: 146 inline bool processRequest(Socket *sock, QIODevice *io) const; 147 inline void parseMethod(const char *ptr, const char *end, Socket *sock) const; 148 inline void parseHeader(const char *ptr, const char *end, Socket *sock) const; 149 150 protected: 151 friend class ProtoRequestHttp; 152 153 ProtocolWebSocket *m_websocketProto; 154 ProtocolHttp2 *m_upgradeH2c; 155 bool usingFrontendProxy; 156 }; 157 158 } 159 160 #endif // PROTOCOLHTTP_H 161