1 /* 2 * Copyright (c) 2023 Unionman Technology Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef JQHTTPSERVER_H 17 #define JQHTTPSERVER_H 18 19 #ifndef QT_NETWORK_LIB 20 #error("Please add network in pro file") 21 #endif 22 23 #ifndef QT_CONCURRENT_LIB 24 #error("Please add concurrent in pro file") 25 #endif 26 27 // C++ lib import 28 #include <functional> 29 30 // Qt lib import 31 #include <QHostAddress> 32 #include <QMap> 33 #include <QMutex> 34 #include <QObject> 35 #include <QPointer> 36 #include <QSet> 37 #include <QSharedPointer> 38 #include <QUrl> 39 #include <QVector> 40 41 class QIODevice; 42 class QThreadPool; 43 class QHostAddress; 44 class QTimer; 45 class QImage; 46 class QTcpServer; 47 class QLocalServer; 48 class QSslCertificate; 49 class QSslKey; 50 class QSslConfiguration; 51 52 namespace JQHttpServer { 53 54 class Session : public QObject { 55 Q_OBJECT 56 Q_DISABLE_COPY(Session) 57 58 public: 59 Session(const QPointer<QIODevice>& tcpSocket); 60 61 ~Session(); 62 setHandleAcceptedCallback(const std::function<void (const QPointer<Session> &)> & callback)63 inline void setHandleAcceptedCallback(const std::function<void(const QPointer<Session>&)>& callback) 64 { 65 handleAcceptedCallback_ = callback; 66 } 67 requestMethod()68 inline QString requestMethod() const 69 { 70 return requestMethod_; 71 } 72 requestUrl()73 inline QString requestUrl() const 74 { 75 return requestUrl_; 76 } 77 requestCrlf()78 inline QString requestCrlf() const 79 { 80 return requestCrlf_; 81 } 82 requestHeader()83 inline QMap<QString, QString> requestHeader() const 84 { 85 return requestHeader_; 86 } 87 requestBody()88 inline QByteArray requestBody() const 89 { 90 return requestBody_; 91 } 92 93 QString requestUrlPath() const; 94 95 QStringList requestUrlPathSplitToList() const; 96 97 QMap<QString, QString> requestUrlQuery() const; 98 GetIODevice()99 inline QIODevice* GetIODevice() const 100 { 101 return ioDevice_.data(); 102 } 103 104 public slots: 105 void ReplyText(const QString& replyData, const int& httpStatusCode = 200); 106 107 void ReplyRedirects(const QUrl& targetUrl, const int& httpStatusCode = 200); 108 109 void ReplyJsonObject(const QJsonObject& jsonObject, const int& httpStatusCode = 200); 110 111 void ReplyJsonArray(const QJsonArray& jsonArray, const int& httpStatusCode = 200); 112 113 void ReplyFile(const QString& filePath, const int& httpStatusCode = 200); 114 115 void ReplyImage(const QImage& image, const int& httpStatusCode = 200); 116 117 void ReplyImage(const QString& imageFilePath, const int& httpStatusCode = 200); 118 119 void ReplyBytes(const QByteArray& bytes, const int& httpStatusCode = 200); 120 121 void ReplyOptions(); 122 123 private: 124 void InspectionBufferSetup1(); 125 126 void InspectionBufferSetup2(); 127 128 private: 129 QPointer<QIODevice> ioDevice_; 130 std::function<void(const QPointer<Session>&)> handleAcceptedCallback_; 131 QSharedPointer<QTimer> timerForClose_; 132 133 QByteArray buffer_; 134 135 QString requestMethod_; 136 QString requestUrl_; 137 QString requestCrlf_; 138 139 QMap<QString, QString> requestHeader_; 140 bool headerAcceptedFinish_ = false; 141 qint64 contentLength_ = -1; 142 bool alreadyReply_ = false; 143 144 QByteArray requestBody_; 145 146 qint64 waitWrittenByteCount_ = 0; 147 QSharedPointer<QIODevice> ioDeviceForReply_; 148 }; 149 150 class AbstractManage : public QObject { 151 Q_OBJECT 152 Q_DISABLE_COPY(AbstractManage) 153 154 public: 155 AbstractManage(const int& handleMaxThreadCount); 156 157 virtual ~AbstractManage(); 158 setHttpAcceptedCallback(const std::function<void (const QPointer<Session> & session)> & httpAcceptedCallback)159 inline void setHttpAcceptedCallback( 160 const std::function<void(const QPointer<Session>& session)>& httpAcceptedCallback) 161 { 162 httpAcceptedCallback_ = httpAcceptedCallback; 163 } 164 handleThreadPool()165 inline QSharedPointer<QThreadPool> handleThreadPool() 166 { 167 return handleThreadPool_; 168 } 169 serverThreadPool()170 inline QSharedPointer<QThreadPool> serverThreadPool() 171 { 172 return serverThreadPool_; 173 } 174 175 virtual bool IsRunning() = 0; 176 177 protected Q_SLOTS: 178 bool Begin(); 179 180 void Close(); 181 182 protected: 183 virtual bool OnStart() = 0; 184 185 virtual void OnFinish() = 0; 186 187 bool StartServerThread(); 188 189 void StopHandleThread(); 190 191 void StopServerThread(); 192 193 void NewSession(const QPointer<Session>& session); 194 195 void HandleAccepted(const QPointer<Session>& session); 196 197 signals: 198 void readyToClose(); 199 200 protected: 201 QSharedPointer<QThreadPool> serverThreadPool_; 202 QSharedPointer<QThreadPool> handleThreadPool_; 203 204 QMutex mutex_; 205 206 std::function<void(const QPointer<Session>& session)> httpAcceptedCallback_; 207 208 QSet<Session*> availableSessions_; 209 }; 210 211 class TcpServerManage : public AbstractManage { 212 Q_OBJECT 213 Q_DISABLE_COPY(TcpServerManage) 214 215 public: 216 TcpServerManage(const int& handleMaxThreadCount = 2); 217 218 ~TcpServerManage() override; 219 220 bool Listen(const QHostAddress& address, const quint16& port); 221 222 bool IsRunning() override; 223 224 private: 225 bool OnStart() override; 226 227 void OnFinish() override; 228 229 private: 230 QPointer<QTcpServer> tcpServer_; 231 232 QHostAddress listenAddress_ = QHostAddress::Any; 233 quint16 listenPort_ = 0; 234 }; 235 236 #ifndef QT_NO_SSL 237 class SslServerHelper; 238 239 class SslServerManage : public AbstractManage { 240 Q_OBJECT 241 Q_DISABLE_COPY(SslServerManage) 242 243 public: 244 SslServerManage(const int& handleMaxThreadCount = 2); 245 246 ~SslServerManage() override; 247 248 bool Listen(const QHostAddress& address, const quint16& port, const QString& crtFilePath, 249 const QString& keyFilePath, const QList<QPair<QString, bool>>& caFileList = {} // [ { filePath, isPem } ] 250 ); 251 252 bool IsRunning() override; 253 254 private: 255 bool OnStart() override; 256 257 void OnFinish() override; 258 259 private: 260 QPointer<SslServerHelper> tcpServer_; 261 262 QHostAddress listenAddress_ = QHostAddress::Any; 263 quint16 listenPort_ = 0; 264 265 QSharedPointer<QSslConfiguration> sslConfiguration_; 266 }; 267 #endif 268 269 class LocalServerManage : public AbstractManage { 270 Q_OBJECT 271 Q_DISABLE_COPY(LocalServerManage) 272 273 public: 274 LocalServerManage(const int& handleMaxThreadCount); 275 276 ~LocalServerManage() override; 277 278 bool Listen(const QString& name); 279 280 bool IsRunning() override; 281 282 private: 283 bool OnStart() override; 284 285 void OnFinish() override; 286 287 private: 288 QPointer<QLocalServer> localServer_; 289 290 QString listenName_; 291 }; 292 293 } 294 295 #endif // JQHTTPSERVER_H_ 296