218 lines
5.9 KiB
C++
218 lines
5.9 KiB
C++
#include "private/qhttpserverconnection_private.hpp"
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
namespace qhttp {
|
|
namespace server {
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
QHttpConnection::QHttpConnection(QObject *parent)
|
|
: QObject(parent), d_ptr(new QHttpConnectionPrivate(this)) {
|
|
QHTTP_LINE_LOG
|
|
}
|
|
|
|
QHttpConnection::QHttpConnection(QHttpConnectionPrivate& dd, QObject* parent)
|
|
: QObject(parent), d_ptr(&dd) {
|
|
QHTTP_LINE_LOG
|
|
}
|
|
|
|
void
|
|
QHttpConnection::setSocketDescriptor(qintptr sokDescriptor, TBackend backendType) {
|
|
d_ptr->createSocket(sokDescriptor, backendType);
|
|
}
|
|
|
|
QHttpConnection::~QHttpConnection() {
|
|
QHTTP_LINE_LOG
|
|
}
|
|
|
|
void
|
|
QHttpConnection::setTimeOut(quint32 miliSeconds) {
|
|
if ( miliSeconds != 0 ) {
|
|
d_func()->itimeOut = miliSeconds;
|
|
d_func()->itimer.start(miliSeconds, Qt::CoarseTimer, this);
|
|
}
|
|
}
|
|
|
|
void
|
|
QHttpConnection::killConnection() {
|
|
d_func()->isocket.close();
|
|
}
|
|
|
|
TBackend
|
|
QHttpConnection::backendType() const {
|
|
return d_func()->isocket.ibackendType;
|
|
}
|
|
|
|
QTcpSocket*
|
|
QHttpConnection::tcpSocket() const {
|
|
return d_func()->isocket.itcpSocket;
|
|
}
|
|
|
|
QLocalSocket*
|
|
QHttpConnection::localSocket() const {
|
|
return d_func()->isocket.ilocalSocket;
|
|
}
|
|
|
|
void
|
|
QHttpConnection::onHandler(const TServerHandler &handler) {
|
|
d_func()->ihandler = handler;
|
|
}
|
|
|
|
void
|
|
QHttpConnection::timerEvent(QTimerEvent *) {
|
|
killConnection();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// if user closes the connection, ends the response or by any other reason the
|
|
// socket disconnects, then the irequest and iresponse instances may have
|
|
// been deleted. In these situations reading more http body or emitting end()
|
|
// for incoming request are not possible:
|
|
// if ( ilastRequest == nullptr )
|
|
// return 0;
|
|
|
|
|
|
int
|
|
QHttpConnectionPrivate::messageBegin(http_parser*) {
|
|
itempUrl.clear();
|
|
itempUrl.reserve(128);
|
|
|
|
if ( ilastRequest )
|
|
ilastRequest->deleteLater();
|
|
|
|
ilastRequest = new QHttpRequest(q_func());
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
QHttpConnectionPrivate::url(http_parser*, const char* at, size_t length) {
|
|
Q_ASSERT(ilastRequest);
|
|
|
|
itempUrl.append(at, length);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
QHttpConnectionPrivate::headerField(http_parser*, const char* at, size_t length) {
|
|
if ( ilastRequest == nullptr )
|
|
return 0;
|
|
|
|
// insert the header we parsed previously
|
|
// into the header map
|
|
if ( !itempHeaderField.isEmpty() && !itempHeaderValue.isEmpty() ) {
|
|
// header names are always lower-cased
|
|
ilastRequest->d_func()->iheaders.insert(
|
|
itempHeaderField.toLower(),
|
|
itempHeaderValue.toLower()
|
|
);
|
|
// clear header value. this sets up a nice
|
|
// feedback loop where the next time
|
|
// HeaderValue is called, it can simply append
|
|
itempHeaderField.clear();
|
|
itempHeaderValue.clear();
|
|
}
|
|
|
|
itempHeaderField.append(at, length);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
QHttpConnectionPrivate::headerValue(http_parser*, const char* at, size_t length) {
|
|
if ( ilastRequest == nullptr )
|
|
return 0;
|
|
|
|
itempHeaderValue.append(at, length);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
QHttpConnectionPrivate::headersComplete(http_parser* parser) {
|
|
if ( ilastRequest == nullptr )
|
|
return 0;
|
|
|
|
ilastRequest->d_func()->iurl = QUrl(itempUrl);
|
|
|
|
// set method
|
|
ilastRequest->d_func()->imethod =
|
|
static_cast<THttpMethod>(parser->method);
|
|
|
|
// set version
|
|
ilastRequest->d_func()->iversion = QString("%1.%2")
|
|
.arg(parser->http_major)
|
|
.arg(parser->http_minor);
|
|
|
|
// Insert last remaining header
|
|
ilastRequest->d_func()->iheaders.insert(
|
|
itempHeaderField.toLower(),
|
|
itempHeaderValue.toLower()
|
|
);
|
|
|
|
// set client information
|
|
if ( isocket.ibackendType == ETcpSocket ) {
|
|
ilastRequest->d_func()->iremoteAddress = isocket.itcpSocket->peerAddress().toString();
|
|
ilastRequest->d_func()->iremotePort = isocket.itcpSocket->peerPort();
|
|
|
|
} else if ( isocket.ibackendType == ELocalSocket ) {
|
|
ilastRequest->d_func()->iremoteAddress = isocket.ilocalSocket->fullServerName();
|
|
ilastRequest->d_func()->iremotePort = 0; // not used in local sockets
|
|
}
|
|
|
|
if ( ilastResponse )
|
|
ilastResponse->deleteLater();
|
|
ilastResponse = new QHttpResponse(q_func());
|
|
|
|
if ( parser->http_major < 1 || parser->http_minor < 1 )
|
|
ilastResponse->d_func()->ikeepAlive = false;
|
|
|
|
// close the connection if response was the last packet
|
|
QObject::connect(ilastResponse, &QHttpResponse::done, [this](bool wasTheLastPacket){
|
|
ikeepAlive = !wasTheLastPacket;
|
|
if ( wasTheLastPacket ) {
|
|
isocket.flush();
|
|
isocket.close();
|
|
}
|
|
});
|
|
|
|
// we are good to go!
|
|
if ( ihandler )
|
|
ihandler(ilastRequest, ilastResponse);
|
|
else
|
|
emit q_ptr->newRequest(ilastRequest, ilastResponse);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
QHttpConnectionPrivate::body(http_parser*, const char* at, size_t length) {
|
|
if ( ilastRequest == nullptr )
|
|
return 0;
|
|
|
|
ilastRequest->d_func()->ireadState = QHttpRequestPrivate::EPartial;
|
|
|
|
if ( ilastRequest->d_func()->icollectRequired ) {
|
|
if ( !ilastRequest->d_func()->append(at, length) ) {
|
|
// forcefully dispatch the ilastRequest
|
|
finalizeConnection();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
emit ilastRequest->data(QByteArray(at, length));
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
QHttpConnectionPrivate::messageComplete(http_parser*) {
|
|
if ( ilastRequest == nullptr )
|
|
return 0;
|
|
|
|
// request is done
|
|
finalizeConnection();
|
|
return 0;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
} // namespace server
|
|
} // namespace qhttp
|
|
///////////////////////////////////////////////////////////////////////////////
|