#include "config.h" #include #include #include #include namespace pt = boost::property_tree; using namespace std::string_literals; void Config::readConfigfile(std::string filename) { if (filename == "") { filename = default_filename; } pt::ptree tree; pt::read_xml(filename, tree, pt::xml_parser::no_comments | pt::xml_parser::trim_whitespace); // mandatory m_user = tree.get("webserver.user"); m_group = tree.get("webserver.group"); m_threads = tree.get("webserver.threads"); // optional entries auto elements = tree.get_child_optional("webserver"); if (elements) { for (const auto& element: *elements) { if (element.first == "plugin-directory"s) { m_plugin_directories.push_back(element.second.data()); } else if (element.first == "sites"s) { for (const auto& site: element.second) { if (site.first != "site"s) throw std::runtime_error(" expected in "); Site site_struct; for (const auto& x: site.second) { if (x.first == "name"s) { site_struct.name = x.second.data(); } else if (x.first == "host"s) { site_struct.hosts.insert(x.second.data()); } else if (x.first == "path"s) { Path path; auto attrs = x.second.get_child(""); path.requested = attrs.get("requested"); std::string type = attrs.get("type"); if (type == "files") { path.type = Files; } else if (type == "plugin") { path.type = Plugin; } else throw std::runtime_error("Unknown type: "s + type); for (const auto& param: x.second) { if (param.first.size() > 0 && param.first[0] != '<') // exclude meta-elements like path.params[param.first.data()] = param.second.data(); } site_struct.paths.push_back(path); } else if (x.first == "certpath"s) { site_struct.cert_path = x.second.data(); } else if (x.first == "keypath"s) { site_struct.key_path = x.second.data(); } else throw std::runtime_error("Unknown element: "s + x.first); } m_sites.push_back(site_struct); } } else if (element.first == "sockets"s) { for (const auto& socket: element.second) { if (socket.first != "socket"s) throw std::runtime_error(" expected in "); Socket socket_struct; for (const auto& x: socket.second) { if (x.first == "address"s) { socket_struct.address = x.second.data(); } else if (x.first == "port"s) { socket_struct.port = x.second.data(); } else if (x.first == "protocol"s) { if (x.second.data() == "http"s) socket_struct.protocol = SocketProtocol::HTTP; else if (x.second.data() == "https"s) socket_struct.protocol = SocketProtocol::HTTPS; else throw std::runtime_error("Unknown protocol: "s + x.second.data()); } else throw std::runtime_error("Unknown element: "s + x.first); } if (geteuid() != 0 && stoi(socket_struct.port) < 1024) std::cout << "Warning: Skipping privileged port " << socket_struct.port << std::endl; else m_sockets.push_back(socket_struct); } } } } // expand socket sites for (auto& socket: m_sockets) { if (socket.serve_sites.empty()) { for (const auto& site: m_sites) { socket.serve_sites.push_back(site.name); } } } } Config::Config(const std::string& filename) { readConfigfile(filename); dump(); } std::string Config::User() const { return m_user; } std::string Config::Group() const { return m_group; } int Config::Threads() const { return m_threads; } const std::vector& Config::PluginDirectories() const { return m_plugin_directories; } const std::vector& Config::Sites() const { return m_sites; } const std::vector& Config::Sockets() const { return m_sockets; } void Config::dump() const { std::cout << "=== Configuration ===========================" << std::endl; std::cout << "User: " << m_user << std::endl; std::cout << "Group: " << m_user << std::endl; std::cout << "Threads: " << m_threads << std::endl; std::cout << "Plugin Directories:"; for (const auto& dir: m_plugin_directories) std::cout << " " << dir; std::cout << std::endl; for (const auto& site: m_sites) { std::cout << "Site: " << site.name << ":"; for (const auto& host: site.hosts) std::cout << " " << host; std::cout << std::endl; if (site.paths.size() == 0) std::cout << " Warning: No paths configured." << std::endl; for (const auto& path: site.paths) { std::cout << " Path: " << path.requested << " -> " << ((path.type == Files) ? "files" : "plugin") << std::endl; for (const auto& param: path.params) { std::cout << " " << param.first << ": " << param.second << std::endl; } } if (site.key_path != ""s) { std::cout << " Key: " << site.key_path.generic_string() << std::endl; std::cout << " Cert: " << site.cert_path.generic_string() << std::endl; } } for (const auto& socket: m_sockets) { std::cout << "Socket: " << socket.address << ":" << socket.port << " (" << (socket.protocol == SocketProtocol::HTTP ? "HTTP" : "HTTPS") << ")" << std::endl; std::cout << " Serving:"; for (const auto& site: socket.serve_sites) { std::cout << " " << site; } std::cout << std::endl; } std::cout << "=============================================" << std::endl; } std::string Config::DocRoot(const Socket& socket, const std::string& requested_host, const std::string& requested_path) const { // TODO: speed this up std::string host{requested_host}; std::string result; auto pos {host.find(':')}; if (pos != host.npos) { host = host.substr(0, pos); } for (const auto& site: m_sites) { if (std::find(socket.serve_sites.begin(), socket.serve_sites.end(), site.name) != socket.serve_sites.end()) { for (const auto& m_host: site.hosts) { if (m_host == host) { for (const auto& path: site.paths) { if (boost::starts_with(requested_path, path.requested)) { const auto& root { path.params.at("target")}; if (root.size() > result.size()) result = root; } } } } } } return result; }