mirror of
https://github.com/arcan1s/queued.git
synced 2025-04-24 23:47:19 +00:00
some server template improvements
This commit is contained in:
parent
511de6e2d0
commit
80689782de
@ -18,7 +18,8 @@
|
|||||||
|
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QUrl>
|
#include <QNetworkRequest>
|
||||||
|
#include <QTcpSocket>
|
||||||
#include <QUrlQuery>
|
#include <QUrlQuery>
|
||||||
|
|
||||||
#include <queued/Queued.h>
|
#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;
|
QList<QByteArray> output;
|
||||||
output += "HTTP/1.1 " + QByteArray::number(code) + " OK\r\n";
|
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 += "Content-Type: application/json\r\n";
|
||||||
output += "\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;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QueuedTcpServerThread::QueuedTcpServerRequest
|
QueuedTcpServerThread::QueuedTcpServerHeaders
|
||||||
QueuedTcpServerThread::getRequest(const QStringList &headers,
|
QueuedTcpServerThread::getHeaders(const QStringList &headers)
|
||||||
const QByteArray &body)
|
|
||||||
{
|
{
|
||||||
qCDebug(LOG_SERV) << "Get request object from headers" << headers
|
qCDebug(LOG_SERV) << "Get headers object from" << headers;
|
||||||
<< "and body" << body;
|
|
||||||
|
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;
|
QueuedTcpServerThread::QueuedTcpServerRequest request;
|
||||||
request.valid = true;
|
request.headers = headers;
|
||||||
// method
|
|
||||||
request.request = headers.first().split(' ').at(0);
|
|
||||||
// path
|
|
||||||
QUrl url(headers.first().split(' ').at(1));
|
|
||||||
request.path = url.path();
|
|
||||||
// body
|
// body
|
||||||
QJsonParseError error;
|
QJsonParseError error;
|
||||||
auto jsonDoc = QJsonDocument::fromJson(body, &error);
|
auto jsonDoc = QJsonDocument::fromJson(body, &error);
|
||||||
if (error.error != QJsonParseError::NoError) {
|
if (error.error == QJsonParseError::NoError)
|
||||||
qCWarning(LOG_SERV) << "Parse error" << error.errorString();
|
|
||||||
request.valid = false;
|
|
||||||
} else {
|
|
||||||
request.data = jsonDoc.object().toVariantHash();
|
request.data = jsonDoc.object().toVariantHash();
|
||||||
}
|
else
|
||||||
|
qCWarning(LOG_SERV) << "Parse error" << error.errorString();
|
||||||
|
|
||||||
// append from url if any
|
// append from url if any
|
||||||
auto items = QUrlQuery(url.query()).queryItems();
|
auto items = QUrlQuery(headers.query.query()).queryItems();
|
||||||
for (auto &item : items) {
|
for (auto &item : items) {
|
||||||
auto key = item.first;
|
auto key = item.first;
|
||||||
auto value = item.second;
|
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()
|
void QueuedTcpServerThread::run()
|
||||||
{
|
{
|
||||||
m_socket = new QTcpSocket(this);
|
m_socket = new QTcpSocket(this);
|
||||||
if (!m_socket->setSocketDescriptor(m_socketDescriptor)) {
|
if (!m_socket->setSocketDescriptor(m_socketDescriptor)) {
|
||||||
emit(error(m_socket->error()));
|
qCWarning(LOG_SERV) << "Socket error" << m_socket->error();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,17 +200,14 @@ void QueuedTcpServerThread::readyRead()
|
|||||||
auto body = m_socket->readAll().simplified();
|
auto body = m_socket->readAll().simplified();
|
||||||
|
|
||||||
// get request object
|
// get request object
|
||||||
auto request = getRequest(headers, body);
|
auto headersObj = getHeaders(headers);
|
||||||
if (!request.valid) {
|
auto requestObj = getRequest(body, headersObj);
|
||||||
emit(error(QTcpSocket::UnsupportedSocketOperationError));
|
auto responseObj = response(requestObj);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto response = defaultResponse(200);
|
auto responseList = defaultResponse(responseObj.code, responseObj.data);
|
||||||
for (auto &resp : response) {
|
for (auto &resp : responseList)
|
||||||
m_socket->write(resp);
|
m_socket->write(resp);
|
||||||
m_socket->flush();
|
m_socket->flush();
|
||||||
}
|
|
||||||
|
|
||||||
m_socket->waitForBytesWritten(3000);
|
m_socket->waitForBytesWritten(3000);
|
||||||
m_socket->disconnectFromHost();
|
m_socket->disconnectFromHost();
|
||||||
|
@ -17,8 +17,9 @@
|
|||||||
#ifndef QUEUEDTCPSERVERTHREAD_H
|
#ifndef QUEUEDTCPSERVERTHREAD_H
|
||||||
#define QUEUEDTCPSERVERTHREAD_H
|
#define QUEUEDTCPSERVERTHREAD_H
|
||||||
|
|
||||||
#include <QTcpSocket>
|
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
|
|
||||||
class QTcpSocket;
|
class QTcpSocket;
|
||||||
@ -29,23 +30,31 @@ class QueuedTcpServerThread : public QThread
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
QList<QPair<QByteArray, QByteArray>> headers;
|
||||||
|
QString protocol;
|
||||||
|
QUrl query;
|
||||||
QString request;
|
QString request;
|
||||||
QString path;
|
} QueuedTcpServerHeaders;
|
||||||
|
typedef struct {
|
||||||
|
QueuedTcpServerHeaders headers;
|
||||||
QVariantHash data;
|
QVariantHash data;
|
||||||
bool valid = false;
|
|
||||||
} QueuedTcpServerRequest;
|
} QueuedTcpServerRequest;
|
||||||
|
typedef struct {
|
||||||
|
int code;
|
||||||
|
QVariantHash data;
|
||||||
|
} QueuedTcpServerResponse;
|
||||||
|
|
||||||
explicit QueuedTcpServerThread(int socketDescriptor, QObject *parent);
|
explicit QueuedTcpServerThread(int socketDescriptor, QObject *parent);
|
||||||
virtual ~QueuedTcpServerThread();
|
virtual ~QueuedTcpServerThread();
|
||||||
static QList<QByteArray> defaultResponse(const int code);
|
static QByteArrayList defaultResponse(const int code,
|
||||||
static QueuedTcpServerRequest getRequest(const QStringList &headers,
|
const QVariantHash &json);
|
||||||
const QByteArray &body);
|
static QueuedTcpServerHeaders getHeaders(const QStringList &headers);
|
||||||
QVariantHash response(const QueuedTcpServerRequest &request) const;
|
static QueuedTcpServerRequest
|
||||||
|
getRequest(const QByteArray &body, const QueuedTcpServerHeaders &headers);
|
||||||
|
QueuedTcpServerResponse
|
||||||
|
response(const QueuedTcpServerRequest &request) const;
|
||||||
void run() override;
|
void run() override;
|
||||||
|
|
||||||
signals:
|
|
||||||
void error(QTcpSocket::SocketError socketError);
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void disconnected();
|
void disconnected();
|
||||||
void readyRead();
|
void readyRead();
|
||||||
|
Loading…
Reference in New Issue
Block a user