1 /* 2 * server_settings.hpp 3 * 4 * Created on: 15 févr. 2016 5 * Author: gaudryc 6 */ 7 #pragma once 8 #ifndef WEBSERVER_SERVER_SETTINGS_HPP_ 9 #define WEBSERVER_SERVER_SETTINGS_HPP_ 10 11 #include <string> 12 #include <boost/asio.hpp> 13 #include <boost/asio/ssl.hpp> 14 #include <boost/algorithm/string.hpp> 15 16 namespace http { 17 namespace server { 18 19 struct server_settings { 20 public: server_settingshttp::server::server_settings21 server_settings() : 22 is_secure_(false) {} server_settingshttp::server::server_settings23 server_settings(const server_settings & s) : 24 www_root(s.www_root), 25 listening_address(s.listening_address), 26 listening_port(s.listening_port), 27 php_cgi_path(s.php_cgi_path), 28 is_secure_(s.is_secure_) 29 {} ~server_settingshttp::server::server_settings30 virtual ~server_settings() {} operator =http::server::server_settings31 server_settings & operator=(const server_settings & s) { 32 www_root = s.www_root; 33 listening_address = s.listening_address; 34 listening_port = s.listening_port; 35 php_cgi_path = s.php_cgi_path; 36 is_secure_ = s.is_secure_; 37 return *this; 38 } is_securehttp::server::server_settings39 bool is_secure() const { 40 return is_secure_; 41 } is_enabledhttp::server::server_settings42 bool is_enabled() const { 43 return ((listening_port != "0") && (listening_port != "")); 44 } is_php_enabledhttp::server::server_settings45 bool is_php_enabled() const { 46 return !php_cgi_path.empty(); 47 } 48 /** 49 * Set relevant values 50 */ sethttp::server::server_settings51 virtual void set(const server_settings & settings) { 52 www_root = get_valid_value(listening_address, settings.www_root); 53 listening_address = get_valid_value(listening_address, settings.listening_address); 54 listening_port = get_valid_value(listening_port, settings.listening_port); 55 php_cgi_path = get_valid_value(php_cgi_path, settings.php_cgi_path); 56 if (listening_port == "0") { 57 listening_port.clear();// server NOT enabled 58 } 59 } 60 to_stringhttp::server::server_settings61 virtual std::string to_string() const { 62 return std::string("'server_settings[is_secure_=") + (is_secure_ == true ? "true" : "false") + 63 ", www_root='" + www_root + "'" + 64 ", listening_address='" + listening_address + "'" + 65 ", listening_port='" + listening_port + "'" + 66 ", php_cgi_path='" + php_cgi_path + "'" + 67 "]'"; 68 } 69 70 protected: server_settingshttp::server::server_settings71 explicit server_settings(bool is_secure) : 72 is_secure_(is_secure) {} get_valid_valuehttp::server::server_settings73 std::string get_valid_value(const std::string & old_value, const std::string & new_value) { 74 if ((!new_value.empty()) && (new_value.compare(old_value) != 0)) { 75 return new_value; 76 } 77 return old_value; 78 } 79 public: 80 std::string www_root; 81 std::string listening_address; 82 std::string listening_port; 83 84 std::string php_cgi_path; //if not empty, php files are handled 85 //feature 86 //std::string fastcgi_php_server; (like nginx) 87 private: 88 bool is_secure_; 89 }; 90 91 #ifdef WWW_ENABLE_SSL 92 93 struct ssl_server_settings : public server_settings { 94 public: 95 std::string ssl_method; 96 std::string certificate_chain_file_path; 97 std::string ca_cert_file_path; 98 std::string cert_file_path; 99 100 std::string private_key_file_path; 101 std::string private_key_pass_phrase; 102 103 std::string ssl_options; 104 std::string tmp_dh_file_path; 105 106 bool verify_peer; 107 bool verify_fail_if_no_peer_cert; 108 std::string verify_file_path; 109 ssl_server_settingshttp::server::ssl_server_settings110 ssl_server_settings() : 111 server_settings(true), 112 verify_peer(false), 113 verify_fail_if_no_peer_cert(false) {} ssl_server_settingshttp::server::ssl_server_settings114 ssl_server_settings(const ssl_server_settings & s) : 115 server_settings::server_settings(s), 116 ssl_method(s.ssl_method), 117 certificate_chain_file_path(s.certificate_chain_file_path), 118 ca_cert_file_path(s.ca_cert_file_path), 119 cert_file_path(s.cert_file_path), 120 private_key_file_path(s.private_key_file_path), 121 private_key_pass_phrase(s.private_key_pass_phrase), 122 ssl_options(s.ssl_options), 123 tmp_dh_file_path(s.tmp_dh_file_path), 124 verify_peer(s.verify_peer), 125 verify_fail_if_no_peer_cert(s.verify_fail_if_no_peer_cert), 126 verify_file_path(s.verify_file_path) {} ~ssl_server_settingshttp::server::ssl_server_settings127 virtual ~ssl_server_settings() {} operator =http::server::ssl_server_settings128 ssl_server_settings & operator=(const ssl_server_settings & s) { 129 server_settings::operator=(s); 130 ssl_method = s.ssl_method; 131 certificate_chain_file_path = s.certificate_chain_file_path; 132 ca_cert_file_path = s.ca_cert_file_path; 133 cert_file_path = s.cert_file_path; 134 private_key_file_path = s.private_key_file_path; 135 private_key_pass_phrase = s.private_key_pass_phrase; 136 ssl_options = s.ssl_options; 137 tmp_dh_file_path = s.tmp_dh_file_path; 138 verify_peer = s.verify_peer; 139 verify_fail_if_no_peer_cert = s.verify_fail_if_no_peer_cert; 140 verify_file_path = s.verify_file_path; 141 return *this; 142 } 143 get_ssl_methodhttp::server::ssl_server_settings144 boost::asio::ssl::context::method get_ssl_method() const { 145 boost::asio::ssl::context::method method; 146 if (ssl_method.compare("tlsv1") == 0) { 147 method = boost::asio::ssl::context::tlsv1; 148 } else if (ssl_method.compare("tlsv1_server") == 0) { 149 method = boost::asio::ssl::context::tlsv1_server; 150 } else if (ssl_method.compare("sslv23") == 0) { 151 method = boost::asio::ssl::context::sslv23; 152 } else if (ssl_method.compare("sslv23_server") == 0) { 153 method = boost::asio::ssl::context::sslv23_server; 154 } else if (ssl_method.compare("tlsv11") == 0) { 155 method = boost::asio::ssl::context::tlsv11; 156 } else if (ssl_method.compare("tlsv11_server") == 0) { 157 method = boost::asio::ssl::context::tlsv11_server; 158 } else if (ssl_method.compare("tlsv12") == 0) { 159 method = boost::asio::ssl::context::tlsv12; 160 } else if (ssl_method.compare("tlsv12_server") == 0) { 161 method = boost::asio::ssl::context::tlsv12_server; 162 } else { 163 std::string error_message("invalid SSL method "); 164 error_message.append("'").append(ssl_method).append("'"); 165 throw std::invalid_argument(error_message); 166 } 167 return method; 168 } 169 get_ssl_optionshttp::server::ssl_server_settings170 boost::asio::ssl::context::options get_ssl_options() const { 171 boost::asio::ssl::context::options opts(0x0L); 172 173 std::string error_message(""); 174 175 std::vector<std::string> options_array; 176 boost::split(options_array, ssl_options, boost::is_any_of(","), boost::token_compress_on); 177 std::vector<std::string>::iterator itt; 178 for (itt = options_array.begin(); itt != options_array.end(); ++itt) { 179 std::string option = *itt; 180 if (option.compare("default_workarounds") == 0) { 181 update_options(opts, boost::asio::ssl::context::default_workarounds); 182 } else if (option.compare("single_dh_use") == 0) { 183 update_options(opts, boost::asio::ssl::context::single_dh_use); 184 } else if (option.compare("no_sslv2") == 0) { 185 update_options(opts, boost::asio::ssl::context::no_sslv2); 186 } else if (option.compare("no_sslv3") == 0) { 187 update_options(opts, boost::asio::ssl::context::no_sslv3); 188 } else if (option.compare("no_tlsv1") == 0) { 189 update_options(opts, boost::asio::ssl::context::no_tlsv1); 190 } else if (option.compare("no_tlsv1_1") == 0) { 191 update_options(opts, boost::asio::ssl::context::no_tlsv1_1); 192 } else if (option.compare("no_tlsv1_2") == 0) { 193 update_options(opts, boost::asio::ssl::context::no_tlsv1_2); 194 } else if (option.compare("no_compression") == 0) { 195 update_options(opts, boost::asio::ssl::context::no_compression); 196 } else { 197 if (error_message.empty()) { 198 error_message.append("unknown SSL option(s) : "); 199 } 200 if (error_message.find("'") != std::string::npos) { 201 error_message.append(", "); 202 } 203 error_message.append("'").append(option).append("'"); 204 } 205 } 206 if (!error_message.empty()) { 207 throw std::invalid_argument(error_message); 208 } 209 return opts; 210 } 211 212 /** 213 * Set relevant values 214 */ sethttp::server::ssl_server_settings215 virtual void set(const ssl_server_settings & ssl_settings) { 216 server_settings::set(ssl_settings); 217 218 ssl_method = server_settings::get_valid_value(ssl_method, ssl_settings.ssl_method); 219 220 std::string path = server_settings::get_valid_value(cert_file_path, ssl_settings.cert_file_path); 221 bool update_cert = path.compare(ssl_settings.cert_file_path) == 0; 222 if (update_cert) { 223 cert_file_path = ssl_settings.cert_file_path; 224 // use certificate file for all usage by default 225 certificate_chain_file_path = ssl_settings.cert_file_path; 226 ca_cert_file_path = ssl_settings.cert_file_path; 227 private_key_file_path = ssl_settings.private_key_file_path; 228 tmp_dh_file_path = ssl_settings.cert_file_path; 229 verify_file_path = ssl_settings.cert_file_path; 230 } 231 232 certificate_chain_file_path = server_settings::get_valid_value(certificate_chain_file_path, ssl_settings.certificate_chain_file_path); 233 ca_cert_file_path = server_settings::get_valid_value(ca_cert_file_path, ssl_settings.ca_cert_file_path); 234 private_key_file_path = server_settings::get_valid_value(private_key_file_path, ssl_settings.private_key_file_path); 235 private_key_pass_phrase = server_settings::get_valid_value(private_key_pass_phrase, ssl_settings.private_key_pass_phrase); 236 237 ssl_options = server_settings::get_valid_value(ssl_options, ssl_settings.ssl_options); 238 tmp_dh_file_path = server_settings::get_valid_value(tmp_dh_file_path, ssl_settings.tmp_dh_file_path); 239 240 verify_peer = ssl_settings.verify_peer; 241 verify_fail_if_no_peer_cert = ssl_settings.verify_fail_if_no_peer_cert; 242 verify_file_path = server_settings::get_valid_value(verify_file_path, ssl_settings.verify_file_path); 243 } 244 to_stringhttp::server::ssl_server_settings245 virtual std::string to_string() const override { 246 return std::string("ssl_server_settings[") + server_settings::to_string() + 247 ", ssl_method='" + ssl_method + "'" + 248 ", certificate_chain_file_path='" + certificate_chain_file_path + "'" + 249 ", ca_cert_file_path='" + ca_cert_file_path + "'" + 250 ", cert_file_path=" + cert_file_path + "'" + 251 ", private_key_file_path='" + private_key_file_path + "'" + 252 ", private_key_pass_phrase='" + private_key_pass_phrase + "'" + 253 ", ssl_options='" + ssl_options + "'" + 254 ", tmp_dh_file_path='" + tmp_dh_file_path + "'" + 255 ", verify_peer=" + (verify_peer == true ? "true" : "false") + 256 ", verify_fail_if_no_peer_cert=" + (verify_fail_if_no_peer_cert == true ? "true" : "false") + 257 ", verify_file_path='" + verify_file_path + "'" + 258 "]"; 259 } 260 261 protected: update_optionshttp::server::ssl_server_settings262 void update_options(boost::asio::ssl::context::options & opts, boost::asio::ssl::context::options option) const { 263 if (opts != 0x0L) { 264 opts |= option; 265 } else { 266 opts = option; 267 } 268 } 269 }; 270 271 #endif //#ifdef WWW_ENABLE_SSL 272 273 } // namespace server 274 } // namespace http 275 276 #endif /* WEBSERVER_SERVER_SETTINGS_HPP_ */ 277