diff options
| -rw-r--r-- | TODO | 3 | ||||
| -rw-r--r-- | config.cpp | 21 | ||||
| -rw-r--r-- | config.h | 5 | ||||
| -rw-r--r-- | http.cpp | 54 | ||||
| -rw-r--r-- | http.h | 13 | ||||
| -rw-r--r-- | https.cpp | 57 | ||||
| -rw-r--r-- | https.h | 21 | ||||
| -rw-r--r-- | server.cpp | 56 | ||||
| -rw-r--r-- | server.h | 12 | ||||
| -rw-r--r-- | webserver.conf | 20 | 
10 files changed, 179 insertions, 83 deletions
@@ -1,7 +1,4 @@ -HTTP+HTTPS: https://www.boost.org/doc/libs/1_72_0/libs/beast/doc/html/beast/examples.html#beast.examples.servers  Certbot: https://certbot.eff.org/lets-encrypt/debianbuster-other  Webbox  Debian 10  alternative hosts www, lists, ... - -Selective sites per Socket @@ -40,7 +40,7 @@ void Config::readConfigfile(std::string filename)        if (x.first == "name"s) {         site_struct.name = x.second.data();        } else if (x.first == "host"s) { -       site_struct.host = x.second.data(); +       site_struct.hosts.insert(x.second.data());        } else if (x.first == "path"s) {         Path path;         auto attrs = x.second.get_child("<xmlattr>"); @@ -91,6 +91,15 @@ void Config::readConfigfile(std::string filename)     }    }   } + + // 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) @@ -143,7 +152,10 @@ void Config::dump() const   std::cout << std::endl;   for (const auto& site: m_sites) { -  std::cout << "Site: " << site.name << ": " << site.host << std::endl; +  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) { @@ -160,6 +172,11 @@ void Config::dump() const     std::cout << "  Key: " << socket.key_path.generic_string() << std::endl;     std::cout << "  Cert: " << socket.cert_path.generic_string() << std::endl;    } +  std::cout << "  Serving:"; +  for (const auto& site: socket.serve_sites) { +   std::cout << " " << site; +  } +  std::cout << std::endl;   }   std::cout << "=============================================" << std::endl;  } @@ -3,6 +3,7 @@  #include <filesystem>  #include <string>  #include <unordered_map> +#include <unordered_set>  #include <vector>  namespace fs = std::filesystem; @@ -23,7 +24,7 @@ struct Path  struct Site  {   std::string name; - std::string host; + std::unordered_set<std::string> hosts;   std::vector<Path> paths;  }; @@ -38,7 +39,7 @@ struct Socket   std::string address;   std::string port;   SocketProtocol protocol; - std::vector<std::string> serve_sites; // if empty, serve all configured sites // TODO: implement + std::vector<std::string> serve_sites; // if empty, automatically expand to all configured sites   fs::path cert_path;   fs::path key_path;  }; @@ -153,6 +153,7 @@ handle_request(      // Build the path to the requested file      std::string path = path_cat(doc_root, req.target()); +    std::cout << "DEBUG: " << req["host"] << std::endl;      if(req.target().back() == '/')          path.append("index.html"); @@ -446,35 +447,28 @@ private:  namespace HTTP { -int server(Config& config) -{ -    // TODO: Config -    auto const address = net::ip::make_address(config.Sockets()[0].address); -    auto const port = static_cast<unsigned short>(std::atoi(config.Sockets()[0].port.data())); -    auto const doc_root = std::make_shared<std::string>(config.Sites()[0].paths[0].params.at("target")); -    auto const threads = std::max<int>(1, config.Threads()); - -    // The io_context is required for all I/O -    net::io_context ioc{threads}; - -    // Create and launch a listening port -    std::make_shared<listener>( -        ioc, -        tcp::endpoint{address, port}, -        doc_root)->run(); - -    // Run the I/O service on the requested number of threads -    std::vector<std::thread> v; -    v.reserve(threads - 1); -    for(auto i = threads - 1; i > 0; --i) -        v.emplace_back( -        [&ioc] -        { -            ioc.run(); -        }); -    ioc.run(); - -    return EXIT_SUCCESS; -} + Server::Server(Config& config, boost::asio::io_context& ioc, const Socket& socket): ::Server(config, ioc), m_socket(socket) + { + } + + Server::~Server() + { + } + + int Server::start() + { +  // TODO: Config +  auto const address = net::ip::make_address(m_socket.address); +  auto const port = static_cast<unsigned short>(std::atoi(m_socket.port.data())); +  auto const doc_root = std::make_shared<std::string>(m_config.Sites()[0].paths[0].params.at("target")); + +  // Create and launch a listening port +  std::make_shared<listener>( +   m_ioc, +   tcp::endpoint{address, port}, +   doc_root)->run(); + +  return EXIT_SUCCESS; + }  } // namespace HTTP @@ -1,9 +1,20 @@  #pragma once +#include <boost/asio/dispatch.hpp> +#include <boost/asio/strand.hpp> +  #include "config.h" +#include "server.h"  namespace HTTP { -int server(Config& config); +class Server: public ::Server +{ + const Socket& m_socket; +public: + Server(Config& config, boost::asio::io_context& ioc, const Socket& socket); + virtual ~Server(); + int start() override; +};  } // namespace HTTP @@ -515,42 +515,31 @@ private:  namespace HTTPS { -int server(Config& config) +Server::Server(Config& config, boost::asio::io_context& ioc, const Socket& socket): ::Server(config, ioc), m_socket(socket)  { -    // TODO: Config -    auto const address = net::ip::make_address(config.Sockets()[0].address); -    auto const port = static_cast<unsigned short>(std::atoi(config.Sockets()[0].port.data())); -    auto const doc_root = std::make_shared<std::string>(config.Sites()[0].paths[0].params.at("target")); -    auto const threads = std::max<int>(1, config.Threads()); - -    // The io_context is required for all I/O -    net::io_context ioc{threads}; - -    // The SSL context is required, and holds certificates -    ssl::context ctx{ssl::context::tlsv13}; - -    // This holds the self-signed certificate used by the server -    load_server_certificate(ctx, config.Sockets()[0].cert_path, config.Sockets()[0].key_path); // TODO: config - -    // Create and launch a listening port -    std::make_shared<listener>( -        ioc, -        ctx, -        tcp::endpoint{address, port}, -        doc_root)->run(); - -    // Run the I/O service on the requested number of threads -    std::vector<std::thread> v; -    v.reserve(threads - 1); -    for(auto i = threads - 1; i > 0; --i) -        v.emplace_back( -        [&ioc] -        { -            ioc.run(); -        }); -    ioc.run(); + // This holds the self-signed certificate used by the server + load_server_certificate(m_ctx, m_socket.cert_path, m_socket.key_path); +} + +Server::~Server() +{ +} -    return EXIT_SUCCESS; +int Server::start() +{ + // TODO: Config + auto const address = net::ip::make_address(m_socket.address); + auto const port = static_cast<unsigned short>(std::atoi(m_socket.port.data())); + auto const doc_root = std::make_shared<std::string>(m_config.Sites()[0].paths[0].params.at("target")); + + // Create and launch a listening port + std::make_shared<listener>( +     m_ioc, +     m_ctx, +     tcp::endpoint{address, port}, +     doc_root)->run(); + + return EXIT_SUCCESS;  }  } // namespace HTTPS @@ -1,9 +1,28 @@  #pragma once +#include <boost/asio/dispatch.hpp> +#include <boost/asio/strand.hpp> +#include <boost/beast/ssl.hpp> +#include <boost/asio/ssl.hpp> +  #include "config.h" +#include "server.h" + +namespace ssl = boost::asio::ssl;       // from <boost/asio/ssl.hpp>  namespace HTTPS { -int server(Config& config); +class Server: public ::Server +{ + // The SSL context is required, and holds certificates + ssl::context m_ctx{ssl::context::tlsv13}; + const Socket& m_socket; + +public: + Server(Config& config, boost::asio::io_context& ioc, const Socket& socket); + virtual ~Server(); + + int start() override; +};  } @@ -1,10 +1,62 @@ +#include <boost/beast/core.hpp> +#include <boost/beast/http.hpp> +#include <boost/beast/version.hpp> +#include <boost/beast/ssl.hpp> +#include <boost/asio/dispatch.hpp> +#include <boost/asio/strand.hpp> +#include <boost/config.hpp> + +#include <thread> +#include <vector> +  #include "server.h"  #include "http.h"  #include "https.h" +namespace beast = boost::beast;         // from <boost/beast.hpp> +namespace http = beast::http;           // from <boost/beast/http.hpp> +namespace net = boost::asio;            // from <boost/asio.hpp> +namespace ssl = boost::asio::ssl;       // from <boost/asio/ssl.hpp> +using tcp = boost::asio::ip::tcp;       // from <boost/asio/ip/tcp.hpp> + +Server::Server(Config& config, boost::asio::io_context& ioc): m_config(config), m_ioc(ioc) +{ +} + +Server::~Server() +{ +} +  int server(Config& config)  { - //return HTTP::server(config); - return HTTPS::server(config); + auto const threads = std::max<int>(1, config.Threads()); + + boost::asio::io_context ioc{threads}; + + std::vector<std::shared_ptr<Server>> servers; + + const auto& sockets {config.Sockets()}; + for (const auto& socket: sockets) { +  if (socket.protocol == SocketProtocol::HTTP) { +   servers.push_back(std::make_shared<HTTP::Server>(config, ioc, socket)); +  } else { +   servers.push_back(std::make_shared<HTTPS::Server>(config, ioc, socket)); +  } +  servers.back()->start(); + } + + // Run the I/O service on the requested number of threads + std::vector<std::thread> v; + v.reserve(threads - 1); + for(auto i = threads - 1; i > 0; --i) +     v.emplace_back( +     [&ioc] +     { +         ioc.run(); +     }); + ioc.run(); + + return EXIT_SUCCESS;   } + @@ -6,4 +6,16 @@ using namespace std::string_literals;  static const std::string VersionString{ "Webserver "s + std::string{VERSION} }; +class Server +{ +protected: + Config& m_config; + boost::asio::io_context& m_ioc; + +public: + Server(Config& config, boost::asio::io_context& ioc); + virtual ~Server(); + virtual int start() = 0; +}; +  int server(Config& config); diff --git a/webserver.conf b/webserver.conf index 2036f67..46d4120 100644 --- a/webserver.conf +++ b/webserver.conf @@ -11,6 +11,8 @@    <site>     <name>antcom.de</name>     <host>lists.antcom.de</host> +   <host>antcom.de</host> +   <host>www.antcom.de</host>     <path requested="/" type="files">      <target>/home/ernie/homepage/test</target>     </path> @@ -21,11 +23,15 @@     </path>     -->    </site> -  <!--    <site> -   <name>reichwein.it</name> -   <host>reichwein.it</host> +   <name>marx</name> +   <host>marx.antcom.de</host> +   <path requested="/" type="files"> +    <target>/home/ernie/homepage/test1</target> +   </path>    </site> +  <!-- +  reichwein.it    danielareichwein.de    rolandreichwein.de    kneipenband.com @@ -36,20 +42,18 @@     <address>127.0.0.1</address>     <port>8080</port>     <protocol>http</protocol> -   <certpath>/home/ernie/code/webserver/fullchain.pem</certpath> -   <keypath>/home/ernie/code/webserver/privkey.pem</keypath>     <!--     <site>antcom.de</site>     <site>reichwein.it</site>     -->    </socket> -  <!--    <socket>     <address>127.0.0.1</address> -   <port>443</port> +   <port>8081</port>     <protocol>https</protocol> +   <certpath>/home/ernie/code/webserver/fullchain.pem</certpath> +   <keypath>/home/ernie/code/webserver/privkey.pem</keypath>    </socket> -  -->   </sockets>  </webserver>  | 
