Loading src/httpd.cpp +52 −0 Original line number Diff line number Diff line Loading @@ -2265,6 +2265,34 @@ libhttppp::HttpD::HttpD(const std::string& httpaddr, int port,int maxconnections } } libhttppp::HttpD::HttpD(const std::string &httpaddr, int port, int maxconnections, const std::map<std::string, netplus::ssl::CertificateBundle> &certsByHostname) { try { _fileServer = false; if (certsByHostname.empty()) { _httpexception[HTTPException::Critical] << "HttpD SNI ctor requires at least one hostname->cert entry"; throw _httpexception; } _certBundle = certsByHostname; for (auto &[hostname, bundle] : _certBundle) { if (!bundle.cert.checkValidity()) { time_t now = time(nullptr); _httpexception[HTTPException::Critical] << "invalid certfile for hostname " << hostname << " (CN=" << bundle.cert.getSubjectCN() << ", system_time=" << now << ")"; throw _httpexception; } } auto tss = std::make_unique<netplus::ssl>(_certBundle, httpaddr, port, maxconnections, -1); auto qss = std::make_unique<netplus::quic>(_certBundle, httpaddr, port, maxconnections, -1); _ServerSockets.push_back(std::move(tss)); _ServerSockets.push_back(std::move(qss)); } catch (netplus::NetException &e) { HTTPException ee; ee[HTTPException::Critical] << e.what(); throw ee; } } std::vector<netplus::socket*> libhttppp::HttpD::getServerSockets(){ std::vector<netplus::socket*> sockets; for (auto &sock : _ServerSockets) { Loading Loading @@ -2298,5 +2326,29 @@ bool libhttppp::HttpD::reloadCertificates(const std::string &certpath, const std return true; } bool libhttppp::HttpD::reloadCertificate(const std::string &hostname, const std::string &certpath, const std::string &keypath, const std::string &password) { netplus::ssl::CertificateBundle bundle; if (!bundle.loadFromFile(certpath, keypath, password)) { return false; } if (!bundle.cert.checkValidity()) { return false; } // Unlike reloadCertificates() above, only this one hostname's entry is replaced -- every // other hostname bound to this listener keeps its own, unrelated certificate. _certBundle[hostname] = bundle; for (auto &sock : _ServerSockets) { if (auto *s = dynamic_cast<netplus::ssl*>(sock.get())) { s->setCertificates(_certBundle); } else if (auto *q = dynamic_cast<netplus::quic*>(sock.get())) { q->setCertificates(_certBundle); } } return true; } libhttppp::HttpD::~HttpD(){ } src/httpd.h +11 −0 Original line number Diff line number Diff line Loading @@ -186,11 +186,22 @@ namespace libhttppp { public: HttpD(int argc, char** argv); HttpD(const std::string &httpaddr, int port, int maxconnections, const std::string &sslcertpath, const std::string &sslkeypath, const std::string &sslpassword = ""); // SNI virtual hosting: certsByHostname is keyed by the SNI hostname each bundle should // be presented for (unlike the single-cert ctor above, whose _certBundle ends up keyed // by httpaddr) -- netplus::ssl/quic pick a bundle per-connection from this map by // matching the ClientHello's requested hostname, see netplus::tls::cert_map. HttpD(const std::string &httpaddr, int port, int maxconnections, const std::map<std::string, netplus::ssl::CertificateBundle> &certsByHostname); ~HttpD(); std::vector<netplus::socket*> getServerSockets(); // Reload SSL certificates from file(s). Updates all ssl/quic server sockets. bool reloadCertificates(const std::string &certpath, const std::string &keypath, const std::string &password = ""); // Reload just one SNI hostname's bundle (for a multi-hostname HttpD from the ctor // above) without disturbing any other hostname's certificate. bool reloadCertificate(const std::string &hostname, const std::string &certpath, const std::string &keypath, const std::string &password = ""); protected: void FileServer(); private: Loading Loading
src/httpd.cpp +52 −0 Original line number Diff line number Diff line Loading @@ -2265,6 +2265,34 @@ libhttppp::HttpD::HttpD(const std::string& httpaddr, int port,int maxconnections } } libhttppp::HttpD::HttpD(const std::string &httpaddr, int port, int maxconnections, const std::map<std::string, netplus::ssl::CertificateBundle> &certsByHostname) { try { _fileServer = false; if (certsByHostname.empty()) { _httpexception[HTTPException::Critical] << "HttpD SNI ctor requires at least one hostname->cert entry"; throw _httpexception; } _certBundle = certsByHostname; for (auto &[hostname, bundle] : _certBundle) { if (!bundle.cert.checkValidity()) { time_t now = time(nullptr); _httpexception[HTTPException::Critical] << "invalid certfile for hostname " << hostname << " (CN=" << bundle.cert.getSubjectCN() << ", system_time=" << now << ")"; throw _httpexception; } } auto tss = std::make_unique<netplus::ssl>(_certBundle, httpaddr, port, maxconnections, -1); auto qss = std::make_unique<netplus::quic>(_certBundle, httpaddr, port, maxconnections, -1); _ServerSockets.push_back(std::move(tss)); _ServerSockets.push_back(std::move(qss)); } catch (netplus::NetException &e) { HTTPException ee; ee[HTTPException::Critical] << e.what(); throw ee; } } std::vector<netplus::socket*> libhttppp::HttpD::getServerSockets(){ std::vector<netplus::socket*> sockets; for (auto &sock : _ServerSockets) { Loading Loading @@ -2298,5 +2326,29 @@ bool libhttppp::HttpD::reloadCertificates(const std::string &certpath, const std return true; } bool libhttppp::HttpD::reloadCertificate(const std::string &hostname, const std::string &certpath, const std::string &keypath, const std::string &password) { netplus::ssl::CertificateBundle bundle; if (!bundle.loadFromFile(certpath, keypath, password)) { return false; } if (!bundle.cert.checkValidity()) { return false; } // Unlike reloadCertificates() above, only this one hostname's entry is replaced -- every // other hostname bound to this listener keeps its own, unrelated certificate. _certBundle[hostname] = bundle; for (auto &sock : _ServerSockets) { if (auto *s = dynamic_cast<netplus::ssl*>(sock.get())) { s->setCertificates(_certBundle); } else if (auto *q = dynamic_cast<netplus::quic*>(sock.get())) { q->setCertificates(_certBundle); } } return true; } libhttppp::HttpD::~HttpD(){ }
src/httpd.h +11 −0 Original line number Diff line number Diff line Loading @@ -186,11 +186,22 @@ namespace libhttppp { public: HttpD(int argc, char** argv); HttpD(const std::string &httpaddr, int port, int maxconnections, const std::string &sslcertpath, const std::string &sslkeypath, const std::string &sslpassword = ""); // SNI virtual hosting: certsByHostname is keyed by the SNI hostname each bundle should // be presented for (unlike the single-cert ctor above, whose _certBundle ends up keyed // by httpaddr) -- netplus::ssl/quic pick a bundle per-connection from this map by // matching the ClientHello's requested hostname, see netplus::tls::cert_map. HttpD(const std::string &httpaddr, int port, int maxconnections, const std::map<std::string, netplus::ssl::CertificateBundle> &certsByHostname); ~HttpD(); std::vector<netplus::socket*> getServerSockets(); // Reload SSL certificates from file(s). Updates all ssl/quic server sockets. bool reloadCertificates(const std::string &certpath, const std::string &keypath, const std::string &password = ""); // Reload just one SNI hostname's bundle (for a multi-hostname HttpD from the ctor // above) without disturbing any other hostname's certificate. bool reloadCertificate(const std::string &hostname, const std::string &certpath, const std::string &keypath, const std::string &password = ""); protected: void FileServer(); private: Loading