http link highlighting

master
const an teen 2021-12-09 11:23:59 -05:00
parent e3c4c3f338
commit e4423a8dba
2 changed files with 187 additions and 61 deletions

View File

@ -6,12 +6,15 @@
#include <QRegularExpression>
#include <QDirIterator>
#include <QDateTime>
#include <QHostAddress>
#include <QTcpSocket>
#include <QDebug>
#include <QFile>
#include <QDir>
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 = "<a href=\"" + httpLine + "\">" + 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 += "</a>";
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<QTcpSocket*>(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("<center><h1>NOT FOUND</H1></center>");
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("<center><h1>NOT FOUND</H1></center>");
}
}
}
}
// 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("<title>404</title><center><h1>NOT FOUND</H1></center>");
if (socket->isOpen()) {
socket->write(HEADER_404.toUtf8());
socket->write("<title>404</title><center><h1>NOT FOUND</H1></center>");
}
}
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("<title>Critical error</title><center><h1>NOT FOUND</H1><p>Maybe it is compilation error</p></center>");
if (socket->isOpen()) {
socket->write(HEADER_404.toUtf8());
if (not isHeadRequest) socket->write("<title>Critical error</title><center><h1>NOT FOUND</H1><p>Maybe it is compilation error</p></center>");
}
}
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());
}
}

View File

@ -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()