#include #include #include #include #include #include #include #include #define PROGRAMVERSION "1.0" #define BUFSIZE 1000000 // supported httpStatusCode: // 400 Bad Request // 403 Forbidden // 404 Not Found // 500 Internal Server Error // message: additional message QString httpError(int httpStatusCode, QString message) { QString description; switch(httpStatusCode) { case 400: description = "Bad Request"; break; case 403: description = "Forbidden"; break; case 404: description = "Not Found"; break; case 500: description = "Internal Server Error"; break; default: message = QString("Bad error code: %1, message: %2").arg(httpStatusCode).arg(message); httpStatusCode = 500; description = "Internal Server Error"; } return QString("Status: %1 %2\r\nContent-Type: text/html\r\n\r\n

%1 %2

%3

\r\n").arg(httpStatusCode).arg(description).arg(message); } int main(int argc, char* argv[]) { int result = FCGX_Init(); if (result != 0) { return 1; // error on init } FCGX_Request request; if (FCGX_InitRequest(&request, 0, 0) != 0) { return 1; // error on init } int count = 0; while (FCGX_Accept_r(&request) == 0) { count++; QString queryString(FCGX_GetParam("QUERY_STRING", request.envp)); // URL parameters QStringList paramList = queryString.split("&"); QHash paramHash; foreach(QString keyValue, paramList) { QStringList keyValueList = keyValue.split("="); if (keyValueList.size() == 2) { QString key = keyValueList[0]; QString value = keyValueList[1]; paramHash[key] = value; } } QString command = paramHash["command"]; // process environment QString webboxPath(getenv("WEBBOX_PATH")); // FastCGI request environment QString pathInfo(FCGX_GetParam("PATH_INFO", request.envp)); if (pathInfo == "") { pathInfo = "/"; } if (pathInfo.contains("..")) { FCGX_PutS(httpError(403, QString("Bad path: %1").arg(pathInfo)).toUtf8().data(), request.out); continue; } QString path = webboxPath + pathInfo; if (command == "diag") { FCGX_PutS("Content-Type: text/html\r\n\r\n", request.out); FCGX_PutS("Params\r\n", request.out); FCGX_PutS(QString("Request no. %1

\r\n").arg(count).toUtf8().data(), request.out); char** tmp = request.envp; while (*tmp) { FCGX_PutS(QString("%1
\r\n").arg(*tmp).toUtf8().data(), request.out); tmp++; } FCGX_PutS(QString("
WEBBOX_PATH=%1
\r\n").arg(getenv("WEBBOX_PATH")).toUtf8().data(), request.out); FCGX_PutS("\r\n", request.out); } else if (command == "list") { FCGX_PutS("Content-Type: text/xml\r\n\r\n", request.out); FCGX_PutS("\r\n", request.out); QDir dir(path); QFileInfoList dirEntryList = dir.entryInfoList(QDir::NoDot | QDir::AllEntries, QDir::DirsFirst | QDir::Name); foreach(QFileInfo i, dirEntryList) { if (pathInfo != "/" || i.fileName() != "..") { // skip on ".." in "/" FCGX_PutS(QString("%2\r\n").arg(i.isDir() ? "dir" : "file").arg(i.fileName()).toUtf8().data(), request.out); } } FCGX_PutS("\r\n", request.out); } else if (command == "title") { FCGX_PutS("Content-Type: text/plain\r\n\r\n", request.out); FCGX_PutS(getenv("WEBBOX_NAME"), request.out); } else if (command == "version") { FCGX_PutS("Content-Type: text/plain\r\n\r\n", request.out); FCGX_PutS(QString("webbox %1
(C) 2017 Reichwein.IT\r\n").arg(PROGRAMVERSION).toUtf8().data(), request.out); } else if (command == "newdir") { // POST! QString contentLengthString(FCGX_GetParam("CONTENT_LENGTH", request.envp)); bool ok; int contentLength = contentLengthString.toInt(&ok); FCGX_PutS("Content-Type: text/plain\r\n\r\n", request.out); if (!ok) { FCGX_PutS(QString("Bad content length").toUtf8().data(), request.out); } else { QByteArray content(contentLength, 0); int result = FCGX_GetStr(content.data(), content.size(), request.in); if (result != content.size()) { FCGX_PutS(QString("Read error (%1/%2)").arg(result).arg(content.size()).toUtf8().data(), request.out); } else { QXmlStreamReader xml(content); while (!xml.atEnd()) { while (xml.readNextStartElement()) { if (xml.name() == "dirname") { QString dirname = xml.readElementText(); QDir dir(path); if (dir.mkdir(dirname)) { FCGX_PutS("Successfully created directory", request.out); } else { FCGX_PutS("Error creating directory", request.out); } } } } } } } else if (command == "info") { // POST! QString contentLengthString(FCGX_GetParam("CONTENT_LENGTH", request.envp)); bool ok; int contentLength = contentLengthString.toInt(&ok); FCGX_PutS("Content-Type: text/plain\r\n\r\n", request.out); if (!ok) { FCGX_PutS(QString("Bad content length").toUtf8().data(), request.out); } else { QByteArray content(contentLength, 0); int result = FCGX_GetStr(content.data(), content.size(), request.in); if (result != content.size()) { FCGX_PutS(QString("Read error (%1/%2)").arg(result).arg(content.size()).toUtf8().data(), request.out); } else { QXmlStreamReader xml(content); while (!xml.atEnd()) { while (xml.readNextStartElement()) { if (xml.name() == "files") { while (xml.readNextStartElement()) { if (xml.name() == "file") { QString filename = xml.readElementText(); QFileInfo fileInfo(path + "/" + filename); qint64 size = fileInfo.size(); QString date = fileInfo.lastModified().toString(); QString type = fileInfo.isDir() ? "directory" : "file"; FCGX_PutS(QString("%1, %2 bytes, %3 (%4)
") .arg(filename) .arg(size) .arg(date) .arg(type).toUtf8().data(), request.out); } } } } } } } } else if (command == "download-zip") { // POST! QString contentLengthString(FCGX_GetParam("CONTENT_LENGTH", request.envp)); bool ok; int contentLength = contentLengthString.toInt(&ok); if (!ok) { FCGX_PutS("Content-Type: text/plain\r\n\r\n", request.out); FCGX_PutS(QString("Bad content length").toUtf8().data(), request.out); } else { QByteArray content(contentLength, 0); int result = FCGX_GetStr(content.data(), content.size(), request.in); if (result != content.size()) { FCGX_PutS("Content-Type: text/plain\r\n\r\n", request.out); FCGX_PutS(QString("Read error (%1/%2)").arg(result).arg(content.size()).toUtf8().data(), request.out); } else { QXmlStreamReader xml(content); QByteArray zipData; while (!xml.atEnd()) { while (xml.readNextStartElement()) { if (xml.name() == "files") { while (xml.readNextStartElement()) { if (xml.name() == "file") { QString filename = xml.readElementText(); zipData.append(filename.toUtf8()); // TBD } } } } } FCGX_PutS(QString("Content-Disposition: attachment; filename=\"%1\"\r\n").arg("webbox-download.zip").toUtf8().data(), request.out); FCGX_PutS("Content-Type: application/octet-stream\r\n\r\n", request.out); FCGX_PutStr(zipData.data(), zipData.size(), request.out); } } } else if (command == "upload") { // POST! QString contentLengthString(FCGX_GetParam("CONTENT_LENGTH", request.envp)); bool ok; int contentLength = contentLengthString.toInt(&ok); FCGX_PutS("Content-Type: text/plain\r\n\r\n", request.out); if (!ok) { FCGX_PutS(QString("Bad content length").toUtf8().data(), request.out); } else { QByteArray content(contentLength, 0); int result = FCGX_GetStr(content.data(), content.size(), request.in); if (result != content.size()) { FCGX_PutS(QString("Read error (%1/%2)").arg(result).arg(content.size()).toUtf8().data(), request.out); } else { QString contentType(FCGX_GetParam("CONTENT_TYPE", request.envp)); QString separator("boundary="); if (!contentType.contains(separator)) { FCGX_PutS(QString("No boundary defined").toUtf8().data(), request.out); } else { QByteArray boundary = QByteArray("--") + contentType.split(separator)[1].toUtf8(); int boundaryCount = content.count(boundary); if (boundaryCount != 2) { FCGX_PutS(QString("Bad boundary number found: %1").arg(boundaryCount).toUtf8().data(), request.out); } else { int start = content.indexOf(boundary) + boundary.size(); int end = content.indexOf(QByteArray("\r\n") + boundary, start); content = content.mid(start, end - start); // Read filename start = content.indexOf("filename=\""); if (start == -1) { FCGX_PutS(QString("Error reading filename / start").toUtf8().data(), request.out); } else { start += QByteArray("filename=\"").size(); end = content.indexOf(QByteArray("\""), start); if (end == -1) { FCGX_PutS(QString("Error reading filename / end").toUtf8().data(), request.out); } else { QString filename = content.mid(start, end - start); if (filename.size() < 1) { FCGX_PutS(QString("Bad filename").toUtf8().data(), request.out); } else { // Remove header start = content.indexOf(QByteArray("\r\n\r\n")); if (start == -1) { FCGX_PutS(QString("Error removing upload header").toUtf8().data(), request.out); } else { content = content.mid(start + QString("\r\n\r\n").toUtf8().size()); QFile file(path + "/" + filename); if (!file.open(QIODevice::WriteOnly)) { FCGX_PutS(QString("Error opening file").toUtf8().data(), request.out); } else { qint64 written = file.write(content); if (written != content.size()) { FCGX_PutS(QString("Error writing file").toUtf8().data(), request.out); } else { FCGX_PutS("OK", request.out); } } } } } } } } } } } else { // default: download QFile file(path); if (file.open(QIODevice::ReadOnly)) { QFileInfo fileInfo(path); FCGX_PutS(QString("Content-Disposition: attachment; filename=\"%1\"\r\n").arg(fileInfo.fileName()).toUtf8().data(), request.out); FCGX_PutS("Content-Type: application/octet-stream\r\n\r\n", request.out); while (!file.atEnd()) { QByteArray ba = file.read(BUFSIZE); FCGX_PutStr(ba.data(), ba.size(), request.out); } } else { FCGX_PutS(httpError(500, QString("Bad file: %1").arg(pathInfo)).toUtf8().data(), request.out); } } } return 0; }