Implemented directory listing
This commit is contained in:
@@ -1,14 +1,36 @@
|
|||||||
#include "fileserverapplication.h"
|
#include "fileserverapplication.h"
|
||||||
|
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonValue>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "webserver.h"
|
#include "webserver.h"
|
||||||
#include "httprequest.h"
|
#include "httprequest.h"
|
||||||
#include "httpresponse.h"
|
#include "httpresponse.h"
|
||||||
#include "httpclientconnection.h"
|
#include "httpclientconnection.h"
|
||||||
|
#include "httpnotfoundexception.h"
|
||||||
|
#include "httpexception.h"
|
||||||
|
|
||||||
|
const QString FileserverApplication::SERVER_NAME(QStringLiteral("Fileserver 1.0"));
|
||||||
|
const QDir FileserverApplication::PLUGIN_RESOURCES_DIR(QStringLiteral(":/webserver/plugins/fileserverplugin"));
|
||||||
|
|
||||||
FileserverApplication::FileserverApplication(const QJsonObject &config, WebServer &webServer) :
|
FileserverApplication::FileserverApplication(const QJsonObject &config, WebServer &webServer) :
|
||||||
WebApplication(&webServer), m_webServer(webServer)
|
WebApplication(&webServer), m_webServer(webServer)
|
||||||
{
|
{
|
||||||
Q_UNUSED(config)
|
if(!config.contains(QStringLiteral("rootPath")))
|
||||||
|
throw std::runtime_error("Fileserver application does not contain rootPath");
|
||||||
|
|
||||||
|
const auto rootPathVal = config.value(QStringLiteral("rootPath"));
|
||||||
|
if(!rootPathVal.isString())
|
||||||
|
throw std::runtime_error("Fileserver application rootPath is not a string");
|
||||||
|
|
||||||
|
m_rootPath = QDir(rootPathVal.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileserverApplication::start()
|
void FileserverApplication::start()
|
||||||
@@ -17,8 +39,97 @@ void FileserverApplication::start()
|
|||||||
|
|
||||||
void FileserverApplication::handleRequest(HttpClientConnection *connection, const HttpRequest &request)
|
void FileserverApplication::handleRequest(HttpClientConnection *connection, const HttpRequest &request)
|
||||||
{
|
{
|
||||||
HttpResponse response;
|
static const QString pluginPrefix(QStringLiteral("/:fileserverplugin/"));
|
||||||
response.protocol = request.protocol;
|
const auto pluginResource = request.path.startsWith(pluginPrefix);
|
||||||
response.statusCode = HttpResponse::StatusCode::OK;
|
|
||||||
connection->sendResponse(response, "Hello from FileserverApplication: " + request.path);
|
const QFileInfo fileInfo((pluginResource ? PLUGIN_RESOURCES_DIR : m_rootPath)
|
||||||
|
.absoluteFilePath(request.path.mid(pluginResource ? pluginPrefix.length() : 1)));
|
||||||
|
|
||||||
|
if(!fileInfo.exists())
|
||||||
|
throw HttpNotFoundException(request);
|
||||||
|
|
||||||
|
if(fileInfo.isDir())
|
||||||
|
{
|
||||||
|
if(!request.path.endsWith(QLatin1Char('/')))
|
||||||
|
{
|
||||||
|
const QString newUrl = request.path + '/';
|
||||||
|
|
||||||
|
HttpResponse response;
|
||||||
|
response.protocol = request.protocol;
|
||||||
|
response.statusCode = HttpResponse::StatusCode::MovedPermanently;
|
||||||
|
response.headers.insert(HttpResponse::HEADER_SERVER, SERVER_NAME);
|
||||||
|
response.headers.insert(HttpResponse::HEADER_LOCATION, newUrl);
|
||||||
|
connection->sendResponse(response, QStringLiteral("<a href=\"%0\">%1</a>").arg(QString(QUrl::toPercentEncoding(newUrl)).toHtmlEscaped()).arg(tr("Moved.")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDir dir(fileInfo.absoluteFilePath());
|
||||||
|
|
||||||
|
QString content;
|
||||||
|
static const QString line(QStringLiteral("<tr><td><img src=\"/:fileserverplugin/images/%0\" /> <a href=\"%1\">%2</a></td><td>%3</td></tr>"));
|
||||||
|
|
||||||
|
if(request.path != QStringLiteral("/"))
|
||||||
|
content.append(line.arg(QStringLiteral("back.png")).arg(QStringLiteral("..")).arg(tr("Parent directory")).arg(QString()));
|
||||||
|
|
||||||
|
for(auto info : dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot))
|
||||||
|
content.append(line
|
||||||
|
.arg(info.isDir() ? QStringLiteral("folder.png") : QStringLiteral("text.png"))
|
||||||
|
.arg(QString(QUrl::toPercentEncoding(info.fileName())).toHtmlEscaped())
|
||||||
|
.arg(info.fileName().toHtmlEscaped())
|
||||||
|
.arg(info.isDir() ? QString() : formatSize(info.size())));
|
||||||
|
|
||||||
|
HttpResponse response;
|
||||||
|
response.protocol = request.protocol;
|
||||||
|
response.statusCode = HttpResponse::StatusCode::OK;
|
||||||
|
response.headers.insert(HttpResponse::HEADER_SERVER, SERVER_NAME);
|
||||||
|
connection->sendResponse(response, QStringLiteral("<!doctype html>"
|
||||||
|
"<html lang=\"en\">"
|
||||||
|
"<head>"
|
||||||
|
"<meta charset=\"utf-8\">"
|
||||||
|
"<link rel=\"stylesheet\" href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css\" integrity=\"sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO\" crossorigin=\"anonymous\">"
|
||||||
|
"</head>"
|
||||||
|
"<body>"
|
||||||
|
"<div class=\"container\">"
|
||||||
|
"<table class=\"table\">"
|
||||||
|
"<thead>"
|
||||||
|
"<tr>"
|
||||||
|
"<th>Filename</th>"
|
||||||
|
"<th>Size</th>"
|
||||||
|
"</tr>"
|
||||||
|
"</thead>"
|
||||||
|
"<tbody>"
|
||||||
|
"%0"
|
||||||
|
"</tbody>"
|
||||||
|
"</table>"
|
||||||
|
"</div>"
|
||||||
|
"</body>"
|
||||||
|
"</html>").arg(content));
|
||||||
|
}
|
||||||
|
else if(fileInfo.isFile())
|
||||||
|
{
|
||||||
|
std::unique_ptr<QFileDevice> file = std::make_unique<QFile>(fileInfo.filePath());
|
||||||
|
if(!file->open(QIODevice::ReadOnly))
|
||||||
|
throw HttpException(request, tr("Could not open requested file \"%0\" because %1").arg(request.path, file->errorString()).toStdString());
|
||||||
|
|
||||||
|
HttpResponse response;
|
||||||
|
response.protocol = request.protocol;
|
||||||
|
response.statusCode = HttpResponse::StatusCode::OK;
|
||||||
|
response.headers.insert(HttpResponse::HEADER_SERVER, SERVER_NAME);
|
||||||
|
connection->sendResponse(response, std::move(file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FileserverApplication::formatSize(qint64 size)
|
||||||
|
{
|
||||||
|
static const QStringList suffixes { QStringLiteral("B"), QStringLiteral("kB"), QStringLiteral("MB"), QStringLiteral("GB"), QStringLiteral("TB") };
|
||||||
|
static const int stepSize = 1024;
|
||||||
|
|
||||||
|
for(const auto &suffix : suffixes)
|
||||||
|
{
|
||||||
|
if(size < stepSize)
|
||||||
|
return QStringLiteral("%0 %1").arg(size).arg(suffix);
|
||||||
|
size /= stepSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QStringLiteral("%0 %1").arg(size).arg(suffixes.last());
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "webapplication.h"
|
#include "webapplication.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
class QJsonObject;
|
class QJsonObject;
|
||||||
|
|
||||||
class WebServer;
|
class WebServer;
|
||||||
@@ -9,6 +11,8 @@ class WebServer;
|
|||||||
class FileserverApplication : public WebApplication
|
class FileserverApplication : public WebApplication
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
static const QString SERVER_NAME;
|
||||||
|
static const QDir PLUGIN_RESOURCES_DIR;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FileserverApplication(const QJsonObject &config, WebServer &webServer);
|
FileserverApplication(const QJsonObject &config, WebServer &webServer);
|
||||||
@@ -18,5 +22,8 @@ public:
|
|||||||
void handleRequest(HttpClientConnection *connection, const HttpRequest &request) Q_DECL_OVERRIDE;
|
void handleRequest(HttpClientConnection *connection, const HttpRequest &request) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static QString formatSize(qint64 size);
|
||||||
|
|
||||||
WebServer &m_webServer;
|
WebServer &m_webServer;
|
||||||
|
QDir m_rootPath;
|
||||||
};
|
};
|
||||||
|
@@ -10,7 +10,7 @@ SOURCES += fileserverplugin.cpp \
|
|||||||
|
|
||||||
FORMS +=
|
FORMS +=
|
||||||
|
|
||||||
RESOURCES +=
|
RESOURCES += fileserverplugin_resources.qrc
|
||||||
|
|
||||||
TRANSLATIONS +=
|
TRANSLATIONS +=
|
||||||
|
|
||||||
|
7
fileserverplugin_resources.qrc
Normal file
7
fileserverplugin_resources.qrc
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="/webserver/plugins/fileserverplugin">
|
||||||
|
<file>images/back.png</file>
|
||||||
|
<file>images/folder.png</file>
|
||||||
|
<file>images/text.png</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
BIN
images/back.png
Normal file
BIN
images/back.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 308 B |
BIN
images/folder.png
Normal file
BIN
images/folder.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 295 B |
BIN
images/text.png
Normal file
BIN
images/text.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 288 B |
Reference in New Issue
Block a user