keepassxc/src/http/qhttp/private/qhttpserverconnection_private.hpp
2017-02-26 22:13:22 -05:00

201 lines
6 KiB
C++

/** 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 <QBasicTimer>
#include <QFile>
///////////////////////////////////////////////////////////////////////////////
namespace qhttp {
namespace server {
///////////////////////////////////////////////////////////////////////////////
class QHttpConnectionPrivate :
public details::HttpRequestParser<QHttpConnectionPrivate>
{
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<size_t>(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