From e4423a8dbad5d68fca241d989eec2c082ac79a9f Mon Sep 17 00:00:00 2001 From: acetone Date: Thu, 9 Dec 2021 11:23:59 -0500 Subject: [PATCH] http link highlighting --- httpserver.cpp | 247 +++++++++++++++++++++++++++++++++++++------------ ircclient.cpp | 1 - 2 files changed, 187 insertions(+), 61 deletions(-) diff --git a/httpserver.cpp b/httpserver.cpp index 3deeb21..8a0330c 100644 --- a/httpserver.cpp +++ b/httpserver.cpp @@ -6,12 +6,15 @@ #include #include +#include #include #include #include #include #include +constexpr int BUFFER_SIZE = 2048; + HttpServer::HttpServer(const QString &address, quint16 port, const QString& logFolder, const QString& mainChannel, QObject *parent) : QObject(parent), @@ -36,11 +39,52 @@ HttpServer::~HttpServer() m_TcpServer->deleteLater(); } +QString HttpServer::convertToClickableLink(const QString &httpLine) +{ + QString result; + if (not httpLine.contains(QRegularExpression("http.?://"))) return result; + + QString scheme {httpLine}; + scheme.remove(QRegularExpression("://.*$")); + + QString displayedName {httpLine}; + displayedName.remove(QRegularExpression("http.?://")); + int sizeFirst = displayedName.size(); + displayedName.remove(QRegularExpression("/.*$")); + int sizeSecond = displayedName.size(); + result = "" + scheme + "://" + displayedName; + if (sizeFirst - sizeSecond > 2) { + QString longUrl {httpLine}; + longUrl.remove(QRegularExpression("^.*"+displayedName)); + int displayedPart = longUrl.size(); + bool fixed = false; + for (int i = 0; i < displayedPart; ++i) { + result += longUrl[i]; + if (i > 2 and displayedPart > 10 and not fixed) { + result += "..."; + i = displayedPart - 4; + fixed = true; + } + } + } + result += ""; + return result; +} + void HttpServer::consoleLog(const QString &message) { qInfo().noquote() << "[WEBINTERFACE]" << message; } +void HttpServer::debugLog(const QString &req) +{ + QFile log(m_logFolder + "httprequests.log"); + if (log.open(QIODevice::WriteOnly | QIODevice::Append)) { + log.write(QDateTime::currentDateTime().toString().toUtf8() + ":\n" + req.toUtf8() + "\n"); + log.close(); + } +} + void HttpServer::acceptor() { QTcpSocket* socket = m_TcpServer->nextPendingConnection(); @@ -51,66 +95,90 @@ void HttpServer::acceptor() void HttpServer::reader() { QTcpSocket* socket = static_cast(sender()); - QString request = socket->readAll(); + QString request = socket->read(BUFFER_SIZE); + if (not request.startsWith("GET") and not request.startsWith("HEAD")) { + if (socket->isOpen()) { + socket->write("Your request has been rejected!\n"); + socket->disconnectFromHost(); + } + return; + } + + bool isHeadRequest = false; + if (request.startsWith("HEAD ")) { + isHeadRequest = true; + } + QString urlPath = getRequestPath(request); // static files if (urlPath == "/favicon.ico") { QString eTag = global::getValue(request, "If-None-Match", global::eHttpHeader); if (eTag == HTTP_ACTUAL_ETAG) { - socket->write(HEADER_304.toUtf8()); - return; + if (socket->isOpen()) socket->write(HEADER_304.toUtf8()); } - QFile icon("://html/favicon.ico"); - if (icon.open(QIODevice::ReadOnly)) { - QByteArray file = icon.readAll(); - icon.close(); - QString header = HEADER_ICO; - replaceTag(header, "SIZE", QString::number(file.size())); - socket->write(header.toUtf8()); - socket->write(file); + else { + QFile icon("://html/favicon.ico"); + if (icon.open(QIODevice::ReadOnly)) { + QByteArray file = icon.readAll(); + icon.close(); + QString header = HEADER_ICO; + replaceTag(header, "SIZE", QString::number(file.size())); + if (socket->isOpen()) { + socket->write(header.toUtf8()); + if (not isHeadRequest) socket->write(file); + } + } } } else if (urlPath == "/style.css") { QString eTag = global::getValue(request, "If-None-Match", global::eHttpHeader); if (eTag == HTTP_ACTUAL_ETAG) { - socket->write(HEADER_304.toUtf8()); - return; + if (socket->isOpen()) socket->write(HEADER_304.toUtf8()); } - QFile css("://html/style.css"); - if (css.open(QIODevice::ReadOnly)) { - QByteArray file = css.readAll(); - css.close(); - QString header = HEADER_CSS; - replaceTag(header, "SIZE", QString::number(file.size())); - socket->write(header.toUtf8()); - socket->write(file); + else { + QFile css("://html/style.css"); + if (css.open(QIODevice::ReadOnly)) { + QByteArray file = css.readAll(); + css.close(); + QString header = HEADER_CSS; + replaceTag(header, "SIZE", QString::number(file.size())); + if (socket->isOpen()) { + socket->write(header.toUtf8()); + if (not isHeadRequest) socket->write(file); + } + } } } else if (urlPath.endsWith(".svg")) { QString eTag = global::getValue(request, "If-None-Match", global::eHttpHeader); if (eTag == HTTP_ACTUAL_ETAG) { - socket->write(HEADER_304.toUtf8()); - return; - } - QFile svg("://html"+urlPath); - if (svg.open(QIODevice::ReadOnly)) { - QByteArray file = svg.readAll(); - svg.close(); - QString header = HEADER_SVG; - replaceTag(header, "SIZE", QString::number(file.size())); - socket->write(header.toUtf8()); - socket->write(file); + if (socket->isOpen()) socket->write(HEADER_304.toUtf8()); } else { - socket->write(HEADER_404.toUtf8()); - socket->write("

NOT FOUND

"); + QFile svg("://html"+urlPath); + if (svg.open(QIODevice::ReadOnly)) { + QByteArray file = svg.readAll(); + svg.close(); + QString header = HEADER_SVG; + replaceTag(header, "SIZE", QString::number(file.size())); + if (socket->isOpen()) { + socket->write(header.toUtf8()); + if (not isHeadRequest) socket->write(file); + } + } + else { + if (socket->isOpen()) { + socket->write(HEADER_404.toUtf8()); + if (not isHeadRequest) socket->write("

NOT FOUND

"); + } + } } } // dynamic page else { - writeMainPage(socket, urlPath); + writeMainPage(socket, urlPath, isHeadRequest); } socket->disconnectFromHost(); } @@ -172,8 +240,10 @@ QString HttpServer::getWordFromPath(const QString &path) void HttpServer::writeErrorPage(QTcpSocket *socket) { - socket->write(HEADER_404.toUtf8()); - socket->write("404

NOT FOUND

"); + if (socket->isOpen()) { + socket->write(HEADER_404.toUtf8()); + socket->write("404

NOT FOUND

"); + } } void HttpServer::replaceTag(QString &page, const QString &tag, const QString &payload) @@ -181,7 +251,7 @@ void HttpServer::replaceTag(QString &page, const QString &tag, const QString &pa page.replace("{{"+tag+"}}", payload); } -void HttpServer::writeMainPage(QTcpSocket *socket, QString &urlPath) +void HttpServer::writeMainPage(QTcpSocket *socket, QString &urlPath, bool isHeadRequest) { QString searchRequest; int specSymbol = urlPath.indexOf('?'); // any actions like a ?toSearch= @@ -200,14 +270,20 @@ void HttpServer::writeMainPage(QTcpSocket *socket, QString &urlPath) main.close(); } else { - socket->write(HEADER_404.toUtf8()); - socket->write("Critical error

NOT FOUND

Maybe it is compilation error

"); + if (socket->isOpen()) { + socket->write(HEADER_404.toUtf8()); + if (not isHeadRequest) socket->write("Critical error

NOT FOUND

Maybe it is compilation error

"); + } } QString server = getWordFromPath(urlPath); QDir fsPath(m_logFolder+server); if (not fsPath.exists()) { - writeErrorPage(socket); + if (isHeadRequest) { + if (socket->isOpen()) socket->write(HEADER_404.toUtf8()); + } else { + writeErrorPage(socket); + } return; } @@ -226,8 +302,13 @@ void HttpServer::writeMainPage(QTcpSocket *socket, QString &urlPath) break; } } + if (not fsPath.cd(channel)) { - writeErrorPage(socket); + if (isHeadRequest) { + if (socket->isOpen()) socket->write(HEADER_404.toUtf8()); + } else { + writeErrorPage(socket); + } return; } @@ -237,6 +318,7 @@ void HttpServer::writeMainPage(QTcpSocket *socket, QString &urlPath) originalServerName = s.first; } } + QString originalChannelName; for (const auto &server: m_backendInfo) { for (const auto &channel_users: server.second) { @@ -270,11 +352,17 @@ void HttpServer::writeMainPage(QTcpSocket *socket, QString &urlPath) QByteArray file = plain.readAll(); plain.close(); replaceTag(header, "SIZE", QString::number(file.size())); - socket->write(header.toUtf8()); - socket->write(file); + if (socket->isOpen()) { + socket->write(header.toUtf8()); + if (not isHeadRequest) socket->write(file); + } } else { - writeErrorPage(socket); + if (isHeadRequest) { + if (socket->isOpen()) socket->write(HEADER_404.toUtf8()); + } else { + writeErrorPage(socket); + } } return; } @@ -587,6 +675,7 @@ void HttpServer::writeMainPage(QTcpSocket *socket, QString &urlPath) // Simple log explorer else { + if (year.isEmpty()) { // / QStringList folderNameS; QDirIterator it(fsPath.path()); @@ -672,21 +761,56 @@ void HttpServer::writeMainPage(QTcpSocket *socket, QString &urlPath) QString nick {buffer}; nick.remove(QRegularExpression("\\]\\s.*$")); nick.remove(QRegularExpression("^\\[")); - if (nick.isEmpty()) continue; - - QString text {buffer}; - text.remove(QRegularExpression("^\\[.*\\]\\s")); - - while (QRegularExpression("[^\\s]{100,10000}.*").match(text).hasMatch()) { - int pos = text.indexOf(QRegularExpression("[^\\s]{50,10000}.*")); - if (pos == -1) { - consoleLog("Bug! HttpServer.cpp while (QRegularExpression(\"[^\\s]{50,10000}.*\").match(text).hasMatch())"); - break; - } - text.insert(pos+25, ' '); + if (nick.isEmpty()) { + buffer = file.readLine(); + continue; } - if (text.isEmpty()) continue; + QString text {buffer}; + text.remove(QRegularExpression("^\\[[^\\s]*\\]\\s")); + if (text.isEmpty()) { + buffer = file.readLine(); + continue; + } + + // http links + while (QRegularExpression("(^|\\s)http.?://").match(text).hasMatch()) { + int pos = text.indexOf(QRegularExpression("(^|\\s)http.?://")); + if (pos == -1) { + consoleLog("Bug! HttpServer.cpp while (QRegularExpression(\"(^|\\s)http.?://\").match(text).hasMatch())"); + break; + } + QString rawLink {text}; + rawLink.remove(0, pos); + if (rawLink.startsWith(' ')) { + rawLink.remove(0,1); + } + int space = rawLink.indexOf(' '); + if (space > 0) { + rawLink.remove(space, rawLink.size()-space); + } + text.replace(rawLink, convertToClickableLink(rawLink)); + } + // long lines + int space = 0; + bool isHref = false; + for (int i = 0; i < text.size(); i++) { + if (text[i] == ' ') { + space = i; + if (isHref) { + isHref = false; + } + else { + if (text.indexOf("href=\"http", i+1) == i+1) { + isHref = true; + } + } + } + if (not isHref and i-space > 30) { + text.insert(i, ' '); + space = i; + } + } QString message = HTML_PAYLOAD_LIST_CHAT_MESSAGE; for (const auto &user: m_backendInfo[originalServerName][originalChannelName]) { @@ -714,6 +838,9 @@ void HttpServer::writeMainPage(QTcpSocket *socket, QString &urlPath) QString mainHeader = HEADER_HTML; replaceTag(mainHeader, "SIZE", QString::number(QByteArray(page.toUtf8()).size())); - socket->write(mainHeader.toUtf8()); - socket->write(page.toUtf8()); + + if (socket->isOpen()) { + socket->write(mainHeader.toUtf8()); + if (not isHeadRequest) socket->write(page.toUtf8()); + } } diff --git a/ircclient.cpp b/ircclient.cpp index c0355c0..248d48a 100644 --- a/ircclient.cpp +++ b/ircclient.cpp @@ -233,7 +233,6 @@ void IrcClient::errorLog(const QString &message) log.write(QDateTime::currentDateTime().toString().toUtf8() + " " + message.toUtf8() + "\n"); log.close(); } - return; } void IrcClient::onRead()