243 lines
7.9 KiB
C++
243 lines
7.9 KiB
C++
#include <string>
|
|
#include <iostream>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
|
|
#include "crow.h"
|
|
|
|
std::string escapeHtml(const std::string &input) {
|
|
std::string escaped;
|
|
for (char c : input) {
|
|
switch (c) {
|
|
case '&': escaped += "&"; break;
|
|
case '<': escaped += "<"; break;
|
|
case '>': escaped += ">"; break;
|
|
case '"': escaped += """; break;
|
|
case '\'': escaped += "'"; break;
|
|
default: escaped += c; break;
|
|
}
|
|
}
|
|
|
|
return escaped;
|
|
}
|
|
|
|
std::string generateBreadcrumb(const std::string &urlpath) {
|
|
std::stringstream breadcrumb;
|
|
breadcrumb << "<nav><ul style=\"display: inline;\">"
|
|
"<li style=\"display: inline; margin-right: 8px;\">"
|
|
"<a href=\"/\">トップ</a> / </li>";
|
|
std::string currentPath = "";
|
|
size_t start = 0, end = 0;
|
|
|
|
while ((end = urlpath.find('/', start)) != std::string::npos) {
|
|
std::string part = urlpath.substr(start, end - start);
|
|
currentPath += part + "/";
|
|
breadcrumb << "<li style=\"display: inline; margin-right: 8px;\">"
|
|
<< "<a href=\"/" << currentPath.substr(0, currentPath.size() - 1)
|
|
<< "\">"
|
|
<< part << "</a> / "
|
|
<< "</li>";
|
|
start = end + 1;
|
|
}
|
|
|
|
std::string lastPart = urlpath.substr(start);
|
|
currentPath += lastPart;
|
|
breadcrumb << "<li style=\"display: inline;\">" << lastPart << "</li>";
|
|
|
|
breadcrumb << "</ul></nav>";
|
|
return breadcrumb.str();
|
|
}
|
|
|
|
bool isImage(const std::string &path) {
|
|
const std::string extensions[] = {".png", ".jpg", ".jpeg", ".gif", ".bmp", ".webp"};
|
|
for (const auto &ext : extensions) {
|
|
if (path.size() >= ext.size() &&
|
|
path.compare(path.size() - ext.size(), ext.size(), ext) == 0) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int main() {
|
|
std::string path = "/home/suwako/open-repos/";
|
|
std::string repotype = "";
|
|
|
|
crow::SimpleApp website;
|
|
|
|
CROW_ROUTE(website, "/")([&]() -> crow::response {
|
|
repotype = "";
|
|
std::string res = "<html><head><meta content=\"text/html; charset=utf-8\" "
|
|
"http-equiv=\"content-type\" />"
|
|
"<style>html { color: #fcfcfc; background-color: #232023; } "
|
|
"a { color: #ea79d8; }</style>"
|
|
"</head><body>";
|
|
|
|
res += "<h1>/</h1>";
|
|
res += "<ul>";
|
|
res += "<li><a href=\"/game\">ゲーム</a></li>";
|
|
res += "<li><a href=\"/soft\">ソフト</a></li>";
|
|
res += "<li><a href=\"/web\">ウェブ</a></li>";
|
|
res += "<li><a href=\"/misc\">その他</a></li>";
|
|
res += "</ul>";
|
|
res += "</body></html>";
|
|
|
|
crow::response out(200, res);
|
|
out.add_header("Content-Type", "text/html; charset=utf-8");
|
|
return out;
|
|
});
|
|
|
|
CROW_ROUTE(website, "/<path>")([&](const crow::request &req, std::string urlpath)
|
|
-> crow::response {
|
|
std::string lspath = path + urlpath;
|
|
|
|
std::cout << "FUCK " << urlpath << std::endl;
|
|
if (urlpath == "soft"
|
|
|| urlpath == "game"
|
|
|| urlpath == "web"
|
|
|| urlpath == "misc") {
|
|
repotype = "";
|
|
}
|
|
|
|
std::string title = "";
|
|
std::vector<std::string> ret;
|
|
|
|
std::string res = "<html><head><meta content=\"text/html; charset=utf-8\" "
|
|
"http-equiv=\"content-type\" />"
|
|
"<style>html { color: #fcfcfc; background-color: #232023; } "
|
|
"a { color: #ea79d8; }</style>"
|
|
"</head><body>";
|
|
|
|
if (lspath.find(".svn") != std::string::npos ||
|
|
lspath.find(".git") != std::string::npos ||
|
|
lspath.find(".hg") != std::string::npos) {
|
|
std::cerr << "アクセス禁止: " << lspath << std::endl;
|
|
res += "<p>馬鹿野郎、ここは立入禁止だろう!</p>";
|
|
res += "</body></html>";
|
|
crow::response out(403, res);
|
|
out.add_header("Content-Type", "text/html; charset=utf-8");
|
|
return out;
|
|
}
|
|
|
|
try {
|
|
if (!std::filesystem::exists(lspath)) {
|
|
std::cerr << "見つかりません: " << lspath << std::endl;
|
|
res += "<p>見つかりません。</p></body></html>";
|
|
crow::response out(404, res);
|
|
out.add_header("Content-Type", "text/html; charset=utf-8");
|
|
return out;
|
|
}
|
|
|
|
if (std::filesystem::is_regular_file(lspath)) {
|
|
if (isImage(lspath)) {
|
|
crow::response imageResponse;
|
|
std::ifstream file(lspath, std::ios::binary);
|
|
if (!file.is_open()) {
|
|
std::cerr << "エラー: ファイルを開くに失敗: " << lspath << std::endl;
|
|
res += "<p>エラー: ファイルを開くに失敗。</p></body></html>";
|
|
crow::response out(500, res);
|
|
out.add_header("Content-Type", "text/html; charset=utf-8");
|
|
return out;
|
|
}
|
|
std::ostringstream buffer;
|
|
buffer << file.rdbuf();
|
|
file.close();
|
|
|
|
std::string contentType = "image/";
|
|
if (lspath.ends_with(".jpg") || lspath.ends_with(".jpeg")) contentType += "jpeg";
|
|
else if (lspath.ends_with(".png")) contentType += "png";
|
|
else if (lspath.ends_with(".gif")) contentType += "gif";
|
|
else if (lspath.ends_with(".bmp")) contentType += "bmp";
|
|
else if (lspath.ends_with(".webp")) contentType += "webp";
|
|
|
|
imageResponse.add_header("Content-Type", contentType);
|
|
imageResponse.write(buffer.str());
|
|
return imageResponse;
|
|
}
|
|
|
|
std::ifstream file(lspath);
|
|
if (!file.is_open()) {
|
|
std::cerr << "エラー: ファイルを開くに失敗: " << lspath << std::endl;
|
|
res += "<p>エラー: ファイルを開くに失敗。</p></body></html>";
|
|
crow::response out(500, res);
|
|
out.add_header("Content-Type", "text/html; charset=utf-8");
|
|
return out;
|
|
}
|
|
|
|
std::stringstream buffer;
|
|
buffer << file.rdbuf();
|
|
file.close();
|
|
|
|
std::string content = escapeHtml(buffer.str());
|
|
|
|
res += "<h1>" + title + "</h1>";
|
|
res += generateBreadcrumb(urlpath);
|
|
if (!repotype.empty()) res += "<h2>レポジトリ種類: " + repotype + "</h2>";
|
|
res += "<pre><code>" + content + "</code></pre>";
|
|
res += "</body></html>";
|
|
crow::response out(200, res);
|
|
out.add_header("Content-Type", "text/html; charset=utf-8");
|
|
return out;
|
|
}
|
|
|
|
if (!lspath.empty() && lspath.back() != '/') lspath += '/';
|
|
|
|
if (!std::filesystem::exists(lspath)) {
|
|
std::cerr << "ディレクトリが見つかりません: " << lspath << std::endl;
|
|
res += "<p>ディレクトリが見つかりません。</p></body></html>";
|
|
crow::response out(404, res);
|
|
out.add_header("Content-Type", "text/html; charset=utf-8");
|
|
return out;
|
|
}
|
|
|
|
for (const auto &entry : std::filesystem::directory_iterator(lspath)) {
|
|
std::string fullpath = entry.path().string();
|
|
std::string showpath = fullpath.substr(lspath.length());
|
|
|
|
if (showpath == ".hg") {
|
|
repotype = "Mercurial";
|
|
continue;
|
|
}
|
|
if (showpath == ".git") {
|
|
repotype = "Git";
|
|
continue;
|
|
}
|
|
if (showpath == ".svn") {
|
|
repotype = "SVN";
|
|
continue;
|
|
}
|
|
|
|
std::string outpath = "<a href=\"/" + urlpath + "/" + showpath + "\">"
|
|
+ showpath + "</a>";
|
|
|
|
ret.push_back(outpath);
|
|
}
|
|
} catch (const std::filesystem::filesystem_error &e) {
|
|
std::cerr << "エラーが発生しました: " << e.what() << std::endl;
|
|
res += "<p>エラーが発生しました。</p></body></html>";
|
|
crow::response out(500, res);
|
|
out.add_header("Content-Type", "text/html; charset=utf-8");
|
|
return out;
|
|
}
|
|
|
|
res += "<h1>" + title + "</h1>";
|
|
res += generateBreadcrumb(urlpath);
|
|
if (!repotype.empty()) res += "<h2>レポジトリ種類: " + repotype + "</h2>";
|
|
res += "<ul>";
|
|
for (const auto &line : ret) {
|
|
res += "<li>" + line + "</li>";
|
|
}
|
|
res += "</ul>";
|
|
|
|
res += "</body></html>";
|
|
|
|
crow::response out(200, res);
|
|
out.add_header("Content-Type", "text/html; charset=utf-8");
|
|
return out;
|
|
});
|
|
|
|
website.port(8040).run();
|
|
}
|