mirror of https://notabug.org/acetone/ircabot.git
http link highlighting
parent
e3c4c3f338
commit
e4423a8dba
247
httpserver.cpp
247
httpserver.cpp
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue