From 80689782de2371bed9b6a3c201f47ac5bf5eadad Mon Sep 17 00:00:00 2001 From: Evgeniy Alekseev Date: Wed, 5 Apr 2017 02:41:04 +0300 Subject: [PATCH] some server template improvements --- .../src/QueuedTcpServerThread.cpp | 118 +++++++++++++----- .../queued-server/src/QueuedTcpServerThread.h | 29 +++-- 2 files changed, 107 insertions(+), 40 deletions(-) diff --git a/sources/queued-server/src/QueuedTcpServerThread.cpp b/sources/queued-server/src/QueuedTcpServerThread.cpp index 2f85d3e..53cf642 100644 --- a/sources/queued-server/src/QueuedTcpServerThread.cpp +++ b/sources/queued-server/src/QueuedTcpServerThread.cpp @@ -18,7 +18,8 @@ #include #include -#include +#include +#include #include #include @@ -39,9 +40,11 @@ QueuedTcpServerThread::~QueuedTcpServerThread() } -QList QueuedTcpServerThread::defaultResponse(const int code) +QByteArrayList QueuedTcpServerThread::defaultResponse(const int code, + const QVariantHash &json) { - qCDebug(LOG_SERV) << "Build server response with code" << code; + qCDebug(LOG_SERV) << "Build server response with code" << code + << "and json"; QList output; output += "HTTP/1.1 " + QByteArray::number(code) + " OK\r\n"; @@ -55,35 +58,64 @@ QList QueuedTcpServerThread::defaultResponse(const int code) output += "Content-Type: application/json\r\n"; output += "\r\n"; + // json response + if (!json.isEmpty()) { + auto jsonObj = QJsonObject::fromVariantHash(json); + auto jsonByte + = QJsonDocument(jsonObj).toJson(QJsonDocument::JsonFormat::Compact); + output += jsonByte; + } + return output; } -QueuedTcpServerThread::QueuedTcpServerRequest -QueuedTcpServerThread::getRequest(const QStringList &headers, - const QByteArray &body) +QueuedTcpServerThread::QueuedTcpServerHeaders +QueuedTcpServerThread::getHeaders(const QStringList &headers) { - qCDebug(LOG_SERV) << "Get request object from headers" << headers - << "and body" << body; + qCDebug(LOG_SERV) << "Get headers object from" << headers; + + QueuedTcpServerThread::QueuedTcpServerHeaders headersObj; + + // metadata + auto protocolData = headers.first().split(' '); + if (protocolData.count() >= 3) { + headersObj.request = protocolData.takeFirst(); + headersObj.protocol = protocolData.takeLast(); + headersObj.query = protocolData.join(' '); + } + // headers + for (auto &header : headers.mid(1)) { + auto parsed = header.split(": "); + if (parsed.count() < 2) + continue; + headersObj.headers + += {parsed.first().toUtf8(), parsed.mid(1).join(": ").toUtf8()}; + } + + return headersObj; +} + + +QueuedTcpServerThread::QueuedTcpServerRequest QueuedTcpServerThread::getRequest( + const QByteArray &body, + const QueuedTcpServerThread::QueuedTcpServerHeaders &headers) +{ + qCDebug(LOG_SERV) << "Get request object from body" << body; QueuedTcpServerThread::QueuedTcpServerRequest request; - request.valid = true; - // method - request.request = headers.first().split(' ').at(0); - // path - QUrl url(headers.first().split(' ').at(1)); - request.path = url.path(); + request.headers = headers; + // body QJsonParseError error; auto jsonDoc = QJsonDocument::fromJson(body, &error); - if (error.error != QJsonParseError::NoError) { - qCWarning(LOG_SERV) << "Parse error" << error.errorString(); - request.valid = false; - } else { + if (error.error == QJsonParseError::NoError) request.data = jsonDoc.object().toVariantHash(); - } + else + qCWarning(LOG_SERV) << "Parse error" << error.errorString(); + // append from url if any - auto items = QUrlQuery(url.query()).queryItems(); + auto items = QUrlQuery(headers.query.query()).queryItems(); for (auto &item : items) { auto key = item.first; auto value = item.second; @@ -106,11 +138,40 @@ QueuedTcpServerThread::getRequest(const QStringList &headers, } +QueuedTcpServerThread::QueuedTcpServerResponse +QueuedTcpServerThread::response(const QueuedTcpServerRequest &request) const +{ + qCDebug(LOG_SERV) << "Build response for request" << request.headers.query; + + QueuedTcpServerThread::QueuedTcpServerResponse response; + + // HACK additional workaround to parse content type header + QNetworkRequest netRequest; + for (auto &headers : request.headers.headers) + netRequest.setRawHeader(headers.first, headers.second); + + // prepend code + if (!netRequest.header(QNetworkRequest::KnownHeaders::ContentTypeHeader) + .toString() + .startsWith("application/json")) + response.code = 415; + else + response.code = 200; + + // json data + if (response.code == 200) + // TODO json response from helpers + response.data = {{"foo", "bar"}}; + + return response; +} + + void QueuedTcpServerThread::run() { m_socket = new QTcpSocket(this); if (!m_socket->setSocketDescriptor(m_socketDescriptor)) { - emit(error(m_socket->error())); + qCWarning(LOG_SERV) << "Socket error" << m_socket->error(); return; } @@ -139,17 +200,14 @@ void QueuedTcpServerThread::readyRead() auto body = m_socket->readAll().simplified(); // get request object - auto request = getRequest(headers, body); - if (!request.valid) { - emit(error(QTcpSocket::UnsupportedSocketOperationError)); - return; - } + auto headersObj = getHeaders(headers); + auto requestObj = getRequest(body, headersObj); + auto responseObj = response(requestObj); - auto response = defaultResponse(200); - for (auto &resp : response) { + auto responseList = defaultResponse(responseObj.code, responseObj.data); + for (auto &resp : responseList) m_socket->write(resp); - m_socket->flush(); - } + m_socket->flush(); m_socket->waitForBytesWritten(3000); m_socket->disconnectFromHost(); diff --git a/sources/queued-server/src/QueuedTcpServerThread.h b/sources/queued-server/src/QueuedTcpServerThread.h index 9a40662..4dadff3 100644 --- a/sources/queued-server/src/QueuedTcpServerThread.h +++ b/sources/queued-server/src/QueuedTcpServerThread.h @@ -17,8 +17,9 @@ #ifndef QUEUEDTCPSERVERTHREAD_H #define QUEUEDTCPSERVERTHREAD_H -#include #include +#include +#include class QTcpSocket; @@ -29,23 +30,31 @@ class QueuedTcpServerThread : public QThread public: typedef struct { + QList> headers; + QString protocol; + QUrl query; QString request; - QString path; + } QueuedTcpServerHeaders; + typedef struct { + QueuedTcpServerHeaders headers; QVariantHash data; - bool valid = false; } QueuedTcpServerRequest; + typedef struct { + int code; + QVariantHash data; + } QueuedTcpServerResponse; explicit QueuedTcpServerThread(int socketDescriptor, QObject *parent); virtual ~QueuedTcpServerThread(); - static QList defaultResponse(const int code); - static QueuedTcpServerRequest getRequest(const QStringList &headers, - const QByteArray &body); - QVariantHash response(const QueuedTcpServerRequest &request) const; + static QByteArrayList defaultResponse(const int code, + const QVariantHash &json); + static QueuedTcpServerHeaders getHeaders(const QStringList &headers); + static QueuedTcpServerRequest + getRequest(const QByteArray &body, const QueuedTcpServerHeaders &headers); + QueuedTcpServerResponse + response(const QueuedTcpServerRequest &request) const; void run() override; -signals: - void error(QTcpSocket::SocketError socketError); - private slots: void disconnected(); void readyRead();