1 #ifndef SERVER_HTTPS_HPP 2 #define SERVER_HTTPS_HPP 3 4 #include "server_http.hpp" 5 #include <boost/asio/ssl.hpp> 6 #include <openssl/ssl.h> 7 #include <algorithm> 8 9 namespace SimpleWeb { 10 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> HTTPS; 11 12 template<> 13 class Server<HTTPS> : public ServerBase<HTTPS> { 14 std::string session_id_context; 15 bool set_session_id_context=false; 16 public: Server(unsigned short port,size_t thread_pool_size,const std::string & cert_file,const std::string & private_key_file,long timeout_request=5,long timeout_content=300,const std::string & verify_file=std::string ())17 DEPRECATED Server(unsigned short port, size_t thread_pool_size, const std::string& cert_file, const std::string& private_key_file, 18 long timeout_request=5, long timeout_content=300, 19 const std::string& verify_file=std::string()) : 20 Server(cert_file, private_key_file, verify_file) { 21 config.port=port; 22 config.thread_pool_size=thread_pool_size; 23 config.timeout_request=timeout_request; 24 config.timeout_content=timeout_content; 25 } 26 Server(const std::string & cert_file,const std::string & private_key_file,const std::string & verify_file=std::string ())27 Server(const std::string& cert_file, const std::string& private_key_file, const std::string& verify_file=std::string()): 28 ServerBase<HTTPS>::ServerBase(443), context(boost::asio::ssl::context::tlsv12) { 29 context.use_certificate_chain_file(cert_file); 30 context.use_private_key_file(private_key_file, boost::asio::ssl::context::pem); 31 32 if(verify_file.size()>0) { 33 context.load_verify_file(verify_file); 34 context.set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert | 35 boost::asio::ssl::verify_client_once); 36 set_session_id_context=true; 37 } 38 } 39 start()40 void start() { 41 if(set_session_id_context) { 42 // Creating session_id_context from address:port but reversed due to small SSL_MAX_SSL_SESSION_ID_LENGTH 43 session_id_context=std::to_string(config.port)+':'; 44 session_id_context.append(config.address.rbegin(), config.address.rend()); 45 SSL_CTX_set_session_id_context(context.native_handle(), reinterpret_cast<const unsigned char*>(session_id_context.data()), 46 std::min<size_t>(session_id_context.size(), SSL_MAX_SSL_SESSION_ID_LENGTH)); 47 } 48 ServerBase::start(); 49 } 50 51 protected: 52 boost::asio::ssl::context context; 53 accept()54 void accept() { 55 //Create new socket for this connection 56 //Shared_ptr is used to pass temporary objects to the asynchronous functions 57 auto socket=std::make_shared<HTTPS>(*io_service, context); 58 59 acceptor->async_accept((*socket).lowest_layer(), [this, socket](const boost::system::error_code& ec) { 60 //Immediately start accepting a new connection (if io_service hasn't been stopped) 61 if (ec != boost::asio::error::operation_aborted) 62 accept(); 63 64 65 if(!ec) { 66 boost::asio::ip::tcp::no_delay option(true); 67 socket->lowest_layer().set_option(option); 68 69 //Set timeout on the following boost::asio::ssl::stream::async_handshake 70 auto timer=get_timeout_timer(socket, config.timeout_request); 71 socket->async_handshake(boost::asio::ssl::stream_base::server, [this, socket, timer] 72 (const boost::system::error_code& ec) { 73 if(timer) 74 timer->cancel(); 75 if(!ec) 76 read_request_and_content(socket); 77 else if(on_error) 78 on_error(std::shared_ptr<Request>(new Request(*socket)), ec); 79 }); 80 } 81 else if(on_error) 82 on_error(std::shared_ptr<Request>(new Request(*socket)), ec); 83 }); 84 } 85 }; 86 } 87 88 89 #endif /* SERVER_HTTPS_HPP */ 90 91