khttpd: port to KHTTP

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2022-05-09 01:06:55 +03:00
parent 015674649d
commit b621e1e8b8
2 changed files with 91 additions and 110 deletions

View file

@ -15,6 +15,7 @@ add_executable(khttpd ${khttpd_sources})
target_link_libraries(khttpd target_link_libraries(khttpd
${KDE4_KDEUI_LIBS} ${KDE4_KDEUI_LIBS}
${KDE4_KDNSSD_LIBS} ${KDE4_KDNSSD_LIBS}
${KDE4_KHTTP_LIBS}
) )
install(TARGETS khttpd DESTINATION ${KDE4_BIN_INSTALL_DIR}) install(TARGETS khttpd DESTINATION ${KDE4_BIN_INSTALL_DIR})

View file

@ -24,6 +24,7 @@
#include <KIcon> #include <KIcon>
#include <KMimeType> #include <KMimeType>
#include <KDebug> #include <KDebug>
#include <khttp.h>
#include <QBuffer> #include <QBuffer>
#include <QDir> #include <QDir>
#include <QTcpServer> #include <QTcpServer>
@ -97,34 +98,76 @@ static QByteArray contentForDirectory(const QString &path, const QString &basedi
return data; return data;
} }
class HttpHeaderParser class HttpServer : public KHTTP
{ {
Q_OBJECT
public: public:
void parseHeader(const QByteArray &header); HttpServer(QObject *parent = nullptr);
QString path() const { return m_path; } protected:
void respond(const QByteArray &url, QByteArray *outdata, ushort *httpstatus, KHTTPHeaders *outheaders) final;
private:
QString m_path;
}; };
void HttpHeaderParser::parseHeader(const QByteArray &header) HttpServer::HttpServer(QObject *parent)
: KHTTP(parent)
{ {
bool firstline = true; }
foreach (const QByteArray &line, header.split('\n')) {
if (line.isEmpty()) { void HttpServer::respond(const QByteArray &url, QByteArray *outdata, ushort *httpstatus, KHTTPHeaders *outheaders)
firstline = false; {
continue; qDebug() << Q_FUNC_INFO << url;
static const QString m_directory = QDir::currentPath();
const QString normalizedpath = QUrl::fromPercentEncoding(url);
QFileInfo pathinfo(m_directory + QLatin1Char('/') + normalizedpath);
// qDebug() << Q_FUNC_INFO << normalizedpath << pathinfo.filePath();
const bool isdirectory = pathinfo.isDir();
const bool isfile = pathinfo.isFile();
QByteArray block;
if (normalizedpath.startsWith(QLatin1String("/khttpd_icons/"))) {
const QPixmap iconpixmap = KIcon(normalizedpath.mid(14)).pixmap(20);
QBuffer iconbuffer;
iconbuffer.open(QBuffer::ReadWrite);
if (!iconpixmap.save(&iconbuffer, "PNG")) {
kWarning() << "could not save image";
} }
if (firstline) { const QByteArray data = iconbuffer.data();
const QList<QByteArray> splitline = line.split(' ');
if (splitline.size() == 3) { *httpstatus = 200;
m_path = splitline.at(1).trimmed(); outheaders->insert("Server", "KHTTPD");
} outheaders->insert("Content-Type", "image/png");
}
firstline = false; block.append(data);
} else if (isdirectory) {
const QByteArray data = contentForDirectory(pathinfo.filePath(), m_directory);
*httpstatus = 200;
outheaders->insert("Server", "KHTTPD");
outheaders->insert("Content-Type", "text/html; charset=UTF-8");
block.append(data);
} else if (isfile) {
QFile datafile(pathinfo.filePath());
datafile.open(QFile::ReadOnly);
const QByteArray data = datafile.readAll();
const QString filemime = KMimeType::findByPath(pathinfo.filePath())->name();
*httpstatus = 200;
outheaders->insert("Server", "KHTTPD");
outheaders->insert("Content-Type", QString::fromLatin1("%1; charset=UTF-8").arg(filemime).toAscii());
block.append(data);
} else {
const QByteArray data("<html>404 Not Found</html>");
*httpstatus = 404;
outheaders->insert("Server", "KHTTPD");
outheaders->insert("Content-Type", "text/html; charset=UTF-8");
block.append(data);
} }
// qDebug() << Q_FUNC_INFO << m_path;
outdata->clear();
outdata->append(block);
} }
@ -138,11 +181,8 @@ public:
bool start(const QString &host, int port, const QString &directory); bool start(const QString &host, int port, const QString &directory);
QString errorString() const; QString errorString() const;
public Q_SLOTS:
void handleRequest();
private: private:
QTcpServer m_tcpserver; HttpServer m_httpserver;
QString m_directory; QString m_directory;
KDNSSD m_kdnssd; KDNSSD m_kdnssd;
}; };
@ -150,7 +190,6 @@ private:
KHTTPD::KHTTPD(QObject *parent) KHTTPD::KHTTPD(QObject *parent)
: QObject(parent) : QObject(parent)
{ {
connect(&m_tcpserver, SIGNAL(newConnection()), this, SLOT(handleRequest()));
} }
KHTTPD::~KHTTPD() KHTTPD::~KHTTPD()
@ -160,6 +199,30 @@ KHTTPD::~KHTTPD()
bool KHTTPD::start(const QString &host, int port, const QString &directory) bool KHTTPD::start(const QString &host, int port, const QString &directory)
{ {
#if 1
QFile keyfile("/home/smil3y/katana/kdelibs/kutils/khttp/example.com+5-key.pem");
// QFile keyfile("/etc/ssl/private/ssl-cert-snakeoil.key");
if (!keyfile.open(QFile::ReadOnly)) {
kWarning() << "Could not open key file";
return false;
}
const QByteArray keydata = keyfile.readAll();
QFile certfile("/home/smil3y/katana/kdelibs/kutils/khttp/example.com+5.pem");
// QFile certfile("/etc/ssl/certs/ssl-cert-snakeoil.pem");
if (!certfile.open(QFile::ReadOnly)) {
kWarning() << "Could not open cert file";
return false;
}
const QByteArray certdata = certfile.readAll();
if (!m_httpserver.setCertificate(keydata, certdata)) {
kWarning() << "Could not set certificate";
return false;
}
#endif
#if 0
m_httpserver.setAuthenticate("asd", "123", "Not authorized");
#endif
m_kdnssd.publishService( m_kdnssd.publishService(
"_http._tcp", port, "_http._tcp", port,
i18n("KHTTPD@%1", QHostInfo::localHostName()) i18n("KHTTPD@%1", QHostInfo::localHostName())
@ -167,96 +230,13 @@ bool KHTTPD::start(const QString &host, int port, const QString &directory)
m_directory = directory; m_directory = directory;
QHostAddress address; QHostAddress address;
address.setAddress(host); address.setAddress(host);
return m_tcpserver.listen(address, port); return m_httpserver.start(address, port);
} }
QString KHTTPD::errorString() const QString KHTTPD::errorString() const
{ {
return m_tcpserver.errorString(); return m_httpserver.errorString();
}
void KHTTPD::handleRequest()
{
QTcpSocket *clientConnection = m_tcpserver.nextPendingConnection();
connect(clientConnection, SIGNAL(disconnected()),
clientConnection, SLOT(deleteLater()));
if (!clientConnection->waitForReadyRead()) {
clientConnection->disconnectFromHost();
}
const QByteArray request(clientConnection->readAll());
// qDebug() << Q_FUNC_INFO << "request" << request;
HttpHeaderParser headerparser;
headerparser.parseHeader(request);
const QString normalizedpath = QUrl::fromPercentEncoding(headerparser.path().toAscii());
QFileInfo pathinfo(m_directory + QLatin1Char('/') + normalizedpath);
// qDebug() << Q_FUNC_INFO << headerparser.path() << pathinfo.filePath();
const bool isdirectory = pathinfo.isDir();
const bool isfile = pathinfo.isFile();
QByteArray block;
if (headerparser.path().startsWith(QLatin1String("/khttpd_icons/"))) {
block.append("HTTP/1.1 200 OK\r\n");
block.append(QString::fromLatin1("Date: %1 GMT\r\n").arg(QDateTime(QDateTime::currentDateTime())
.toString("ddd, dd MMM yyyy hh:mm:ss")).toAscii());
block.append("Server: KHTTPD\r\n");
const QPixmap iconpixmap = KIcon(headerparser.path().mid(14)).pixmap(20);
QBuffer iconbuffer;
iconbuffer.open(QBuffer::ReadWrite);
if (!iconpixmap.save(&iconbuffer, "PNG")) {
kWarning() << "could not save image";
}
const QByteArray data = iconbuffer.data();
block.append("Content-Type: image/png\r\n");
block.append(QString::fromLatin1("Content-Length: %1\r\n\r\n").arg(data.length()).toAscii());
block.append(data);
} else if (isdirectory) {
block.append("HTTP/1.1 200 OK\r\n");
block.append(QString::fromLatin1("Date: %1 GMT\r\n").arg(QDateTime(QDateTime::currentDateTime())
.toString("ddd, dd MMM yyyy hh:mm:ss")).toAscii());
block.append("Server: KHTTPD\r\n");
QByteArray data = contentForDirectory(pathinfo.filePath(), m_directory);
block.append("Content-Type: text/html; charset=UTF-8\r\n");
block.append(QString::fromLatin1("Content-Length: %1\r\n\r\n").arg(data.length()).toAscii());
block.append(data);
} else if (isfile) {
block.append("HTTP/1.1 200 OK\r\n");
block.append(QString::fromLatin1("Date: %1 GMT\r\n").arg(QDateTime(QDateTime::currentDateTime())
.toString("ddd, dd MMM yyyy hh:mm:ss")).toAscii());
block.append("Server: KHTTPD\r\n");
QFile datafile(pathinfo.filePath());
datafile.open(QFile::ReadOnly);
const QByteArray data = datafile.readAll();
const QString filemime = KMimeType::findByPath(pathinfo.filePath())->name();
block.append(QString::fromLatin1("Content-Type: %1; charset=UTF-8\r\n").arg(filemime).toAscii());
block.append(QString::fromLatin1("Content-Length: %1\r\n\r\n").arg(data.length()).toAscii());
block.append(data);
} else {
block.append("HTTP/1.1 404 Not Found\r\n");
block.append(QString::fromLatin1("Date: %1 GMT\r\n").arg(QDateTime(QDateTime::currentDateTime())
.toString("ddd, dd MMM yyyy hh:mm:ss")).toAscii());
block.append("Server: KHTTPD\r\n");
const QByteArray data("<html>404 Not Found</html>");
block.append("Content-Type: text/html; charset=UTF-8\r\n");
block.append(QString::fromLatin1("Content-Length: %1\r\n\r\n").arg(data.length()).toAscii());
block.append(data);
}
clientConnection->write(block);
clientConnection->disconnectFromHost();
} }
int main(int argc, char** argv) int main(int argc, char** argv)