Add network test functionality and add live log viewer for debug server interface
@ -1,8 +1,15 @@
|
|||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="">
|
<qresource prefix="/">
|
||||||
<file>logo.svg</file>
|
<file>logo.svg</file>
|
||||||
<file>warning.svg</file>
|
<file>warning.svg</file>
|
||||||
|
<file>script.js</file>
|
||||||
<file>styles.css</file>
|
<file>styles.css</file>
|
||||||
|
<file>favicons/favicon-16x16.png</file>
|
||||||
|
<file>favicons/favicon-32x32.png</file>
|
||||||
|
<file>favicons/favicon-96x96.png</file>
|
||||||
|
<file>favicons/favicon-128.png</file>
|
||||||
|
<file>favicons/favicon-196x196.png</file>
|
||||||
|
<file>favicons/favicon.ico</file>
|
||||||
|
<file>favicons/favicon.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
||||||
|
|||||||
BIN
data/debug-interface/favicons/apple-touch-icon-114x114.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
data/debug-interface/favicons/apple-touch-icon-120x120.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
data/debug-interface/favicons/apple-touch-icon-144x144.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
data/debug-interface/favicons/apple-touch-icon-152x152.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
data/debug-interface/favicons/apple-touch-icon-57x57.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
data/debug-interface/favicons/apple-touch-icon-60x60.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
data/debug-interface/favicons/apple-touch-icon-72x72.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
data/debug-interface/favicons/apple-touch-icon-76x76.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
data/debug-interface/favicons/favicon-128.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
data/debug-interface/favicons/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 305 B |
BIN
data/debug-interface/favicons/favicon-196x196.png
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
data/debug-interface/favicons/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 615 B |
BIN
data/debug-interface/favicons/favicon-96x96.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
data/debug-interface/favicons/favicon.ico
Normal file
|
After Width: | Height: | Size: 34 KiB |
57
data/debug-interface/favicons/favicon.svg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
data/debug-interface/favicons/mstile-144x144.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
data/debug-interface/favicons/mstile-150x150.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
data/debug-interface/favicons/mstile-310x150.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
data/debug-interface/favicons/mstile-310x310.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
data/debug-interface/favicons/mstile-70x70.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
152
data/debug-interface/script.js
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2018 Simon Stürz <simon.stuerz@guh.io> *
|
||||||
|
* *
|
||||||
|
* This file is part of nymea. *
|
||||||
|
* *
|
||||||
|
* nymea is free software: you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation, version 2 of the License. *
|
||||||
|
* *
|
||||||
|
* nymea is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with nymea. If not, see <http://www.gnu.org/licenses/>. *
|
||||||
|
* *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
|
||||||
|
/* ========================================================================*/
|
||||||
|
/* Websocket connection
|
||||||
|
/* ========================================================================*/
|
||||||
|
|
||||||
|
var webSocket = null;
|
||||||
|
|
||||||
|
function connectWebsocket() {
|
||||||
|
var urlString = "ws://" + window.location.hostname + ":2626"
|
||||||
|
console.log("Connecting to: " + urlString);
|
||||||
|
|
||||||
|
try {
|
||||||
|
webSocket = new WebSocket(urlString);
|
||||||
|
|
||||||
|
webSocket.onopen = function(openEvent) {
|
||||||
|
console.log("WebSocket connected: " + JSON.stringify(openEvent, null, 4));
|
||||||
|
document.getElementById("connectWebsocketButton").disabled = true;
|
||||||
|
document.getElementById("disconnectWebsocketButton").disabled = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
webSocket.onclose = function (closeEvent) {
|
||||||
|
console.log("WebSocket disconnected: " + JSON.stringify(closeEvent, null, 4));
|
||||||
|
document.getElementById("connectWebsocketButton").disabled = false;
|
||||||
|
document.getElementById("disconnectWebsocketButton").disabled = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
webSocket.onerror = function (errorEvent) {
|
||||||
|
console.log("WebSocket error: " + JSON.stringify(errorEvent, null, 4));
|
||||||
|
};
|
||||||
|
|
||||||
|
webSocket.onmessage = function (messageEvent) {
|
||||||
|
var message = messageEvent.data;
|
||||||
|
console.log("WebSocket data received: " + message);
|
||||||
|
document.getElementById("logsTextArea").value += message;
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (exception) {
|
||||||
|
console.error(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function disconnectWebsocket() {
|
||||||
|
console.log("Disconnecting from: " + webSocket.url);
|
||||||
|
webSocket.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ========================================================================*/
|
||||||
|
/* File download function
|
||||||
|
/* ========================================================================*/
|
||||||
|
|
||||||
|
function downloadFile(filePath, fileName) {
|
||||||
|
console.log("Download file requested " + filePath + " --> " + fileName);
|
||||||
|
var element = document.createElement('a');
|
||||||
|
element.setAttribute('href', filePath);
|
||||||
|
element.setAttribute('download', fileName);
|
||||||
|
element.style.display = 'none';
|
||||||
|
document.body.appendChild(element);
|
||||||
|
element.click();
|
||||||
|
document.body.removeChild(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================================================*/
|
||||||
|
/* Network test functions
|
||||||
|
/* ========================================================================*/
|
||||||
|
|
||||||
|
function startPingTest() {
|
||||||
|
console.log("Start ping test");
|
||||||
|
var textArea = document.getElementById("pingTextArea");
|
||||||
|
var button = document.getElementById("pingButton");
|
||||||
|
// Clear the text output
|
||||||
|
textArea.value = "";
|
||||||
|
|
||||||
|
// Request ping output
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.open("GET", "/debug/ping", true);
|
||||||
|
request.send(null);
|
||||||
|
button.disabled = true
|
||||||
|
request.onreadystatechange = function() {
|
||||||
|
if (request.readyState == 4) {
|
||||||
|
console.log(request.responseText);
|
||||||
|
textArea.value = request.responseText
|
||||||
|
button.disabled = false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function startDigTest() {
|
||||||
|
console.log("Start dig test");
|
||||||
|
var textArea = document.getElementById("digTextArea");
|
||||||
|
var button = document.getElementById("digButton");
|
||||||
|
|
||||||
|
// Clear the text output
|
||||||
|
textArea.value = "";
|
||||||
|
|
||||||
|
// Request dig output
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.open("GET", "/debug/dig", true);
|
||||||
|
request.send(null);
|
||||||
|
button.disabled = true
|
||||||
|
request.onreadystatechange = function() {
|
||||||
|
if (request.readyState == 4) {
|
||||||
|
console.log(request.responseText);
|
||||||
|
textArea.value = request.responseText
|
||||||
|
button.disabled = false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function startTracePathTest() {
|
||||||
|
console.log("Start trace path test");
|
||||||
|
var textArea = document.getElementById("tracePathTextArea");
|
||||||
|
var button = document.getElementById("tracePathButton");
|
||||||
|
|
||||||
|
// Clear the text output
|
||||||
|
textArea.value = "";
|
||||||
|
|
||||||
|
// Request dig output
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.open("GET", "/debug/tracepath", true);
|
||||||
|
request.send(null);
|
||||||
|
button.disabled = true
|
||||||
|
request.onreadystatechange = function() {
|
||||||
|
if (request.readyState == 4) {
|
||||||
|
console.log(request.responseText);
|
||||||
|
textArea.value = request.responseText
|
||||||
|
button.disabled = false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -20,120 +20,144 @@
|
|||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
margin:0;
|
margin:0;
|
||||||
padding:0;
|
padding:0;
|
||||||
height:100%;
|
height:100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
color: #676767;
|
color: #676767;
|
||||||
font-family: "Ubuntu", Helvetica, "Helvetica Neue", Arial, sans-serif;
|
font-family: "Ubuntu", Helvetica, "Helvetica Neue", Arial, sans-serif;
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
h1, h2, h3, h4, h5, h6 {
|
||||||
font-family: "Ubuntu", Helvetica, "Helvetica Neue", Arial, sans-serif;
|
font-family: "Ubuntu", Helvetica, "Helvetica Neue", Arial, sans-serif;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
color: #676767;
|
color: #676767;
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
th, td {
|
th, td {
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
color: #676767;
|
color: #676767;
|
||||||
font-family: "Ubuntu", Helvetica, "Helvetica Neue", Arial, sans-serif;
|
font-family: "Ubuntu", Helvetica, "Helvetica Neue", Arial, sans-serif;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr {
|
hr {
|
||||||
color: #efefef;
|
color: #efefef;
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
display: table;
|
display: table;
|
||||||
border-collapse: colapse;
|
border-collapse: colapse;
|
||||||
border-color: #efefef;
|
border-color: #efefef;
|
||||||
width: 100%;
|
min-height: 100px;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
background-color: #3a4055;
|
||||||
|
width: 100%;
|
||||||
|
padding: 15px;
|
||||||
|
min-height: 100px;
|
||||||
|
text-align: left;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.console-textarea {
|
||||||
|
color: white;
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 15px;
|
||||||
|
font-family: "Ubuntu Mono";
|
||||||
|
font-size: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nymea-main-logo {
|
.nymea-main-logo {
|
||||||
left: 0;
|
left: 0;
|
||||||
height: 85px;
|
height: 85px;
|
||||||
min-height: 85px;
|
min-height: 85px;
|
||||||
max-height: 85px;
|
max-height: 85px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.warning {
|
.warning {
|
||||||
background-color: #ed3146;
|
background-color: #ed3146;
|
||||||
border-radius: 20px;
|
border-radius: 10px;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
width: 80%;
|
width: 80%;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.warning-message {
|
.warning-message {
|
||||||
padding:30px;
|
padding: 30px;
|
||||||
margin-left: 60px;
|
margin-left: 60px;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
color: white;
|
color: white;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
font-family: "Ubuntu", Helvetica, "Helvetica Neue", Arial, sans-serif;
|
font-family: "Ubuntu", Helvetica, "Helvetica Neue", Arial, sans-serif;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
float: none;
|
float: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.warning-image {
|
.warning-image {
|
||||||
padding:12px;
|
padding:12px;
|
||||||
height: 60px;
|
height: 60px;
|
||||||
min-height: 60px;
|
min-height: 60px;
|
||||||
max-height: 60px;
|
max-height: 60px;
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.warning:after {
|
.warning:after {
|
||||||
content: "";
|
content: "";
|
||||||
display: table;
|
display: table;
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-row {
|
.download-row {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-name-column {
|
.download-name-column {
|
||||||
float: left;
|
float: left;
|
||||||
width: 30%;
|
width: 20%;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-path-column {
|
.download-path-column {
|
||||||
float: left;
|
float: left;
|
||||||
width: 40%;
|
width: 40%;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-button-column {
|
.download-button-column {
|
||||||
float: left;
|
float: left;
|
||||||
width: 20%;
|
width: 20%;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.show-button-column {
|
||||||
|
float: left;
|
||||||
|
width: 10%;
|
||||||
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-row: after {
|
.download-row: after {
|
||||||
content: "";
|
content: "";
|
||||||
display: table;
|
display: table;
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
@ -146,34 +170,45 @@ button {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
|
opacity: 0.8;
|
||||||
|
transition: 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button:hover {
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:disabled,
|
||||||
|
.button[disabled]{
|
||||||
|
background-color: #cccccc;
|
||||||
|
color: #676767;
|
||||||
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
min-height:100%;
|
min-height:100%;
|
||||||
position:relative;
|
position:relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
padding:10px;
|
padding:10px;
|
||||||
background-color: #efefef;
|
background-color: #efefef;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.body {
|
.body {
|
||||||
padding-left: 15%;
|
padding-left: 15%;
|
||||||
padding-right: 15%;
|
padding-right: 15%;
|
||||||
padding-bottom:120px;
|
padding-bottom:120px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
position:absolute;
|
position:absolute;
|
||||||
bottom:0;
|
bottom:0;
|
||||||
left:0;
|
left:0;
|
||||||
right:0;
|
right:0;
|
||||||
width:100%;
|
width:100%;
|
||||||
height:100px;
|
height:100px;
|
||||||
background-color: #efefef;
|
background-color: #efefef;
|
||||||
color: #676767;
|
color: #676767;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,10 @@
|
|||||||
#ifndef DEBUGSERVERHANDLER_H
|
#ifndef DEBUGSERVERHANDLER_H
|
||||||
#define DEBUGSERVERHANDLER_H
|
#define DEBUGSERVERHANDLER_H
|
||||||
|
|
||||||
|
#include <QTimer>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QWebSocketServer>
|
||||||
|
|
||||||
#include "httpreply.h"
|
#include "httpreply.h"
|
||||||
|
|
||||||
@ -35,15 +38,41 @@ public:
|
|||||||
|
|
||||||
HttpReply *processDebugRequest(const QString &requestPath);
|
HttpReply *processDebugRequest(const QString &requestPath);
|
||||||
|
|
||||||
|
static QList<QWebSocket *> s_websocketClients;
|
||||||
|
static void consoleLogHandler(QtMsgType type, const QMessageLogContext& context, const QString& message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QByteArray createDebugXmlDocument();
|
QTimer *m_timer = nullptr;
|
||||||
QByteArray createErrorXmlDocument(HttpReply::HttpStatusCode statusCode, const QString &errorMessage);
|
QWebSocketServer *m_websocketServer = nullptr;
|
||||||
QByteArray loadResourceFile(const QString &resourceFileName);
|
|
||||||
|
QProcess *m_pingProcess = nullptr;
|
||||||
|
HttpReply *m_pingReply = nullptr;
|
||||||
|
|
||||||
|
QProcess *m_digProcess = nullptr;
|
||||||
|
HttpReply *m_digReply = nullptr;
|
||||||
|
|
||||||
|
QProcess *m_tracePathProcess = nullptr;
|
||||||
|
HttpReply *m_tracePathReply = nullptr;
|
||||||
|
|
||||||
|
QByteArray loadResourceData(const QString &resourceFileName);
|
||||||
QString getResourceFileName(const QString &requestPath);
|
QString getResourceFileName(const QString &requestPath);
|
||||||
bool resourceFileExits(const QString &requestPath);
|
bool resourceFileExits(const QString &requestPath);
|
||||||
|
|
||||||
HttpReply *processDebugFileRequest(const QString &requestPath);
|
HttpReply *processDebugFileRequest(const QString &requestPath);
|
||||||
|
|
||||||
|
QByteArray createDebugXmlDocument();
|
||||||
|
QByteArray createErrorXmlDocument(HttpReply::HttpStatusCode statusCode, const QString &errorMessage);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onTimeout();
|
||||||
|
void onWebsocketClientConnected();
|
||||||
|
void onWebsocketClientDisconnected();
|
||||||
|
void onWebsocketClientError(QAbstractSocket::SocketError error);
|
||||||
|
|
||||||
|
void onPingProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||||
|
void onDigProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||||
|
void onTracePathProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -417,7 +417,7 @@ QByteArray HttpReply::getHeaderType(const HttpReply::HttpHeaderType &headerType)
|
|||||||
*/
|
*/
|
||||||
void HttpReply::startWait()
|
void HttpReply::startWait()
|
||||||
{
|
{
|
||||||
m_timer->start(10000);
|
m_timer->start(60000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpReply::timeout()
|
void HttpReply::timeout()
|
||||||
|
|||||||
@ -132,7 +132,7 @@ QUrl WebServer::serverUrl() const
|
|||||||
void WebServer::sendHttpReply(HttpReply *reply)
|
void WebServer::sendHttpReply(HttpReply *reply)
|
||||||
{
|
{
|
||||||
// get the right socket
|
// get the right socket
|
||||||
QSslSocket *socket = 0;
|
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?";
|
||||||
@ -141,7 +141,7 @@ void WebServer::sendHttpReply(HttpReply *reply)
|
|||||||
|
|
||||||
// send raw data
|
// send raw data
|
||||||
reply->packReply();
|
reply->packReply();
|
||||||
qCDebug(dcWebServer) << "respond" << reply->httpStatusCode() << reply->httpReasonPhrase();
|
qCDebug(dcWebServer) << "Respond" << reply->httpStatusCode() << reply->httpReasonPhrase();
|
||||||
socket->write(reply->data());
|
socket->write(reply->data());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +161,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 +171,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");
|
||||||
@ -388,8 +388,15 @@ void WebServer::readClient()
|
|||||||
|
|
||||||
HttpReply *reply = NymeaCore::instance()->debugServerHandler()->processDebugRequest(request.url().path());
|
HttpReply *reply = NymeaCore::instance()->debugServerHandler()->processDebugRequest(request.url().path());
|
||||||
reply->setClientId(clientId);
|
reply->setClientId(clientId);
|
||||||
sendHttpReply(reply);
|
|
||||||
reply->deleteLater();
|
// Handle async replies
|
||||||
|
if (reply->type() == HttpReply::TypeAsync) {
|
||||||
|
connect(reply, &HttpReply::finished, this, &WebServer::onAsyncReplyFinished);
|
||||||
|
reply->startWait();
|
||||||
|
} else {
|
||||||
|
sendHttpReply(reply);
|
||||||
|
reply->deleteLater();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcWebServer()) << "The debug server handler is disabled. You can enable it by adding \'debugServerEnabled=true\' in the \'nymead\' section of the nymead.conf file.";
|
qCWarning(dcWebServer()) << "The debug server handler is disabled. You can enable it by adding \'debugServerEnabled=true\' in the \'nymead\' section of the nymead.conf file.";
|
||||||
@ -403,7 +410,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()));
|
||||||
@ -418,7 +425,7 @@ void WebServer::readClient()
|
|||||||
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
|
||||||
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);
|
||||||
@ -432,7 +439,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
|
||||||
@ -522,6 +529,21 @@ void WebServer::onError(QAbstractSocket::SocketError error)
|
|||||||
qCWarning(dcWebServer()) << QString("Client socket error %1:%2 ->").arg(socket->peerAddress().toString()).arg(socket->peerPort()) << socket->errorString();
|
qCWarning(dcWebServer()) << QString("Client socket error %1:%2 ->").arg(socket->peerAddress().toString()).arg(socket->peerPort()) << socket->errorString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebServer::onAsyncReplyFinished()
|
||||||
|
{
|
||||||
|
HttpReply *reply = qobject_cast<HttpReply*>(sender());
|
||||||
|
qCDebug(dcWebServer) << "Async reply finished";
|
||||||
|
|
||||||
|
// check if the reply timeouted
|
||||||
|
if (reply->timedOut()) {
|
||||||
|
reply->clear();
|
||||||
|
reply->setHttpStatusCode(HttpReply::GatewayTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendHttpReply(reply);
|
||||||
|
reply->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
void WebServer::onAvahiServiceStateChanged(const QtAvahiService::QtAvahiServiceState &state)
|
void WebServer::onAvahiServiceStateChanged(const QtAvahiService::QtAvahiServiceState &state)
|
||||||
{
|
{
|
||||||
Q_UNUSED(state)
|
Q_UNUSED(state)
|
||||||
@ -826,7 +848,7 @@ void WebServerClient::removeConnection(QSslSocket *socket)
|
|||||||
*/
|
*/
|
||||||
void WebServerClient::resetTimout(QSslSocket *socket)
|
void WebServerClient::resetTimout(QSslSocket *socket)
|
||||||
{
|
{
|
||||||
QTimer *timer = 0;
|
QTimer *timer = nullptr;
|
||||||
timer = m_runningConnections.key(socket);
|
timer = m_runningConnections.key(socket);
|
||||||
if (timer)
|
if (timer)
|
||||||
timer->start();
|
timer->start();
|
||||||
|
|||||||
@ -113,6 +113,7 @@ private slots:
|
|||||||
void onDisconnected();
|
void onDisconnected();
|
||||||
void onEncrypted();
|
void onEncrypted();
|
||||||
void onError(QAbstractSocket::SocketError error);
|
void onError(QAbstractSocket::SocketError error);
|
||||||
|
void onAsyncReplyFinished();
|
||||||
|
|
||||||
void onAvahiServiceStateChanged(const QtAvahiService::QtAvahiServiceState &state);
|
void onAvahiServiceStateChanged(const QtAvahiService::QtAvahiServiceState &state);
|
||||||
void resetAvahiService();
|
void resetAvahiService();
|
||||||
|
|||||||