mirror of
https://github.com/arcan1s/queued.git
synced 2025-04-24 15:37:19 +00:00
some server template improvements
This commit is contained in:
parent
511de6e2d0
commit
80689782de
@ -18,7 +18,8 @@
|
||||
|
||||
#include <QDataStream>
|
||||
#include <QJsonDocument>
|
||||
#include <QUrl>
|
||||
#include <QNetworkRequest>
|
||||
#include <QTcpSocket>
|
||||
#include <QUrlQuery>
|
||||
|
||||
#include <queued/Queued.h>
|
||||
@ -39,9 +40,11 @@ QueuedTcpServerThread::~QueuedTcpServerThread()
|
||||
}
|
||||
|
||||
|
||||
QList<QByteArray> 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<QByteArray> output;
|
||||
output += "HTTP/1.1 " + QByteArray::number(code) + " OK\r\n";
|
||||
@ -55,35 +58,64 @@ QList<QByteArray> 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();
|
||||
|
@ -17,8 +17,9 @@
|
||||
#ifndef QUEUEDTCPSERVERTHREAD_H
|
||||
#define QUEUEDTCPSERVERTHREAD_H
|
||||
|
||||
#include <QTcpSocket>
|
||||
#include <QThread>
|
||||
#include <QUrl>
|
||||
#include <QVariant>
|
||||
|
||||
|
||||
class QTcpSocket;
|
||||
@ -29,23 +30,31 @@ class QueuedTcpServerThread : public QThread
|
||||
|
||||
public:
|
||||
typedef struct {
|
||||
QList<QPair<QByteArray, QByteArray>> 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<QByteArray> 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();
|
||||
|
Loading…
Reference in New Issue
Block a user