File indexing completed on 2025-01-26 04:24:52
0001 /* 0002 * Copyright 2011 Nikhil Marathe <nsm.nikhil@gmail.com> 0003 * 0004 * Permission is hereby granted, free of charge, to any person obtaining a copy 0005 * of this software and associated documentation files (the "Software"), to 0006 * deal in the Software without restriction, including without limitation the 0007 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 0008 * sell copies of the Software, and to permit persons to whom the Software is 0009 * furnished to do so, subject to the following conditions: 0010 * 0011 * The above copyright notice and this permission notice shall be included in 0012 * all copies or substantial portions of the Software. 0013 * 0014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 0015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 0016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 0017 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 0018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 0019 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 0020 * IN THE SOFTWARE. 0021 */ 0022 0023 #ifndef Q_HTTP_SERVER 0024 #define Q_HTTP_SERVER 0025 0026 #define QHTTPSERVER_VERSION_MAJOR 0 0027 #define QHTTPSERVER_VERSION_MINOR 1 0028 #define QHTTPSERVER_VERSION_PATCH 0 0029 0030 #include <QObject> 0031 #include <QHostAddress> 0032 0033 class QTcpServer; 0034 0035 class QHttpRequest; 0036 class QHttpResponse; 0037 0038 /*! 0039 * A map of request or response headers 0040 */ 0041 typedef QHash<QString, QString> HeaderHash; 0042 0043 /*! 0044 * Maps status codes to string reason phrases 0045 */ 0046 extern QHash<int, QString> STATUS_CODES; 0047 0048 /*! \mainpage %QHttpServer Documentation 0049 * 0050 * \section introduction Introduction 0051 * 0052 * %QHttpServer is a easy to use, fast and light-weight 0053 * HTTP Server suitable for C++ web applications backed 0054 * by Qt. Since C++ web applications are pretty uncommon 0055 * the market for this project is pretty low. 0056 * 0057 * But integrating this with a module like QtScript 0058 * and using it to write JavaScript web applications is 0059 * a tempting possibility, and something that I want to 0060 * demonstrate at <a href="http://conf.kde.in">conf.kde.in 2011</a>. 0061 * 0062 * %QHttpServer uses a signal-Q_SLOTS based mechanism 0063 * for all communication, so no inheritance is required. 0064 * It tries to be as asynchronous as possible, to the 0065 * extent that request body data is also delivered as and 0066 * when it is received over the socket via Q. This 0067 * kind of programming may take some getting used to. 0068 * 0069 * %QHttpServer is backed by <a href="http://github.com/ry/http-parser">Ryan 0070 * Dahl's secure and fast http parser</a> which makes it streaming 0071 * till the lowest level. 0072 * 0073 * \section usage Usage 0074 * 0075 * Using %QHttpServer is very simple. Simply create a QHttpServer, 0076 * connect a slot to the newRequest() signal and use the request and 0077 * response objects. 0078 * See the QHttpServer class documentation for an example. 0079 * 0080 * \example helloworld/helloworld.cpp 0081 * \example helloworld/helloworld.h 0082 * \example greeting/greeting.cpp 0083 * \example greeting/greeting.h 0084 * \example bodydata/bodydata.cpp 0085 * \example bodydata/bodydata.h 0086 */ 0087 0088 /*! \class QHttpServer 0089 * The QHttpServer class forms the basis of the %QHttpServer 0090 * project. It is a fast, non-blocking HTTP server. 0091 * 0092 * These are the steps to create a server and respond to requests. 0093 * 0094 * <ol> 0095 * <li>Create an instance of QHttpServer.</li> 0096 * <li>Connect a slot to the newRequest(QHttpRequest*, QHttpResponse*) 0097 * signal.</li> 0098 * <li>Create a QCoreApplication to drive the server event loop.</li> 0099 * <li>Respond to clients by writing out to the QHttpResponse object.</li> 0100 * </ol> 0101 * 0102 * helloworld.cpp 0103 * \include helloworld/helloworld.cpp 0104 * helloworld.h 0105 * \include helloworld/helloworld.h 0106 * 0107 */ 0108 class QHttpServer : public QObject 0109 { 0110 Q_OBJECT 0111 0112 public: 0113 /*! 0114 * Create a new HTTP Server 0115 */ 0116 QHttpServer(QObject *parent = 0); 0117 virtual ~QHttpServer(); 0118 0119 /*! 0120 * Start the server bound to the @c address and @c port. 0121 * This function returns immediately! 0122 * 0123 * \param address Address on which to listen to. Default is to listen on 0124 * all interfaces which means the server can be accessed from anywhere. 0125 * \param port Port number on which the server should run. 0126 * \return true if the server was started successfully, false otherwise. 0127 * \sa listen(quint16), listen(const QString&, quint16) 0128 */ 0129 bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port=0); 0130 0131 /*! 0132 * Start the server bound to the @c address and @c port. 0133 * This function returns immediately! 0134 * 0135 * \param address Address on which to listen to. 0136 * \param port Port number on which the server should run. 0137 * \return true if the server was started successfully, false otherwise. 0138 * \sa listen(quint16), listen(const QHostAddress&, quint16) 0139 */ 0140 Q_INVOKABLE bool listen(const QString &address, quint16 port=0); 0141 0142 /*! 0143 * Starts the server on @c port listening on all interfaces. 0144 * 0145 * \param port Port number on which the server should run. 0146 * \return true if the server was started successfully, false otherwise. 0147 * \sa listen(const QHostAddress&, quint16), listen(const QString&, quint16) 0148 */ 0149 Q_INVOKABLE bool listen(quint16 port); 0150 0151 /*! 0152 * Stop listening for connections 0153 */ 0154 void close(); 0155 0156 Q: 0157 /*! 0158 * This signal is emitted whenever a client 0159 * makes a new request to the server. 0160 * 0161 * The slot should use the @c request and @c response 0162 * objects to communicate with the client. 0163 * 0164 * \section memorymanagement Memory Management 0165 * 0166 * The QHttpRequest and QHttpResponse deletion policies 0167 * are such. 0168 * 0169 * QHttpRequest is <strong>never</strong> deleted by %QHttpServer. 0170 * Since it is not possible to determine till what point the application 0171 * may want access to its data, it is up to the application to delete it. 0172 * A recommended way to handle this is to create a new responder object for 0173 * every request and to delete the request in that object's destructor. The 0174 * object itself can be deleted by connecting to QHttpResponse's done() 0175 * slot as explained below. 0176 * 0177 * You should <strong>NOT</strong> delete the QHttpRequest object until it 0178 * has emitted an QHttpRequest::end() signal. 0179 * 0180 * QHttpResponse queues itself up for auto-deletion once the application 0181 * calls its end() method. Once the data has been flushed to the underlying 0182 * socket, the object will Q_EMIT a QHttpResponse::done() signal before queueing itself up 0183 * for deletion. You should <strong>NOT</strong> interact with the response 0184 * object once it has emitted QHttpResponse::done() although actual deletion does not 0185 * happen until QHttpResponse::destroyed() is emitted. 0186 * QHttpResponse::done() serves as a useful way to handle memory management of the 0187 * application itself. For example: 0188 * 0189 * \code 0190 * MyApp::MyApp() 0191 * : QObject(0) 0192 * { 0193 * QHttpServer *s = new QHttpServer; 0194 * connect(s, SIGNAL(newRequest(...)), this, SLOT(handle(...))); 0195 * s.listen(8000); 0196 * } 0197 * 0198 * void MyApp::handle(QHttpRequest *request, QHttpResponse *response) 0199 * { 0200 * if( request->url() matches a route ) 0201 * new Responder(request, response); 0202 * else 0203 * new PageNotFound(request, response); 0204 * } 0205 * 0206 * ... 0207 * 0208 * Responder::Responder(QHttpRequest *request, QHttpResponse *response) 0209 * { 0210 * m_request = request; 0211 * 0212 * connect(request, SIGNAL(end()), response, SLOT(end())); 0213 * // Once the request is complete, the response is ended. 0214 * // when the response ends, it deletes itself 0215 * // the Responder object connects to done() 0216 * // which will lead to it being deleted 0217 * // and this will delete the request. 0218 * // So all 3 are properly deleted. 0219 * connect(response, SIGNAL(done()), this, SLOT(deleteLater())); 0220 * response->writeHead(200); 0221 * response->write("Quitting soon"); 0222 * } 0223 * 0224 * Responder::~Responder() 0225 * { 0226 * delete m_request; 0227 * m_request = 0; 0228 * } 0229 * \endcode 0230 * 0231 */ 0232 void newRequest(QHttpRequest *request, QHttpResponse *response); 0233 0234 private Q_SLOTS: 0235 void newConnection(); 0236 0237 private: 0238 QTcpServer *m_tcpServer; 0239 }; 0240 0241 #endif