fix replies from webserver

This commit is contained in:
Simon Stürz 2015-08-28 14:44:34 +02:00 committed by Michael Zanetti
parent d759602915
commit 01f9b418a9
7 changed files with 62 additions and 49 deletions

View File

@ -139,7 +139,7 @@ HttpReply::HttpReply(QObject *parent) :
setRawHeader("Access-Control-Allow-Origin","*"); setRawHeader("Access-Control-Allow-Origin","*");
setRawHeader("Keep-Alive", "timeout=6, max=50"); setRawHeader("Keep-Alive", "timeout=6, max=50");
setHeader(HttpHeaderType::CacheControlHeader, "no-cache"); setHeader(HttpHeaderType::CacheControlHeader, "no-cache");
setHeader(HttpHeaderType::ConnectionHeader, "Keep-Alive"); setHeader(HttpHeaderType::ConnectionHeader, "keep-alive");
packReply(); packReply();
} }
@ -275,6 +275,9 @@ bool HttpReply::isEmpty() const
/*! Clears all data of this \l{HttpReply}. */ /*! Clears all data of this \l{HttpReply}. */
void HttpReply::clear() void HttpReply::clear()
{ {
m_closeConnection = false;
m_type = TypeSync;
m_statusCode = Ok;
m_rawHeader.clear(); m_rawHeader.clear();
m_payload.clear(); m_payload.clear();
m_rawHeaderList.clear(); m_rawHeaderList.clear();

View File

@ -90,10 +90,12 @@ HttpReply *RestResource::createCorsSuccessReply()
{ {
HttpReply *reply = RestResource::createSuccessReply(); HttpReply *reply = RestResource::createSuccessReply();
reply->setHeader(HttpReply::ContentTypeHeader, "text/plain"); reply->setHeader(HttpReply::ContentTypeHeader, "text/plain");
reply->setRawHeader("Accept","text/plain");
reply->setRawHeader("Allow", "PUT, POST, GET, DELETE, OPTIONS");
reply->setRawHeader("Access-Control-Allow-Methods", "PUT, POST, GET, DELETE, OPTIONS"); reply->setRawHeader("Access-Control-Allow-Methods", "PUT, POST, GET, DELETE, OPTIONS");
reply->setRawHeader("Access-Control-Allow-Headers", "Origin, Content-Type, Accept"); reply->setRawHeader("Access-Control-Allow-Headers", "Origin, Content-Type, Accept");
reply->setRawHeader("Access-Control-Max-Age", "1728000"); reply->setRawHeader("Access-Control-Max-Age", "1728000");
reply->setCloseConnection(true); //reply->setCloseConnection(true);
return reply; return reply;
} }

View File

@ -116,6 +116,7 @@ void RestServer::processHttpRequest(const QUuid &clientId, const HttpRequest &re
qCDebug(dcRest) << "process options request\n" << request; qCDebug(dcRest) << "process options request\n" << request;
HttpReply *reply = RestResource::createCorsSuccessReply(); HttpReply *reply = RestResource::createCorsSuccessReply();
reply->setClientId(clientId); reply->setClientId(clientId);
qCDebug(dcRest) << reply->data();
m_webserver->sendHttpReply(reply); m_webserver->sendHttpReply(reply);
reply->deleteLater(); reply->deleteLater();
return; return;
@ -142,8 +143,10 @@ void RestServer::asyncReplyFinished()
qCDebug(dcWebServer) << "Async reply finished"; qCDebug(dcWebServer) << "Async reply finished";
if (reply->timedOut()) if (reply->timedOut()) {
reply->clear();
reply->setHttpStatusCode(HttpReply::GatewayTimeout); reply->setHttpStatusCode(HttpReply::GatewayTimeout);
}
m_webserver->sendHttpReply(reply); m_webserver->sendHttpReply(reply);
reply->deleteLater(); reply->deleteLater();

View File

@ -75,6 +75,7 @@
#include "guhsettings.h" #include "guhsettings.h"
#include "httpreply.h" #include "httpreply.h"
#include "httprequest.h" #include "httprequest.h"
#include "rest/restresource.h"
#include <QJsonDocument> #include <QJsonDocument>
#include <QTcpServer> #include <QTcpServer>
@ -130,15 +131,19 @@ WebServer::~WebServer()
*/ */
void WebServer::sendHttpReply(HttpReply *reply) void WebServer::sendHttpReply(HttpReply *reply)
{ {
// get the right socket
QSslSocket *socket = 0; QSslSocket *socket = 0;
socket = m_clientList.value(reply->clientId()); socket = m_clientList.value(reply->clientId());
if (!socket) { if (!socket) {
qCDebug(dcWebServer) << "Invalid socket pointer! This should never happen!!! Missing clientId in reply?"; qCWarning(dcWebServer) << "Invalid socket pointer! This should never happen!!! Missing clientId in reply?";
return; return;
} }
//qCDebug(dcWebServer()) << "sending header to" << socket->peerAddress().toString() << socket->peerPort() << "\n" << reply->rawHeader(); // send raw data
writeData(socket, reply->data()); reply->packReply();
socket->write(reply->data());
// close the connection if wanted
if (reply->closeConnection()) if (reply->closeConnection())
socket->close(); socket->close();
@ -151,30 +156,31 @@ bool WebServer::verifyFile(QSslSocket *socket, const QString &fileName)
// make shore the file exists // make shore the file exists
if (!file.exists()) { if (!file.exists()) {
qCWarning(dcWebServer) << "requested file" << file.filePath() << "does not exist."; qCWarning(dcWebServer) << "requested file" << file.filePath() << "does not exist.";
HttpReply reply(HttpReply::NotFound); HttpReply *reply = RestResource::createErrorReply(HttpReply::NotFound);
reply.setPayload("404 Not found."); reply->setClientId(m_clientList.key(socket));
reply.packReply(); sendHttpReply(reply);
writeData(socket, reply.data()); reply->deleteLater();
return false; return false;
} }
// make shore the file is in the public directory // make shore the file is in the public directory
if (!file.canonicalFilePath().startsWith(m_webinterfaceDir.path())) { if (!file.canonicalFilePath().startsWith(m_webinterfaceDir.path())) {
qCWarning(dcWebServer) << "requested file" << file.fileName() << "is outside the public folder."; qCWarning(dcWebServer) << "requested file" << file.fileName() << "is outside the public folder.";
HttpReply reply(HttpReply::Forbidden); HttpReply *reply = RestResource::createErrorReply(HttpReply::Forbidden);
reply.setPayload("403 Forbidden."); reply->setClientId(m_clientList.key(socket));
reply.packReply(); sendHttpReply(reply);
writeData(socket, reply.data()); reply->deleteLater();
return false; return false;
} }
// make shore we can read the file // make shore we can read the file
if (!file.isReadable()) { if (!file.isReadable()) {
qCWarning(dcWebServer) << "requested file" << file.fileName() << "is not readable."; qCWarning(dcWebServer) << "requested file" << file.fileName() << "is not readable.";
HttpReply reply(HttpReply::Forbidden); HttpReply *reply = RestResource::createErrorReply(HttpReply::Forbidden);
reply.setPayload("403 Forbidden. Page not readable."); reply->setClientId(m_clientList.key(socket));
reply.packReply(); reply->setPayload("403 Forbidden. File not readable");
writeData(socket, reply.data()); sendHttpReply(reply);
reply->deleteLater();
return false; return false;
} }
return true; return true;
@ -192,11 +198,6 @@ QString WebServer::fileName(const QString &query)
return m_webinterfaceDir.path() + fileName; return m_webinterfaceDir.path() + fileName;
} }
void WebServer::writeData(QSslSocket *socket, const QByteArray &data)
{
socket->write(data + "\r\n");
}
void WebServer::incomingConnection(qintptr socketDescriptor) void WebServer::incomingConnection(qintptr socketDescriptor)
{ {
if (!m_enabled) if (!m_enabled)
@ -283,25 +284,29 @@ void WebServer::readClient()
request = HttpRequest(data); request = HttpRequest(data);
} }
// check if the request is complete
if (!request.isComplete()) { if (!request.isComplete()) {
m_incompleteRequests.insert(socket, request); m_incompleteRequests.insert(socket, request);
return; return;
} }
// check if the request is valid
if (!request.isValid()) { if (!request.isValid()) {
qCWarning(dcWebServer) << "Got invalid request."; qCWarning(dcWebServer) << "Got invalid request.";
HttpReply reply(HttpReply::BadRequest); HttpReply *reply = RestResource::createErrorReply(HttpReply::BadRequest);
reply.setPayload("400 Bad Request."); reply->setClientId(clientId);
writeData(socket, reply.data()); sendHttpReply(reply);
reply->deleteLater();
return; return;
} }
// verify HTTP version // check HTTP version
if (request.httpVersion() != "HTTP/1.1") { if (request.httpVersion() != "HTTP/1.1") {
qCWarning(dcWebServer) << "HTTP version is not supported." ; qCWarning(dcWebServer) << "HTTP version is not supported.";
HttpReply reply(HttpReply::HttpVersionNotSupported); HttpReply *reply = RestResource::createErrorReply(HttpReply::HttpVersionNotSupported);
reply.setPayload("505 HTTP version is not supported."); reply->setClientId(clientId);
writeData(socket, reply.data()); sendHttpReply(reply);
reply->deleteLater();
return; return;
} }
@ -318,10 +323,11 @@ void WebServer::readClient()
// verify method // verify method
if (request.method() == HttpRequest::Unhandled) { if (request.method() == HttpRequest::Unhandled) {
HttpReply reply(HttpReply::MethodNotAllowed); HttpReply *reply = RestResource::createErrorReply(HttpReply::MethodNotAllowed);
reply.setHeader(HttpReply::AllowHeader, "GET, PUT, POST, DELETE, OPTIONS"); reply->setClientId(clientId);
reply.setPayload("405 Method not allowed."); reply->setHeader(HttpReply::AllowHeader, "GET, PUT, POST, DELETE, OPTIONS");
writeData(socket, reply.data()); sendHttpReply(reply);
reply->deleteLater();
return; return;
} }
@ -340,21 +346,24 @@ void WebServer::readClient()
QFile file(path); QFile file(path);
if (file.open(QFile::ReadOnly | QFile::Truncate)) { if (file.open(QFile::ReadOnly | QFile::Truncate)) {
qCDebug(dcWebServer) << "load file" << file.fileName(); qCDebug(dcWebServer) << "load file" << file.fileName();
HttpReply reply(HttpReply::Ok); HttpReply *reply = RestResource::createSuccessReply();
if (file.fileName().endsWith(".html")) { if (file.fileName().endsWith(".html")) {
reply.setHeader(HttpReply::ContentTypeHeader, "text/html; charset=\"utf-8\";"); reply->setHeader(HttpReply::ContentTypeHeader, "text/html; charset=\"utf-8\";");
} }
reply.setPayload(file.readAll()); reply->setPayload(file.readAll());
writeData(socket, reply.data()); reply->setClientId(clientId);
sendHttpReply(reply);
reply->deleteLater();
return; return;
} }
} }
// reject everything else... // reject everything else...
qCWarning(dcWebServer) << "Unknown message received. Respond client with 400: Not Implemented."; qCWarning(dcWebServer) << "Unknown message received. Respond client with 501: Not Implemented.";
HttpReply reply(HttpReply::NotFound); HttpReply *reply = RestResource::createErrorReply(HttpReply::NotImplemented);
reply.setPayload("404 Not found."); reply->setClientId(clientId);
writeData(socket, reply.data()); sendHttpReply(reply);
reply->deleteLater();
} }
void WebServer::onDisconnected() void WebServer::onDisconnected()

View File

@ -88,8 +88,6 @@ private:
bool verifyFile(QSslSocket *socket, const QString &fileName); bool verifyFile(QSslSocket *socket, const QString &fileName);
QString fileName(const QString &query); QString fileName(const QString &query);
void writeData(QSslSocket *socket, const QByteArray &data);
protected: protected:
void incomingConnection(qintptr socketDescriptor) override; void incomingConnection(qintptr socketDescriptor) override;

View File

@ -419,7 +419,7 @@ void TestRestDevices::editDevices()
QNetworkRequest request(QUrl(QString("http://localhost:3333/api/v1/devices"))); QNetworkRequest request(QUrl(QString("http://localhost:3333/api/v1/devices")));
QNetworkReply *reply = nam->post(request, QJsonDocument::fromVariant(params).toJson(QJsonDocument::Compact)); QNetworkReply *reply = nam->post(request, QJsonDocument::fromVariant(params).toJson());
clientSpy.wait(); clientSpy.wait();
QCOMPARE(clientSpy.count(), 1); QCOMPARE(clientSpy.count(), 1);

View File

@ -142,11 +142,10 @@ void TestWebserver::multiPackageMessage()
bool ok = false; bool ok = false;
int statusCode = firstLineTokens.at(1).toInt(&ok); int statusCode = firstLineTokens.at(1).toInt(&ok);
QVERIFY2(ok, "Could not convert statuscode from response to int"); QVERIFY2(ok, "Could not convert statuscode from response to int");
QCOMPARE(statusCode, 404); QCOMPARE(statusCode, 501);
socket->close(); socket->close();
socket->deleteLater(); socket->deleteLater();
} }
void TestWebserver::checkAllowedMethodCall_data() void TestWebserver::checkAllowedMethodCall_data()
@ -205,7 +204,6 @@ void TestWebserver::checkAllowedMethodCall()
printResponse(reply); printResponse(reply);
QCOMPARE(clientSpy.count(), 1); QCOMPARE(clientSpy.count(), 1);
//QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
if (expectedStatusCode == 405){ if (expectedStatusCode == 405){
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), expectedStatusCode); QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), expectedStatusCode);