/** private imeplementation. * https://github.com/azadkuh/qhttp * * @author amir zamani * @version 2.0.0 * @date 2014-07-11 */ #ifndef QHTTPSERVER_CONNECTION_PRIVATE_HPP #define QHTTPSERVER_CONNECTION_PRIVATE_HPP /////////////////////////////////////////////////////////////////////////////// #include "qhttpserverconnection.hpp" #include "httpparser.hxx" #include "qhttpserverrequest.hpp" #include "qhttpserverresponse.hpp" #include "private/qhttpserverrequest_private.hpp" #include "private/qhttpserverresponse_private.hpp" #include #include /////////////////////////////////////////////////////////////////////////////// namespace qhttp { namespace server { /////////////////////////////////////////////////////////////////////////////// class QHttpConnectionPrivate : public details::HttpRequestParser { Q_DECLARE_PUBLIC(QHttpConnection) public: explicit QHttpConnectionPrivate(QHttpConnection* q) : q_ptr(q) { QObject::connect( q_func(), &QHttpConnection::disconnected, [this](){ release(); } ); QHTTP_LINE_DEEPLOG } virtual ~QHttpConnectionPrivate() { QHTTP_LINE_DEEPLOG } void createSocket(qintptr sokDesc, TBackend bend) { isocket.ibackendType = bend; if ( bend == ETcpSocket ) { initTcpSocket(sokDesc); } else if ( bend == ESslSocket) { initSslSocket(sokDesc); } else if ( bend == ELocalSocket ) { initLocalSocket(sokDesc); } } void release() { // if socket drops and http_parser can not call // messageComplete, dispatch the ilastRequest finalizeConnection(); isocket.disconnectAllQtConnections(); isocket.release(); if ( ilastRequest ) { ilastRequest->deleteLater(); ilastRequest = nullptr; } if ( ilastResponse ) { ilastResponse->deleteLater(); ilastResponse = nullptr; } q_func()->deleteLater(); } public: void onReadyRead() { while ( isocket.bytesAvailable() > 0 ) { char buffer[4097] = {0}; size_t readLength = static_cast(isocket.readRaw(buffer, 4096)); parse(buffer, readLength); } } void finalizeConnection() { if ( ilastRequest == nullptr ) return; ilastRequest->d_func()->finalizeSending([this]{ emit ilastRequest->end(); }); } public: int messageBegin(http_parser* parser); int url(http_parser* parser, const char* at, size_t length); int status(http_parser*, const char*, size_t) { return 0; // not used in parsing incoming request. } int headerField(http_parser* parser, const char* at, size_t length); int headerValue(http_parser* parser, const char* at, size_t length); int headersComplete(http_parser* parser); int body(http_parser* parser, const char* at, size_t length); int messageComplete(http_parser* parser); private: void initTcpSocket(qintptr sokDesc) { QTcpSocket* sok = new QTcpSocket( q_func() ); isocket.itcpSocket = sok; sok->setSocketDescriptor(sokDesc); QObject::connect( sok, &QTcpSocket::readyRead, [this](){ onReadyRead(); } ); QObject::connect( sok, &QTcpSocket::bytesWritten, [this](){ auto btw = isocket.itcpSocket->bytesToWrite(); if ( btw == 0 && ilastResponse ) emit ilastResponse->allBytesWritten(); }); QObject::connect( sok, &QTcpSocket::disconnected, q_func(), &QHttpConnection::disconnected, Qt::QueuedConnection ); } void initSslSocket(qintptr sokDesc) { QSslSocket* sok = new QSslSocket( q_func() ); isocket.itcpSocket = sok; sok->setSocketDescriptor(sokDesc); QObject::connect( sok, &QSslSocket::readyRead, [this](){ onReadyRead(); } ); QObject::connect( sok, &QSslSocket::bytesWritten, [this](){ auto btw = isocket.itcpSocket->bytesToWrite(); if ( btw == 0 && ilastResponse ) emit ilastResponse->allBytesWritten(); }); QObject::connect( sok, &QSslSocket::disconnected, q_func(), &QHttpConnection::disconnected, Qt::QueuedConnection ); } void initLocalSocket(qintptr sokDesc) { QLocalSocket* sok = new QLocalSocket( q_func() ); isocket.ilocalSocket = sok; sok->setSocketDescriptor(sokDesc); QObject::connect( sok, &QLocalSocket::readyRead, [this](){ onReadyRead(); } ); QObject::connect( sok, &QLocalSocket::bytesWritten, [this](){ auto btw = isocket.ilocalSocket->bytesToWrite(); if ( btw == 0 && ilastResponse ) emit ilastResponse->allBytesWritten(); }); QObject::connect( sok, &QLocalSocket::disconnected, q_func(), &QHttpConnection::disconnected, Qt::QueuedConnection ); } protected: QHttpConnection* const q_ptr; QByteArray itempUrl; // Since there can only be one request/response pair per connection at any // time even with pipelining. QHttpRequest* ilastRequest = nullptr; QHttpResponse* ilastResponse = nullptr; TServerHandler ihandler = nullptr; }; /////////////////////////////////////////////////////////////////////////////// } // namespace server } // namespace qhttp /////////////////////////////////////////////////////////////////////////////// #endif // QHTTPSERVER_CONNECTION_PRIVATE_HPP