Update webserver debug output, add WebServerTraffic category and fix favicons for debugserver

This commit is contained in:
Simon Stürz 2019-01-09 12:23:47 +01:00 committed by Michael Zanetti
parent b9dda16af9
commit e51508ee33
9 changed files with 145 additions and 99 deletions

View File

@ -11,5 +11,18 @@
<file>favicons/favicon-196x196.png</file> <file>favicons/favicon-196x196.png</file>
<file>favicons/favicon.ico</file> <file>favicons/favicon.ico</file>
<file>favicons/favicon.svg</file> <file>favicons/favicon.svg</file>
<file>favicons/mstile-70x70.png</file>
<file>favicons/mstile-144x144.png</file>
<file>favicons/mstile-150x150.png</file>
<file>favicons/mstile-310x150.png</file>
<file>favicons/mstile-310x310.png</file>
<file>favicons/apple-touch-icon-152x152.png</file>
<file>favicons/apple-touch-icon-144x144.png</file>
<file>favicons/apple-touch-icon-57x57.png</file>
<file>favicons/apple-touch-icon-60x60.png</file>
<file>favicons/apple-touch-icon-72x72.png</file>
<file>favicons/apple-touch-icon-76x76.png</file>
<file>favicons/apple-touch-icon-114x114.png</file>
<file>favicons/apple-touch-icon-120x120.png</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -161,7 +161,7 @@ HttpReply::HttpReply(QObject *parent) :
setHeader(HttpHeaderType::CacheControlHeader, "no-cache"); setHeader(HttpHeaderType::CacheControlHeader, "no-cache");
setHeader(HttpHeaderType::ConnectionHeader, "Keep-Alive"); setHeader(HttpHeaderType::ConnectionHeader, "Keep-Alive");
setRawHeader("Access-Control-Allow-Origin","*"); setRawHeader("Access-Control-Allow-Origin","*");
setRawHeader("Keep-Alive", "timeout=12, max=50"); setRawHeader("Keep-Alive", QString("timeout=%1, max=50").arg(m_timeout).toUtf8());
packReply(); packReply();
} }
@ -184,7 +184,7 @@ HttpReply::HttpReply(const HttpReply::HttpStatusCode &statusCode, const HttpRepl
setHeader(HttpHeaderType::CacheControlHeader, "no-cache"); setHeader(HttpHeaderType::CacheControlHeader, "no-cache");
setHeader(HttpHeaderType::ConnectionHeader, "Keep-Alive"); setHeader(HttpHeaderType::ConnectionHeader, "Keep-Alive");
setRawHeader("Access-Control-Allow-Origin","*"); setRawHeader("Access-Control-Allow-Origin","*");
setRawHeader("Keep-Alive", "timeout=12, max=50"); setRawHeader("Keep-Alive", QString("timeout=%1, max=50").arg(m_timeout).toUtf8());
packReply(); packReply();
} }
@ -326,7 +326,7 @@ void HttpReply::packReply()
} }
m_rawHeader.append("\r\n"); m_rawHeader.append("\r\n");
m_data = m_rawHeader.append(m_payload); m_data = QByteArray(m_rawHeader).append(m_payload);
} }
/*! Returns the current raw data (header + payload) of this \l{HttpReply}.*/ /*! Returns the current raw data (header + payload) of this \l{HttpReply}.*/
@ -343,72 +343,101 @@ bool HttpReply::timedOut() const
QByteArray HttpReply::getHttpReasonPhrase(const HttpReply::HttpStatusCode &statusCode) QByteArray HttpReply::getHttpReasonPhrase(const HttpReply::HttpStatusCode &statusCode)
{ {
QByteArray response;
switch (statusCode) { switch (statusCode) {
case HttpStatusCode::Ok: case HttpStatusCode::Ok:
return "Ok"; response = QString("Ok").toUtf8();
break;
case Created: case Created:
return "Created"; response = QString("Created").toUtf8();
break;
case Accepted: case Accepted:
return "Accepted"; response = QString("Accepted").toUtf8();
break;
case NoContent: case NoContent:
return "No Content"; response = QString("No Content").toUtf8();
break;
case Found: case Found:
return "Found"; response = QString("Found").toUtf8();
break;
case PermanentRedirect: case PermanentRedirect:
return "Permanent Redirect"; response = QString("Permanent Redirect").toUtf8();
break;
case BadRequest: case BadRequest:
return "Bad Request"; response = QString("Bad Request").toUtf8();
break;
case Forbidden: case Forbidden:
return "Forbidden"; response = QString("Forbidden").toUtf8();
break;
case NotFound: case NotFound:
return "NotFound"; response = QString("NotFound").toUtf8();
break;
case MethodNotAllowed: case MethodNotAllowed:
return "Method Not Allowed"; response = QString("Method Not Allowed").toUtf8();
break;
case RequestTimeout: case RequestTimeout:
return "Request Timeout"; response = QString("Request Timeout").toUtf8();
break;
case Conflict: case Conflict:
return "Conflict"; response = QString("Conflict").toUtf8();
break;
case InternalServerError: case InternalServerError:
return "Internal Server Error"; response = QString("Internal Server Error").toUtf8();
break;
case NotImplemented: case NotImplemented:
return "Not Implemented"; response = QString("Not Implemented").toUtf8();
break;
case BadGateway: case BadGateway:
return "Bad Gateway"; response = QString("Bad Gateway").toUtf8();
break;
case ServiceUnavailable: case ServiceUnavailable:
return "Service Unavailable"; response = QString("Service Unavailable").toUtf8();
break;
case GatewayTimeout: case GatewayTimeout:
return "Gateway Timeout"; response = QString("Gateway Timeout").toUtf8();
break;
case HttpVersionNotSupported: case HttpVersionNotSupported:
return "HTTP Version Not Supported"; response = QString("HTTP Version Not Supported").toUtf8();
default: break;
return QByteArray();
} }
return response;
} }
QByteArray HttpReply::getHeaderType(const HttpReply::HttpHeaderType &headerType) QByteArray HttpReply::getHeaderType(const HttpReply::HttpHeaderType &headerType)
{ {
QByteArray header;
switch (headerType) { switch (headerType) {
case ContentTypeHeader: case ContentTypeHeader:
return "Content-Type"; header = QString("Content-Type").toUtf8();
break;
case ContentLenghtHeader: case ContentLenghtHeader:
return "Content-Length"; header = QString("Content-Length").toUtf8();
break;
case CacheControlHeader: case CacheControlHeader:
return "Cache-Control"; header = QString("Cache-Control").toUtf8();
break;
case LocationHeader: case LocationHeader:
return "Location"; header = QString("Location").toUtf8();
break;
case ConnectionHeader: case ConnectionHeader:
return "Connection"; header = QString("Connection").toUtf8();
break;
case UserAgentHeader: case UserAgentHeader:
return "User-Agent"; header = QString("User-Agent").toUtf8();
break;
case AllowHeader: case AllowHeader:
return "Allow"; header = QString("Allow").toUtf8();
break;
case DateHeader: case DateHeader:
return "Date"; header = QString("Date").toUtf8();
break;
case ServerHeader: case ServerHeader:
return "Server"; header = QString("Server").toUtf8();
default: break;
return QByteArray();
} }
return header;
} }
/*! Starts the timer for an async \l{HttpReply}. /*! Starts the timer for an async \l{HttpReply}.
@ -417,24 +446,22 @@ QByteArray HttpReply::getHeaderType(const HttpReply::HttpHeaderType &headerType)
*/ */
void HttpReply::startWait() void HttpReply::startWait()
{ {
m_timer->start(60000); m_timer->start(m_timeout);
} }
void HttpReply::timeout() void HttpReply::timeout()
{ {
qCDebug(dcWebServer) << "Http reply timeout"; qCDebug(dcWebServer()) << "Http reply timeout";
m_timedOut = true; m_timedOut = true;
emit finished(); emit finished();
} }
QDebug operator<<(QDebug debug, const HttpReply &httpReply) QDebug operator<<(QDebug debug, HttpReply *httpReply)
{ {
debug << "-----------------------------------" << "\n"; debug.nospace() << "HttpReply(" << httpReply->clientId().toString() << ")" << endl;
debug << httpReply.rawHeader() << "\n"; debug << qUtf8Printable(httpReply->rawHeader());
debug << "-----------------------------------" << "\n"; debug << qUtf8Printable(httpReply->payload());
debug << httpReply.payload() << "\n"; return debug.space();
debug << "-----------------------------------" << "\n";
return debug;
} }
} }

View File

@ -121,7 +121,8 @@ private:
bool m_closeConnection; bool m_closeConnection;
QTimer *m_timer; QTimer *m_timer = nullptr;
int m_timeout = 60000;
bool m_timedOut; bool m_timedOut;
QByteArray getHttpReasonPhrase(const HttpStatusCode &statusCode); QByteArray getHttpReasonPhrase(const HttpStatusCode &statusCode);
@ -138,7 +139,7 @@ signals:
}; };
QDebug operator<< (QDebug debug, const HttpReply &httpReply); QDebug operator<<(QDebug debug, HttpReply *httpReply);
} }

View File

@ -172,7 +172,7 @@ void HttpRequest::validate()
// split the data into header and payload // split the data into header and payload
int headerEndIndex = m_rawData.indexOf("\r\n\r\n"); int headerEndIndex = m_rawData.indexOf("\r\n\r\n");
if (headerEndIndex < 0) { if (headerEndIndex < 0) {
qCWarning(dcWebServer) << "Could not parse end of HTTP header (empty line between header and body):" << m_rawData; qCWarning(dcWebServer()) << "Could not parse end of HTTP header (empty line between header and body):" << m_rawData;
return; return;
} }
@ -184,14 +184,14 @@ void HttpRequest::validate()
QString statusLine = headerLines.takeFirst(); QString statusLine = headerLines.takeFirst();
QStringList statusLineTokens = statusLine.split(QRegExp("[ \r\n][ \r\n]*")); QStringList statusLineTokens = statusLine.split(QRegExp("[ \r\n][ \r\n]*"));
if (statusLineTokens.count() != 3) { if (statusLineTokens.count() != 3) {
qCWarning(dcWebServer) << "Could not parse HTTP status line:" << statusLine; qCWarning(dcWebServer()) << "Could not parse HTTP status line:" << statusLine;
return; return;
} }
// verify http version // verify http version
m_httpVersion = statusLineTokens.at(2).toUtf8().simplified(); m_httpVersion = statusLineTokens.at(2).toUtf8().simplified();
if (!m_httpVersion.contains("HTTP")) { if (!m_httpVersion.contains("HTTP")) {
qCWarning(dcWebServer) << "Unknown HTTP version:" << m_httpVersion; qCWarning(dcWebServer()) << "Unknown HTTP version:" << m_httpVersion;
return; return;
} }
m_methodString = statusLineTokens.at(0).simplified(); m_methodString = statusLineTokens.at(0).simplified();
@ -205,7 +205,7 @@ void HttpRequest::validate()
// verify header formating // verify header formating
foreach (const QString &line, headerLines) { foreach (const QString &line, headerLines) {
if (!line.contains(":")) { if (!line.contains(":")) {
qCWarning(dcWebServer) << "Invalid HTTP header:" << line; qCWarning(dcWebServer()) << "Invalid HTTP header:" << line;
return; return;
} }
int index = line.indexOf(":"); int index = line.indexOf(":");
@ -216,7 +216,7 @@ void HttpRequest::validate()
// check User-Agent // check User-Agent
if (!m_rawHeaderList.contains("User-Agent")) if (!m_rawHeaderList.contains("User-Agent"))
qCWarning(dcWebServer) << "User-Agent header is missing"; qCWarning(dcWebServer()) << "User-Agent header is missing";
// verify content length with actual payload // verify content length with actual payload
@ -224,22 +224,22 @@ void HttpRequest::validate()
bool ok = false; bool ok = false;
int contentLength = m_rawHeaderList.value("Content-Length").toInt(&ok); int contentLength = m_rawHeaderList.value("Content-Length").toInt(&ok);
if (!ok) { if (!ok) {
qCWarning(dcWebServer) << "Could not parse Content-Length."; qCWarning(dcWebServer()) << "Could not parse Content-Length.";
return; return;
} }
// check if we have all data // check if we have all data
if (m_payload.size() < contentLength) { if (m_payload.size() < contentLength) {
qCDebug(dcWebServer) << "Request incomplete:"; qCDebug(dcWebServer()) << "Request incomplete:";
qCDebug(dcWebServer) << " -> Content-Length:" << contentLength; qCDebug(dcWebServer()) << " -> Content-Length:" << contentLength;
qCDebug(dcWebServer) << " -> Payload size :" << payload().size(); qCDebug(dcWebServer()) << " -> Payload size :" << payload().size();
m_isComplete = false; m_isComplete = false;
return; return;
} }
// check if the content length bigger than header Content-Length // check if the content length bigger than header Content-Length
if (m_payload.size() > contentLength) { if (m_payload.size() > contentLength) {
qCWarning(dcWebServer) << "Payload size greater than header Content-Length:"; qCWarning(dcWebServer()) << "Payload size greater than header Content-Length:";
qCWarning(dcWebServer) << " -> Content-Length:" << contentLength; qCWarning(dcWebServer()) << " -> Content-Length:" << contentLength;
qCWarning(dcWebServer) << " -> Payload size :" << payload().size(); qCWarning(dcWebServer()) << " -> Payload size :" << payload().size();
m_isComplete = true; m_isComplete = true;
return; return;
} }
@ -261,23 +261,15 @@ HttpRequest::RequestMethod HttpRequest::getRequestMethodType(const QString &meth
} else if (methodString == "OPTIONS") { } else if (methodString == "OPTIONS") {
return RequestMethod::Options; return RequestMethod::Options;
} }
qCWarning(dcWebServer) << "Method" << methodString << "will not be handled."; qCWarning(dcWebServer()) << "Method" << methodString << "will not be handled.";
return RequestMethod::Unhandled; return RequestMethod::Unhandled;
} }
QDebug operator<<(QDebug debug, const HttpRequest &httpRequest) QDebug operator<<(QDebug debug, const HttpRequest &httpRequest)
{ {
debug << "===================================" << "\n"; debug << "HttpRequest:" << endl;
debug << " HTTP version: " << httpRequest.httpVersion() << "\n"; debug << qUtf8Printable(httpRequest.rawHeader());
debug << " method: " << httpRequest.methodString() << "\n"; debug << qUtf8Printable(httpRequest.payload());
debug << " URL path: " << httpRequest.url().path() << "\n";
debug << " URL query: " << httpRequest.urlQuery().query() << "\n";
debug << " is valid: " << httpRequest.isValid() << "\n";
debug << "-----------------------------------" << "\n";
debug << httpRequest.rawHeader() << "\n";
debug << "-----------------------------------" << "\n";
debug << httpRequest.payload() << "\n";
debug << "-----------------------------------" << "\n";
return debug; return debug;
} }

View File

@ -151,7 +151,7 @@ void RestServer::asyncReplyFinished()
HttpReply *reply = qobject_cast<HttpReply*>(sender()); HttpReply *reply = qobject_cast<HttpReply*>(sender());
if (!m_asyncReplies.values().contains(reply)) { if (!m_asyncReplies.values().contains(reply)) {
qCWarning(dcWebServer) << "Reply for async request does no longer exist"; qCWarning(dcWebServer()) << "Reply for async request does no longer exist";
reply->deleteLater(); reply->deleteLater();
return; return;
} }
@ -159,7 +159,7 @@ void RestServer::asyncReplyFinished()
QUuid clientId = m_asyncReplies.key(reply); QUuid clientId = m_asyncReplies.key(reply);
m_asyncReplies.remove(clientId); m_asyncReplies.remove(clientId);
qCDebug(dcWebServer) << "Async reply finished"; qCDebug(dcWebServer()) << "Async reply finished";
// check if the reply timeouted // check if the reply timeouted
if (reply->timedOut()) { if (reply->timedOut()) {
@ -169,7 +169,7 @@ void RestServer::asyncReplyFinished()
// check if client is still connected // check if client is still connected
if (!m_clientList.contains(clientId)) { if (!m_clientList.contains(clientId)) {
qCWarning(dcWebServer) << "Client for async reply not longer connected."; qCWarning(dcWebServer()) << "Client for async reply not longer connected.";
} else { } else {
reply->setClientId(clientId); reply->setClientId(clientId);
WebServer *webserver = m_clientList.value(clientId); WebServer *webserver = m_clientList.value(clientId);

View File

@ -105,7 +105,7 @@ WebServer::WebServer(const WebServerConfiguration &configuration, const QSslConf
if (QCoreApplication::instance()->organizationName() == "nymea-test") { if (QCoreApplication::instance()->organizationName() == "nymea-test") {
m_configuration.publicFolder = QCoreApplication::applicationDirPath(); m_configuration.publicFolder = QCoreApplication::applicationDirPath();
} }
qCDebug(dcWebServer) << "Starting WebServer. Interface:" << m_configuration.address << "Port:" << m_configuration.port << "SSL:" << m_configuration.sslEnabled << "AUTH:" << m_configuration.authenticationEnabled << "Public folder:" << QDir(m_configuration.publicFolder).canonicalPath(); qCDebug(dcWebServer()) << "Starting WebServer. Interface:" << m_configuration.address << "Port:" << m_configuration.port << "SSL:" << m_configuration.sslEnabled << "AUTH:" << m_configuration.authenticationEnabled << "Public folder:" << QDir(m_configuration.publicFolder).canonicalPath();
m_avahiService = new QtAvahiService(this); m_avahiService = new QtAvahiService(this);
connect(m_avahiService, &QtAvahiService::serviceStateChanged, this, &WebServer::onAvahiServiceStateChanged); connect(m_avahiService, &QtAvahiService::serviceStateChanged, this, &WebServer::onAvahiServiceStateChanged);
@ -135,13 +135,14 @@ void WebServer::sendHttpReply(HttpReply *reply)
QSslSocket *socket = nullptr; QSslSocket *socket = nullptr;
socket = m_clientList.value(reply->clientId()); socket = m_clientList.value(reply->clientId());
if (!socket) { if (!socket) {
qCWarning(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;
} }
// send raw data // send raw data
reply->packReply(); reply->packReply();
qCDebug(dcWebServer) << "Respond" << reply->httpStatusCode() << reply->httpReasonPhrase(); qCDebug(dcWebServerTraffic()) << "Send reply to" << socket->peerAddress().toString() << reply;
qCDebug(dcWebServer()) << "Respond" << socket->peerAddress().toString() << reply->httpStatusCode() << reply->httpReasonPhrase();
socket->write(reply->data()); socket->write(reply->data());
} }
@ -151,7 +152,7 @@ bool WebServer::verifyFile(QSslSocket *socket, const QString &fileName)
// make sure the file exists // make sure 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 = RestResource::createErrorReply(HttpReply::NotFound); HttpReply *reply = RestResource::createErrorReply(HttpReply::NotFound);
reply->setClientId(m_clientList.key(socket)); reply->setClientId(m_clientList.key(socket));
sendHttpReply(reply); sendHttpReply(reply);
@ -161,7 +162,7 @@ bool WebServer::verifyFile(QSslSocket *socket, const QString &fileName)
// make sure the file is in the public directory // make sure the file is in the public directory
if (!file.canonicalFilePath().startsWith(QDir(m_configuration.publicFolder).canonicalPath())) { if (!file.canonicalFilePath().startsWith(QDir(m_configuration.publicFolder).canonicalPath())) {
qCWarning(dcWebServer) << "Requested file" << file.fileName() << "is outside the public folder."; qCWarning(dcWebServer()) << "Requested file" << file.fileName() << "is outside the public folder.";
HttpReply *reply = RestResource::createErrorReply(HttpReply::Forbidden); HttpReply *reply = RestResource::createErrorReply(HttpReply::Forbidden);
reply->setClientId(m_clientList.key(socket)); reply->setClientId(m_clientList.key(socket));
sendHttpReply(reply); sendHttpReply(reply);
@ -171,7 +172,7 @@ bool WebServer::verifyFile(QSslSocket *socket, const QString &fileName)
// make sure we can read the file // make sure 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 = RestResource::createErrorReply(HttpReply::Forbidden); HttpReply *reply = RestResource::createErrorReply(HttpReply::Forbidden);
reply->setClientId(m_clientList.key(socket)); reply->setClientId(m_clientList.key(socket));
reply->setPayload("403 Forbidden. File not readable"); reply->setPayload("403 Forbidden. File not readable");
@ -234,7 +235,7 @@ void WebServer::incomingConnection(qintptr socketDescriptor)
foreach (WebServerClient *client, m_webServerClients) { foreach (WebServerClient *client, m_webServerClients) {
if (client->address() == socket->peerAddress()) { if (client->address() == socket->peerAddress()) {
if (client->connections().count() >= 50) { if (client->connections().count() >= 50) {
qCWarning(dcWebServer()) << QString("Maximum connections for this client reached: rejecting connection from client %1:%2").arg(socket->peerAddress().toString()).arg(socket->peerPort()); qCWarning(dcWebServer()).noquote() << QString("Maximum connections for this client reached: rejecting connection from client %1:%2").arg(socket->peerAddress().toString()).arg(socket->peerPort());
socket->close(); socket->close();
delete socket; delete socket;
return; return;
@ -255,7 +256,7 @@ void WebServer::incomingConnection(qintptr socketDescriptor)
QUuid clientId = QUuid::createUuid(); QUuid clientId = QUuid::createUuid();
m_clientList.insert(clientId, socket); m_clientList.insert(clientId, socket);
qCDebug(dcWebServer()) << QString("Webserver client %1:%2 connected").arg(socket->peerAddress().toString()).arg(socket->peerPort()); qCDebug(dcWebServer()).noquote() << QString("Webserver client %1:%2 connected").arg(socket->peerAddress().toString()).arg(socket->peerPort());
if (m_configuration.sslEnabled) { if (m_configuration.sslEnabled) {
// configure client connection // configure client connection
@ -283,7 +284,7 @@ void WebServer::readClient()
// Check client // Check client
if (clientId.isNull()) { if (clientId.isNull()) {
qCWarning(dcWebServer) << "Client not recognized"; qCWarning(dcWebServer()) << "Client not recognized";
socket->close(); socket->close();
return; return;
} }
@ -293,7 +294,7 @@ void WebServer::readClient()
HttpRequest request; HttpRequest request;
if (m_incompleteRequests.contains(socket)) { if (m_incompleteRequests.contains(socket)) {
qCDebug(dcWebServer) << "Append data to incomlete request"; qCDebug(dcWebServer()) << "Append data to incomlete request";
request = m_incompleteRequests.take(socket); request = m_incompleteRequests.take(socket);
request.appendData(data); request.appendData(data);
} else { } else {
@ -306,9 +307,11 @@ void WebServer::readClient()
return; return;
} }
qCDebug(dcWebServerTraffic()) << "Received request from" << clientId.toString() << socket->peerAddress().toString() << request;
// Check if the request is valid // Check if the request is valid
if (!request.isValid()) { if (!request.isValid()) {
qCWarning(dcWebServer) << "Got invalid request:" << request.url().path(); qCWarning(dcWebServer()) << "Got invalid request:" << request.url().path();
HttpReply *reply = RestResource::createErrorReply(HttpReply::BadRequest); HttpReply *reply = RestResource::createErrorReply(HttpReply::BadRequest);
reply->setClientId(clientId); reply->setClientId(clientId);
sendHttpReply(reply); sendHttpReply(reply);
@ -318,7 +321,7 @@ void WebServer::readClient()
// Check HTTP version // Check HTTP version
if (request.httpVersion() != "HTTP/1.1" && request.httpVersion() != "HTTP/1.0") { if (request.httpVersion() != "HTTP/1.1" && request.httpVersion() != "HTTP/1.0") {
qCWarning(dcWebServer) << "HTTP version is not supported." << request.httpVersion(); qCWarning(dcWebServer()) << "HTTP version is not supported." << request.httpVersion();
HttpReply *reply = RestResource::createErrorReply(HttpReply::HttpVersionNotSupported); HttpReply *reply = RestResource::createErrorReply(HttpReply::HttpVersionNotSupported);
reply->setClientId(clientId); reply->setClientId(clientId);
sendHttpReply(reply); sendHttpReply(reply);
@ -326,8 +329,7 @@ void WebServer::readClient()
return; return;
} }
qCDebug(dcWebServer) << QString("Got valid request from %1:%2").arg(socket->peerAddress().toString()).arg(socket->peerPort()); qCDebug(dcWebServer()).noquote() << QString("Got valid request from %1:%2").arg(socket->peerAddress().toString()).arg(socket->peerPort()) << request.methodString() << request.url().path() << request.urlQuery().toString();
qCDebug(dcWebServer) << request.methodString() << request.url().path();
// Reset timout // Reset timout
foreach (WebServerClient *webserverClient, m_webServerClients) { foreach (WebServerClient *webserverClient, m_webServerClients) {
@ -410,7 +412,7 @@ void WebServer::readClient()
// Check server.xml call // Check server.xml call
if (request.url().path() == "/server.xml" && request.method() == HttpRequest::Get) { if (request.url().path() == "/server.xml" && request.method() == HttpRequest::Get) {
qCDebug(dcWebServer) << "Server XML request call"; qCDebug(dcWebServer()) << "Server XML request call";
HttpReply *reply = RestResource::createSuccessReply(); HttpReply *reply = RestResource::createSuccessReply();
reply->setHeader(HttpReply::ContentTypeHeader, "text/xml"); reply->setHeader(HttpReply::ContentTypeHeader, "text/xml");
reply->setPayload(createServerXmlDocument(socket->localAddress())); reply->setPayload(createServerXmlDocument(socket->localAddress()));
@ -424,8 +426,9 @@ void WebServer::readClient()
// Request for a file... // Request for a file...
if (request.method() == HttpRequest::Get) { if (request.method() == HttpRequest::Get) {
// Check if the webinterface dir does exist, otherwise a filerequest is not relevant // Check if the webinterface dir does exist, otherwise a filerequest is not relevant
// FIXME: return a default webpage containing server information
if (!QDir(m_configuration.publicFolder).exists()) { if (!QDir(m_configuration.publicFolder).exists()) {
qCWarning(dcWebServer) << "Webinterface folder" << m_configuration.publicFolder << "does not exist."; qCWarning(dcWebServer()) << "Webinterface folder" << m_configuration.publicFolder << "does not exist.";
HttpReply *reply = RestResource::createErrorReply(HttpReply::NotFound); HttpReply *reply = RestResource::createErrorReply(HttpReply::NotFound);
reply->setClientId(clientId); reply->setClientId(clientId);
sendHttpReply(reply); sendHttpReply(reply);
@ -439,7 +442,7 @@ 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 = RestResource::createSuccessReply(); HttpReply *reply = RestResource::createSuccessReply();
// Check content type // Check content type
@ -476,7 +479,7 @@ void WebServer::readClient()
} }
// Reject everything else... // Reject everything else...
qCWarning(dcWebServer) << "Unknown message received."; qCWarning(dcWebServer()) << "Unknown message received.";
HttpReply *reply = RestResource::createErrorReply(HttpReply::NotImplemented); HttpReply *reply = RestResource::createErrorReply(HttpReply::NotImplemented);
reply->setClientId(clientId); reply->setClientId(clientId);
sendHttpReply(reply); sendHttpReply(reply);
@ -492,7 +495,7 @@ void WebServer::onDisconnected()
if (client->address() == socket->peerAddress()) { if (client->address() == socket->peerAddress()) {
client->removeConnection(socket); client->removeConnection(socket);
if (client->connections().isEmpty()) { if (client->connections().isEmpty()) {
qCDebug(dcWebServer) << "Delete client" << client->address().toString(); qCDebug(dcWebServer()) << "Delete client" << client->address().toString();
m_webServerClients.removeAll(client); m_webServerClients.removeAll(client);
client->deleteLater(); client->deleteLater();
} }
@ -500,7 +503,7 @@ void WebServer::onDisconnected()
} }
} }
qCDebug(dcWebServer) << QString("Webserver client disonnected %1:%2").arg(socket->peerAddress().toString()).arg(socket->peerPort()); qCDebug(dcWebServer()).noquote() << QString("Webserver client disonnected %1:%2").arg(socket->peerAddress().toString()).arg(socket->peerPort());
// clean up // clean up
QUuid clientId = m_clientList.key(socket); QUuid clientId = m_clientList.key(socket);
@ -514,7 +517,7 @@ void WebServer::onDisconnected()
void WebServer::onEncrypted() void WebServer::onEncrypted()
{ {
QSslSocket* socket = static_cast<QSslSocket *>(sender()); QSslSocket* socket = static_cast<QSslSocket *>(sender());
qCDebug(dcWebServer()) << QString("Encrypted connection %1:%2 successfully established.").arg(socket->peerAddress().toString()).arg(socket->peerPort()); qCDebug(dcWebServer()).noquote() << QString("Encrypted connection %1:%2 successfully established.").arg(socket->peerAddress().toString()).arg(socket->peerPort());
connect(socket, SIGNAL(readyRead()), this, SLOT(readClient())); connect(socket, SIGNAL(readyRead()), this, SLOT(readClient()));
connect(socket, SIGNAL(disconnected()), this, SLOT(onDisconnected())); connect(socket, SIGNAL(disconnected()), this, SLOT(onDisconnected()));
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError))); connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));
@ -524,15 +527,21 @@ void WebServer::onEncrypted()
void WebServer::onError(QAbstractSocket::SocketError error) void WebServer::onError(QAbstractSocket::SocketError error)
{ {
Q_UNUSED(error)
QSslSocket* socket = static_cast<QSslSocket *>(sender()); QSslSocket* socket = static_cast<QSslSocket *>(sender());
qCWarning(dcWebServer()) << QString("Client socket error %1:%2 ->").arg(socket->peerAddress().toString()).arg(socket->peerPort()) << socket->errorString(); switch (error) {
case QAbstractSocket::RemoteHostClosedError:
qCDebug(dcWebServer()).noquote() << QString("Client socket error %1:%2 ->").arg(socket->peerAddress().toString()).arg(socket->peerPort()) << socket->errorString();
break;
default:
qCWarning(dcWebServer()).noquote() << QString("Client socket error %1:%2 ->").arg(socket->peerAddress().toString()).arg(socket->peerPort()) << socket->errorString();
break;
}
} }
void WebServer::onAsyncReplyFinished() void WebServer::onAsyncReplyFinished()
{ {
HttpReply *reply = qobject_cast<HttpReply*>(sender()); HttpReply *reply = qobject_cast<HttpReply*>(sender());
qCDebug(dcWebServer) << "Async reply finished"; qCDebug(dcWebServer()) << "Async reply finished";
// check if the reply timeouted // check if the reply timeouted
if (reply->timedOut()) { if (reply->timedOut()) {
@ -818,13 +827,13 @@ QList<QSslSocket *> WebServerClient::connections()
/*! Adds a new connection (\a socket) to this \l{WebServerClient}. A \l{WebServerClient} /*! Adds a new connection (\a socket) to this \l{WebServerClient}. A \l{WebServerClient}
* can have up to 50 connecections. The connection will timout and closed if the client * can have up to 50 connecections. The connection will timout and closed if the client
* does not use the connection for 12 seconds. * does not use the connection for 65 seconds.
*/ */
void WebServerClient::addConnection(QSslSocket *socket) void WebServerClient::addConnection(QSslSocket *socket)
{ {
QTimer *timer = new QTimer(this); QTimer *timer = new QTimer(this);
timer->setSingleShot(true); timer->setSingleShot(true);
timer->setInterval(12000); timer->setInterval(65000);
connect(timer, &QTimer::timeout, this, &WebServerClient::onTimout); connect(timer, &QTimer::timeout, this, &WebServerClient::onTimout);
m_runningConnections.insert(timer, socket); m_runningConnections.insert(timer, socket);
@ -858,7 +867,8 @@ void WebServerClient::onTimout()
{ {
QTimer *timer = static_cast<QTimer *>(sender()); QTimer *timer = static_cast<QTimer *>(sender());
QSslSocket *socket = m_runningConnections.value(timer); QSslSocket *socket = m_runningConnections.value(timer);
qCDebug(dcWebServer) << QString("Client connection timout %1:%2 -> closing connection").arg(socket->peerAddress().toString()).arg(socket->peerPort()); qCDebug(dcWebServer()).noquote() << QString("Client connection timout %1:%2 -> closing connection").arg(socket->peerAddress().toString()).arg(socket->peerPort());
removeConnection(socket);
socket->close(); socket->close();
} }

View File

@ -33,6 +33,7 @@ Q_LOGGING_CATEGORY(dcLogEngine, "LogEngine")
Q_LOGGING_CATEGORY(dcTcpServer, "TcpServer") Q_LOGGING_CATEGORY(dcTcpServer, "TcpServer")
Q_LOGGING_CATEGORY(dcTcpServerTraffic, "TcpServerTraffic") Q_LOGGING_CATEGORY(dcTcpServerTraffic, "TcpServerTraffic")
Q_LOGGING_CATEGORY(dcWebServer, "WebServer") Q_LOGGING_CATEGORY(dcWebServer, "WebServer")
Q_LOGGING_CATEGORY(dcWebServerTraffic, "WebServerTraffic")
Q_LOGGING_CATEGORY(dcDebugServer, "DebugServer") Q_LOGGING_CATEGORY(dcDebugServer, "DebugServer")
Q_LOGGING_CATEGORY(dcWebSocketServer, "WebSocketServer") Q_LOGGING_CATEGORY(dcWebSocketServer, "WebSocketServer")
Q_LOGGING_CATEGORY(dcWebSocketServerTraffic, "WebSocketServerTraffic") Q_LOGGING_CATEGORY(dcWebSocketServerTraffic, "WebSocketServerTraffic")

View File

@ -41,6 +41,7 @@ Q_DECLARE_LOGGING_CATEGORY(dcLogEngine)
Q_DECLARE_LOGGING_CATEGORY(dcTcpServer) Q_DECLARE_LOGGING_CATEGORY(dcTcpServer)
Q_DECLARE_LOGGING_CATEGORY(dcTcpServerTraffic) Q_DECLARE_LOGGING_CATEGORY(dcTcpServerTraffic)
Q_DECLARE_LOGGING_CATEGORY(dcWebServer) Q_DECLARE_LOGGING_CATEGORY(dcWebServer)
Q_DECLARE_LOGGING_CATEGORY(dcWebServerTraffic)
Q_DECLARE_LOGGING_CATEGORY(dcDebugServer) Q_DECLARE_LOGGING_CATEGORY(dcDebugServer)
Q_DECLARE_LOGGING_CATEGORY(dcWebSocketServer) Q_DECLARE_LOGGING_CATEGORY(dcWebSocketServer)
Q_DECLARE_LOGGING_CATEGORY(dcWebSocketServerTraffic) Q_DECLARE_LOGGING_CATEGORY(dcWebSocketServerTraffic)

View File

@ -111,6 +111,7 @@ int main(int argc, char *argv[])
"TcpServer", "TcpServer",
"TcpServerTraffic", "TcpServerTraffic",
"WebServer", "WebServer",
"WebServerTraffic",
"DebugServer", "DebugServer",
"WebSocketServer", "WebSocketServer",
"WebSocketServerTraffic", "WebSocketServerTraffic",