summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--TODO1
-rw-r--r--config.cpp88
-rw-r--r--config.h9
-rw-r--r--https.cpp14
-rw-r--r--plugin.cpp7
5 files changed, 68 insertions, 51 deletions
diff --git a/TODO b/TODO
index 584b690..76149ec 100644
--- a/TODO
+++ b/TODO
@@ -1,4 +1,3 @@
-Speed up config.GetPath
weblog: link consistency check (cron?)
Integrate into Debian: WNPP
support alternative SSL libs: mbedtls, gnutls, wolfssl, botan, (matrixssl, libressl, cryptlib: not in debian)
diff --git a/config.cpp b/config.cpp
index 2ece1ef..ed28ea9 100644
--- a/config.cpp
+++ b/config.cpp
@@ -56,15 +56,16 @@ void Config::readConfigfile(std::string filename)
for (const auto& site: element.second) {
if (site.first != "site"s)
throw std::runtime_error("<site> expected in <sites>");
+ std::string site_name;
Site site_struct;
for (const auto& x: site.second) {
if (x.first == "name"s) {
- if (site_struct.name == "")
- site_struct.name = x.second.data();
+ if (site_name == "")
+ site_name = x.second.data();
else
throw std::runtime_error("Found double site name: "s + x.second.data());
} else if (x.first == "host"s) {
- if (std::find(site_struct.hosts.begin(), site_struct.hosts.end(), x.second.data()) == site_struct.hosts.end())
+ if (site_struct.hosts.find(x.second.data()) == site_struct.hosts.end())
site_struct.hosts.insert(x.second.data());
else
throw std::runtime_error("Found double site host element: "s + x.second.data());
@@ -110,10 +111,12 @@ void Config::readConfigfile(std::string filename)
} else
throw std::runtime_error("Unknown element: "s + x.first);
}
- if (std::find_if(m_sites.begin(), m_sites.end(), [&](const Site& site){return site.name == site_struct.name;}) == m_sites.end())
- m_sites.push_back(site_struct);
+ if (site_name.empty())
+ throw std::runtime_error("Empty site name");
+ if (m_sites.find(site_name) == m_sites.end())
+ m_sites[site_name] = site_struct;
else
- throw std::runtime_error("Found double site spec: "s + site_struct.name);
+ throw std::runtime_error("Found double site spec: "s + site_name);
}
} else if (element.first == "sockets"s) {
for (const auto& socket: element.second) {
@@ -140,10 +143,10 @@ void Config::readConfigfile(std::string filename)
throw std::runtime_error("Unknown protocol: "s + x.second.data());
} else if (x.first == "site"s) {
std::string site {x.second.data()};
- if (std::find(socket_struct.serve_sites.begin(), socket_struct.serve_sites.end(), site) == socket_struct.serve_sites.end()) {
- socket_struct.serve_sites.push_back(site);
+ if (socket_struct.serve_sites.find(site) == socket_struct.serve_sites.end()) {
+ socket_struct.serve_sites.insert(site);
} else {
- throw std::runtime_error("Site "s + site + " already defined for "s + socket_struct.address + " port " + socket_struct.port);
+ throw std::runtime_error("Site "s + site + " already defined for "s + socket_struct.address + ", port " + socket_struct.port);
}
} else
throw std::runtime_error("Unknown element: "s + x.first);
@@ -161,10 +164,26 @@ void Config::readConfigfile(std::string filename)
for (auto& socket: m_sockets) {
if (socket.serve_sites.empty()) {
for (const auto& site: m_sites) {
- socket.serve_sites.push_back(site.name);
+ socket.serve_sites.insert(site.first);
}
}
}
+
+ validate();
+}
+
+// just throws on inconsistency
+void Config::validate()
+{
+ // make sure all m_sockets.serve_sites are configured in m_sites
+
+ for (auto& socket: m_sockets) {
+ for (auto& serve_site: socket.serve_sites) {
+ if (m_sites.find(serve_site) == m_sites.end())
+ throw std::runtime_error("Found serve_site "s + serve_site + " without configured site"s);
+ }
+ }
+
}
Config::Config(const std::string& filename)
@@ -193,7 +212,7 @@ const std::vector<std::string>& Config::PluginDirectories() const
return m_plugin_directories;
}
-const std::vector<Site>& Config::Sites() const
+const std::unordered_map<std::string, Site>& Config::Sites() const
{
return m_sites;
}
@@ -217,21 +236,21 @@ void Config::dump() const
std::cout << std::endl;
for (const auto& site: m_sites) {
- std::cout << "Site: " << site.name << ":";
- for (const auto& host: site.hosts)
+ std::cout << "Site: " << site.first << ":";
+ for (const auto& host: site.second.hosts)
std::cout << " " << host;
std::cout << std::endl;
- if (site.paths.size() == 0)
+ if (site.second.paths.size() == 0)
std::cout << " Warning: No paths configured." << std::endl;
- for (const auto& path: site.paths) {
+ for (const auto& path: site.second.paths) {
std::cout << " Path: " << path.requested << 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;
+ if (site.second.key_path != ""s) {
+ std::cout << " Key: " << site.second.key_path.generic_string() << std::endl;
+ std::cout << " Cert: " << site.second.cert_path.generic_string() << std::endl;
}
}
@@ -251,29 +270,26 @@ const Path& Config::GetPath(const Socket& socket, const std::string& requested_h
{
//boost::timer::auto_cpu_timer t;
- // TODO: speed this up
std::string host{requested_host};
const Path* result{nullptr};
size_t path_len{0}; // find longest matching prefix
RemovePortFromHostname(host);
- 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) &&
- ("/?"s.find(requested_path[path.requested.size()]) != std::string::npos ||
- requested_path[path.requested.size()] == 0 ||
- requested_path[path.requested.size() - 1] == '/'
- ) &&
- path.requested.size() > path_len)
- {
- path_len = path.requested.size();
- result = &path;
- }
- }
+ for (const auto& site_name: socket.serve_sites) {
+ const Site& site {m_sites.at(site_name)}; // omit error check: validation previously made sure this exists
+
+ if (site.hosts.find(host) != site.hosts.end()) {
+ for (const auto& path: site.paths) {
+ if (boost::starts_with(requested_path, path.requested) &&
+ ("/?"s.find(requested_path[path.requested.size()]) != std::string::npos ||
+ requested_path[path.requested.size()] == 0 ||
+ requested_path[path.requested.size() - 1] == '/'
+ ) &&
+ path.requested.size() > path_len)
+ {
+ path_len = path.requested.size();
+ result = &path;
}
}
}
@@ -288,7 +304,7 @@ const Path& Config::GetPath(const Socket& socket, const std::string& requested_h
bool Config::PluginIsConfigured(const std::string& name) const
{
for (const auto& site: m_sites) {
- for (const auto& path: site.paths) {
+ for (const auto& path: site.second.paths) {
auto it{path.params.find("plugin")};
if (it != path.params.end() && it->second == name)
return true;
diff --git a/config.h b/config.h
index 46cd267..e60bba5 100644
--- a/config.h
+++ b/config.h
@@ -18,7 +18,7 @@ struct Path
struct Site
{
- std::string name;
+ // std::string name; is the index in the m_sites map
std::unordered_set<std::string> hosts;
std::vector<Path> paths;
fs::path cert_path;
@@ -36,7 +36,7 @@ struct Socket
std::string address;
std::string port;
SocketProtocol protocol;
- std::vector<std::string> serve_sites; // if empty, automatically expand to all configured sites
+ std::unordered_set<std::string> serve_sites; // if empty, automatically expand to all configured sites
};
class Config
@@ -44,12 +44,13 @@ class Config
const std::string default_filename{"/etc/webserver.conf"};
void readConfigfile(std::string filename);
+ void validate();
std::string m_user;
std::string m_group;
int m_threads;
std::vector<std::string> m_plugin_directories;
- std::vector<Site> m_sites;
+ std::unordered_map<std::string, Site> m_sites;
std::vector<Socket> m_sockets;
public:
@@ -62,7 +63,7 @@ class Config
int Threads() const;
const std::vector<std::string>& PluginDirectories() const;
- const std::vector<Site>& Sites() const;
+ const std::unordered_map<std::string, Site>& Sites() const;
const std::vector<Socket>& Sockets() const;
//
diff --git a/https.cpp b/https.cpp
index 508ece9..a5aa118 100644
--- a/https.cpp
+++ b/https.cpp
@@ -660,15 +660,15 @@ void Server::load_certificates()
// import the real certificates
for (const auto& serve_site: m_socket.serve_sites) {
for (const auto& site: m_config.Sites()) {
- if (site.name == serve_site) {
+ if (site.first == serve_site) {
std::shared_ptr<ssl::context> ctx {std::make_shared<ssl::context>(tls_method)};
std::cout << "Creating SSL context/cert for site " << serve_site << " on port " << m_socket.port << std::endl;
- load_server_certificate(*ctx, site.cert_path, site.key_path);
+ load_server_certificate(*ctx, site.second.cert_path, site.second.key_path);
SSL_CTX_set_client_hello_cb(ctx->native_handle(), servername_callback, &m_ctx);
- for (const auto& host: site.hosts) {
+ for (const auto& host: site.second.hosts) {
std::cout << " Adding Host " << host << std::endl;
m_ctx.emplace(host, ctx);
}
@@ -681,19 +681,19 @@ void Server::reload_certificates()
{
for (const auto& serve_site: m_socket.serve_sites) {
for (const auto& site: m_config.Sites()) {
- if (site.name == serve_site) {
+ if (site.first == serve_site) {
std::cout << "Updating SSL context/cert for site " << serve_site << " on port " << m_socket.port << std::endl;
- auto it_host {site.hosts.begin()};
- if (it_host == site.hosts.end()) {
+ auto it_host {site.second.hosts.begin()};
+ if (it_host == site.second.hosts.end()) {
std::cout << " Warning: No configured host found." << std::endl;
} else {
auto it_ctx {m_ctx.find(*it_host)};
if (it_ctx == m_ctx.end()) {
std::cout << " Warning: No context found for configured host." << std::endl;
} else {
- load_server_certificate(*it_ctx->second, site.cert_path, site.key_path);
+ load_server_certificate(*it_ctx->second, site.second.cert_path, site.second.key_path);
}
}
}
diff --git a/plugin.cpp b/plugin.cpp
index 28fdb62..afcbdb3 100644
--- a/plugin.cpp
+++ b/plugin.cpp
@@ -64,22 +64,23 @@ void PluginLoader::load_plugins()
}
}
+// validate config regarding plugins
bool PluginLoader::validate_config()
{
const auto& sites{m_config.Sites()};
for (const auto& site: sites) {
- for (const auto& path: site.paths) {
+ for (const auto& path: site.second.paths) {
// path must contain target and plugin
auto it {path.params.find("target")};
if (it == path.params.end()) {
- std::cout << "Path " << path.requested << " for site " << site.name << " is missing target specification." << std::endl;
+ std::cout << "Path " << path.requested << " for site " << site.first << " is missing target specification." << std::endl;
return false;
}
it = path.params.find("plugin");
if (it == path.params.end()) {
- std::cout << "Path " << path.requested << " for site " << site.name << " is missing plugin specification." << std::endl;
+ std::cout << "Path " << path.requested << " for site " << site.first << " is missing plugin specification." << std::endl;
return false;
}