@@ -763,193 +763,201 @@ void webserver::unregister_ws_resource(const std::string& resource) {
763763#endif
764764}
765765
766- bool webserver::start (bool blocking) {
767- struct {
768- MHD_OptionItem operator ()(enum MHD_OPTION opt, intptr_t val, void *ptr = nullptr ) {
769- MHD_OptionItem x = {opt, val, ptr};
770- return x;
771- }
772- } gen;
773- vector<struct MHD_OptionItem > iov;
766+ namespace detail {
774767
775- iov.push_back (gen (MHD_OPTION_NOTIFY_COMPLETED , (intptr_t ) &detail::webserver_impl::request_completed, nullptr ));
768+ // Wrap MHD_OptionItem aggregate-init so each push reads uniformly
769+ // across the option-array builders below. Replaces the local
770+ // struct-with-operator() that used to live inside webserver::start().
771+ static MHD_OptionItem make_option (enum MHD_OPTION opt, intptr_t val,
772+ void * ptr = nullptr ) {
773+ MHD_OptionItem x = {opt, val, ptr};
774+ return x;
775+ }
776+
777+ void webserver_impl::add_base_mhd_options (std::vector<MHD_OptionItem>& iov) const {
778+ iov.push_back (make_option (MHD_OPTION_NOTIFY_COMPLETED ,
779+ (intptr_t ) &webserver_impl::request_completed, nullptr ));
776780 // TASK-016: per-connection arena anchor. MHD_OPTION_NOTIFY_CONNECTION
777781 // hands us a per-connection void** (socket_context) on STARTED, where
778782 // we new a detail::connection_state (which owns the arena), and on
779783 // CLOSED, where we delete it. This makes the arena's lifetime equal
780784 // to the MHD_Connection's lifetime; request_completed reuses the
781785 // arena across keep-alive request boundaries via arena_.release().
782- iov.push_back (gen (MHD_OPTION_NOTIFY_CONNECTION , ( intptr_t ) &detail::webserver_impl::connection_notify, nullptr ));
783- iov. push_back ( gen ( MHD_OPTION_URI_LOG_CALLBACK , (intptr_t ) &detail:: webserver_impl::uri_log, this ));
784- iov.push_back (gen ( MHD_OPTION_EXTERNAL_LOGGER , ( intptr_t ) &detail::webserver_impl::error_log, this ));
785- iov. push_back ( gen ( MHD_OPTION_UNESCAPE_CALLBACK , (intptr_t ) &detail:: webserver_impl::unescaper_func, this ));
786- iov.push_back (gen ( MHD_OPTION_CONNECTION_TIMEOUT , connection_timeout));
787- if (impl_-> bind_socket != 0 ) {
788- iov.push_back (gen ( MHD_OPTION_LISTEN_SOCKET , impl_-> bind_socket ));
789- }
790-
791- if (start_method == http_utils:: THREAD_PER_CONNECTION && (max_threads != 0 || max_thread_stack_size != 0 ) ) {
792- throw std::invalid_argument ( " Cannot specify maximum number of threads when using a thread per connection " );
786+ iov.push_back (make_option (MHD_OPTION_NOTIFY_CONNECTION ,
787+ (intptr_t ) &webserver_impl::connection_notify, nullptr ));
788+ iov.push_back (make_option ( MHD_OPTION_URI_LOG_CALLBACK ,
789+ (intptr_t ) &webserver_impl::uri_log, parent ));
790+ iov.push_back (make_option ( MHD_OPTION_EXTERNAL_LOGGER ,
791+ ( intptr_t ) &webserver_impl::error_log, parent));
792+ iov.push_back (make_option ( MHD_OPTION_UNESCAPE_CALLBACK ,
793+ ( intptr_t ) &webserver_impl::unescaper_func, parent));
794+ iov. push_back ( make_option ( MHD_OPTION_CONNECTION_TIMEOUT , parent-> connection_timeout ));
795+ if (bind_socket != 0 ) {
796+ iov. push_back ( make_option ( MHD_OPTION_LISTEN_SOCKET , bind_socket) );
793797 }
794-
795- if (max_threads != 0 ) {
796- iov.push_back (gen (MHD_OPTION_THREAD_POOL_SIZE , max_threads));
798+ if (parent->max_threads != 0 ) {
799+ iov.push_back (make_option (MHD_OPTION_THREAD_POOL_SIZE , parent->max_threads ));
797800 }
798-
799- if (max_connections != 0 ) {
800- iov.push_back (gen (MHD_OPTION_CONNECTION_LIMIT , max_connections));
801+ if (parent->max_connections != 0 ) {
802+ iov.push_back (make_option (MHD_OPTION_CONNECTION_LIMIT , parent->max_connections ));
801803 }
802-
803- if (memory_limit != 0 ) {
804- iov.push_back (gen (MHD_OPTION_CONNECTION_MEMORY_LIMIT , memory_limit));
804+ if (parent->memory_limit != 0 ) {
805+ iov.push_back (make_option (MHD_OPTION_CONNECTION_MEMORY_LIMIT , parent->memory_limit ));
805806 }
806-
807- if (per_IP_connection_limit != 0 ) {
808- iov.push_back (gen (MHD_OPTION_PER_IP_CONNECTION_LIMIT , per_IP_connection_limit));
807+ if (parent->per_IP_connection_limit != 0 ) {
808+ iov.push_back (make_option (MHD_OPTION_PER_IP_CONNECTION_LIMIT , parent->per_IP_connection_limit ));
809809 }
810-
811- if (max_thread_stack_size != 0 ) {
812- iov.push_back (gen (MHD_OPTION_THREAD_STACK_SIZE , max_thread_stack_size));
810+ if (parent->max_thread_stack_size != 0 ) {
811+ iov.push_back (make_option (MHD_OPTION_THREAD_STACK_SIZE , parent->max_thread_stack_size ));
813812 }
814-
815813#ifdef HAVE_DAUTH
816- if (nonce_nc_size != 0 ) {
817- iov.push_back (gen (MHD_OPTION_NONCE_NC_SIZE , nonce_nc_size));
814+ if (parent-> nonce_nc_size != 0 ) {
815+ iov.push_back (make_option (MHD_OPTION_NONCE_NC_SIZE , parent-> nonce_nc_size ));
818816 }
819817#endif // HAVE_DAUTH
818+ }
820819
821- if (use_ssl) {
822- // Need for const_cast to respect MHD interface that needs a void*
823- iov.push_back (gen (MHD_OPTION_HTTPS_MEM_KEY , 0 , reinterpret_cast <void *>(const_cast <char *>(https_mem_key.c_str ()))));
824- iov.push_back (gen (MHD_OPTION_HTTPS_MEM_CERT , 0 , reinterpret_cast <void *>(const_cast <char *>(https_mem_cert.c_str ()))));
825-
826- if (!https_mem_trust.empty ()) {
827- iov.push_back (gen (MHD_OPTION_HTTPS_MEM_TRUST , 0 , reinterpret_cast <void *>(const_cast <char *>(https_mem_trust.c_str ()))));
820+ void webserver_impl::add_tls_mhd_options (std::vector<MHD_OptionItem>& iov) const {
821+ if (parent->use_ssl ) {
822+ // const_cast respects the MHD C interface, which takes a void*
823+ // even though the data is read-only at the library boundary.
824+ iov.push_back (make_option (MHD_OPTION_HTTPS_MEM_KEY , 0 ,
825+ reinterpret_cast <void *>(const_cast <char *>(parent->https_mem_key .c_str ()))));
826+ iov.push_back (make_option (MHD_OPTION_HTTPS_MEM_CERT , 0 ,
827+ reinterpret_cast <void *>(const_cast <char *>(parent->https_mem_cert .c_str ()))));
828+ if (!parent->https_mem_trust .empty ()) {
829+ iov.push_back (make_option (MHD_OPTION_HTTPS_MEM_TRUST , 0 ,
830+ reinterpret_cast <void *>(const_cast <char *>(parent->https_mem_trust .c_str ()))));
828831 }
829-
830- if (!https_priorities. empty ()) {
831- iov. push_back ( gen ( MHD_OPTION_HTTPS_PRIORITIES , 0 , reinterpret_cast <void *>(const_cast <char *>(https_priorities.c_str ()))));
832+ if (!parent-> https_priorities . empty ()) {
833+ iov. push_back ( make_option ( MHD_OPTION_HTTPS_PRIORITIES , 0 ,
834+ reinterpret_cast <void *>(const_cast <char *>(parent-> https_priorities .c_str ()))));
832835 }
833836 }
834-
835837#ifdef HAVE_DAUTH
836- if (digest_auth_random != " " ) {
837- // Need for const_cast to respect MHD interface that needs a char*
838- iov.push_back (gen (MHD_OPTION_DIGEST_AUTH_RANDOM , digest_auth_random.size (), const_cast <char *>(digest_auth_random.c_str ())));
838+ if (parent->digest_auth_random != " " ) {
839+ iov.push_back (make_option (MHD_OPTION_DIGEST_AUTH_RANDOM ,
840+ parent->digest_auth_random .size (),
841+ const_cast <char *>(parent->digest_auth_random .c_str ())));
839842 }
840843#endif // HAVE_DAUTH
844+ }
841845
846+ void webserver_impl::add_gnutls_mhd_options (std::vector<MHD_OptionItem>& iov) const {
842847#ifdef HAVE_GNUTLS
843- if (cred_type != http_utils::NONE ) {
844- iov.push_back (gen (MHD_OPTION_HTTPS_CRED_TYPE , cred_type));
848+ if (parent-> cred_type != http_utils::NONE ) {
849+ iov.push_back (make_option (MHD_OPTION_HTTPS_CRED_TYPE , parent-> cred_type ));
845850 }
846-
847- if (psk_cred_handler != nullptr && use_ssl) {
848- iov.push_back (gen (MHD_OPTION_GNUTLS_PSK_CRED_HANDLER ,
849- (intptr_t )&detail::webserver_impl::psk_cred_handler_func, this ));
851+ if (parent->psk_cred_handler != nullptr && parent->use_ssl ) {
852+ iov.push_back (make_option (MHD_OPTION_GNUTLS_PSK_CRED_HANDLER ,
853+ (intptr_t )&webserver_impl::psk_cred_handler_func, parent));
850854 }
851-
852855#ifdef MHD_OPTION_HTTPS_CERT_CALLBACK
853- if (sni_callback != nullptr && use_ssl) {
854- iov.push_back (gen (MHD_OPTION_HTTPS_CERT_CALLBACK ,
855- (intptr_t )&detail:: webserver_impl::sni_cert_callback_func, this ));
856+ if (parent-> sni_callback != nullptr && parent-> use_ssl ) {
857+ iov.push_back (make_option (MHD_OPTION_HTTPS_CERT_CALLBACK ,
858+ (intptr_t )&webserver_impl::sni_cert_callback_func, parent ));
856859 }
857860#endif // MHD_OPTION_HTTPS_CERT_CALLBACK
861+ #else // HAVE_GNUTLS
862+ (void )iov;
858863#endif // HAVE_GNUTLS
864+ }
859865
860- if (listen_backlog > 0 ) {
861- iov.push_back (gen (MHD_OPTION_LISTEN_BACKLOG_SIZE , listen_backlog));
862- }
863-
864- if (address_reuse != 0 ) {
865- iov.push_back (gen (MHD_OPTION_LISTENING_ADDRESS_REUSE , address_reuse));
866- }
867-
868- if (connection_memory_increment > 0 ) {
869- iov.push_back (gen (MHD_OPTION_CONNECTION_MEMORY_INCREMENT , connection_memory_increment));
866+ void webserver_impl::add_extended_mhd_options (std::vector<MHD_OptionItem>& iov) const {
867+ if (parent->listen_backlog > 0 ) {
868+ iov.push_back (make_option (MHD_OPTION_LISTEN_BACKLOG_SIZE , parent->listen_backlog ));
870869 }
871-
872- if (tcp_fastopen_queue_size > 0 ) {
873- iov.push_back (gen (MHD_OPTION_TCP_FASTOPEN_QUEUE_SIZE , tcp_fastopen_queue_size));
870+ if (parent->address_reuse != 0 ) {
871+ iov.push_back (make_option (MHD_OPTION_LISTENING_ADDRESS_REUSE , parent->address_reuse ));
874872 }
875-
876- if (sigpipe_handled_by_app) {
877- iov. push_back ( gen ( MHD_OPTION_SIGPIPE_HANDLED_BY_APP , 1 ));
873+ if (parent-> connection_memory_increment > 0 ) {
874+ iov. push_back ( make_option ( MHD_OPTION_CONNECTION_MEMORY_INCREMENT ,
875+ parent-> connection_memory_increment ));
878876 }
879-
880- if (!https_mem_dhparams. empty ()) {
881- iov. push_back ( gen ( MHD_OPTION_HTTPS_MEM_DHPARAMS , 0 , const_cast < char *>(https_mem_dhparams. c_str ()) ));
877+ if (parent-> tcp_fastopen_queue_size > 0 ) {
878+ iov. push_back ( make_option ( MHD_OPTION_TCP_FASTOPEN_QUEUE_SIZE ,
879+ parent-> tcp_fastopen_queue_size ));
882880 }
883-
884- if (!https_key_password.empty ()) {
885- iov.push_back (gen (MHD_OPTION_HTTPS_KEY_PASSWORD , 0 , const_cast <char *>(https_key_password.c_str ())));
881+ if (parent->sigpipe_handled_by_app ) {
882+ iov.push_back (make_option (MHD_OPTION_SIGPIPE_HANDLED_BY_APP , 1 ));
886883 }
887-
888- if (!https_priorities_append.empty ()) {
889- iov.push_back (gen (MHD_OPTION_HTTPS_PRIORITIES_APPEND , 0 , const_cast <char *>(https_priorities_append.c_str ())));
884+ if (parent->no_alpn ) {
885+ iov.push_back (make_option (MHD_OPTION_TLS_NO_ALPN , 1 ));
890886 }
891-
892- if (no_alpn) {
893- iov.push_back (gen (MHD_OPTION_TLS_NO_ALPN , 1 ));
887+ if (parent->client_discipline_level >= 0 ) {
888+ iov.push_back (make_option (MHD_OPTION_CLIENT_DISCIPLINE_LVL , parent->client_discipline_level ));
894889 }
890+ }
895891
896- if (client_discipline_level >= 0 ) {
897- iov.push_back (gen (MHD_OPTION_CLIENT_DISCIPLINE_LVL , client_discipline_level));
892+ void webserver_impl::add_https_extra_options (std::vector<MHD_OptionItem>& iov) const {
893+ if (!parent->https_mem_dhparams .empty ()) {
894+ iov.push_back (make_option (MHD_OPTION_HTTPS_MEM_DHPARAMS , 0 ,
895+ const_cast <char *>(parent->https_mem_dhparams .c_str ())));
898896 }
899-
900- iov.push_back (gen (MHD_OPTION_END , 0 , nullptr ));
901-
902- int start_conf = start_method;
903-
904- if (use_ssl) {
905- start_conf |= MHD_USE_SSL ;
897+ if (!parent->https_key_password .empty ()) {
898+ iov.push_back (make_option (MHD_OPTION_HTTPS_KEY_PASSWORD , 0 ,
899+ const_cast <char *>(parent->https_key_password .c_str ())));
906900 }
907-
908- if (use_ipv6) {
909- start_conf |= MHD_USE_IPv6 ;
901+ if (!parent-> https_priorities_append . empty ()) {
902+ iov. push_back ( make_option ( MHD_OPTION_HTTPS_PRIORITIES_APPEND , 0 ,
903+ const_cast < char *>(parent-> https_priorities_append . c_str ()))) ;
910904 }
905+ }
911906
912- if (use_dual_stack) {
913- start_conf |= MHD_USE_DUAL_STACK ;
914- }
907+ void webserver_impl::build_mhd_option_array (std::vector<MHD_OptionItem>& iov) const {
908+ add_base_mhd_options (iov);
909+ add_tls_mhd_options (iov);
910+ add_gnutls_mhd_options (iov);
911+ add_extended_mhd_options (iov);
912+ add_https_extra_options (iov);
913+ iov.push_back (make_option (MHD_OPTION_END , 0 , nullptr ));
914+ }
915915
916- if (debug) {
917- start_conf |= MHD_USE_DEBUG ;
918- }
919- if (pedantic) {
920- start_conf |= MHD_USE_PEDANTIC_CHECKS ;
921- }
916+ int webserver_impl::compose_transport_flags () const {
917+ int flags = 0 ;
918+ if (parent->use_ssl ) flags |= MHD_USE_SSL ;
919+ if (parent->use_ipv6 ) flags |= MHD_USE_IPv6;
920+ if (parent->use_dual_stack ) flags |= MHD_USE_DUAL_STACK ;
921+ return flags;
922+ }
922923
923- if (deferred_enabled) {
924- start_conf |= MHD_USE_SUSPEND_RESUME ;
925- }
924+ int webserver_impl::compose_runtime_flags () const {
925+ int flags = 0 ;
926+ if (parent->debug ) flags |= MHD_USE_DEBUG ;
927+ if (parent->pedantic ) flags |= MHD_USE_PEDANTIC_CHECKS ;
928+ if (parent->deferred_enabled ) flags |= MHD_USE_SUSPEND_RESUME ;
929+ if (parent->no_listen_socket ) flags |= MHD_USE_NO_LISTEN_SOCKET ;
930+ if (parent->no_thread_safety ) flags |= MHD_USE_NO_THREAD_SAFETY ;
931+ if (parent->turbo ) flags |= MHD_USE_TURBO ;
932+ if (parent->suppress_date_header ) flags |= MHD_USE_SUPPRESS_DATE_NO_CLOCK ;
933+ #ifdef HAVE_WEBSOCKET
934+ if (!registered_ws_handlers.empty ()) flags |= MHD_ALLOW_UPGRADE ;
935+ #endif // HAVE_WEBSOCKET
936+ return flags;
937+ }
926938
939+ int webserver_impl::compose_start_flags () const {
940+ int flags = parent->start_method ;
941+ flags |= compose_transport_flags ();
942+ flags |= compose_runtime_flags ();
927943#ifdef USE_FASTOPEN
928- start_conf |= MHD_USE_TCP_FASTOPEN ;
944+ flags |= MHD_USE_TCP_FASTOPEN ;
929945#endif
946+ return flags;
947+ }
930948
931- if (no_listen_socket) {
932- start_conf |= MHD_USE_NO_LISTEN_SOCKET ;
933- }
934-
935- if (no_thread_safety) {
936- start_conf |= MHD_USE_NO_THREAD_SAFETY ;
937- }
938-
939- if (turbo) {
940- start_conf |= MHD_USE_TURBO ;
941- }
942-
943- if (suppress_date_header) {
944- start_conf |= MHD_USE_SUPPRESS_DATE_NO_CLOCK ;
945- }
949+ } // namespace detail
946950
947- #ifdef HAVE_WEBSOCKET
948- if (!impl_->registered_ws_handlers .empty ()) {
949- start_conf |= MHD_ALLOW_UPGRADE ;
951+ bool webserver::start (bool blocking) {
952+ if (start_method == http_utils::THREAD_PER_CONNECTION
953+ && (max_threads != 0 || max_thread_stack_size != 0 )) {
954+ throw std::invalid_argument (
955+ " Cannot specify maximum number of threads when using a thread per connection" );
950956 }
951- #endif // HAVE_WEBSOCKET
952957
958+ vector<struct MHD_OptionItem > iov;
959+ impl_->build_mhd_option_array (iov);
960+ const int start_conf = impl_->compose_start_flags ();
953961
954962 impl_->daemon = nullptr ;
955963 if (bind_address == nullptr ) {
@@ -966,8 +974,6 @@ bool webserver::start(bool blocking) {
966974 throw std::invalid_argument (" Unable to connect daemon to port: " + std::to_string (port));
967975 }
968976
969- bool value_onclose = false ;
970-
971977 impl_->running = true ;
972978
973979 if (blocking) {
@@ -976,9 +982,9 @@ bool webserver::start(bool blocking) {
976982 pthread_cond_wait (&impl_->mutexcond , &impl_->mutexwait );
977983 }
978984 pthread_mutex_unlock (&impl_->mutexwait );
979- value_onclose = true ;
985+ return true ;
980986 }
981- return value_onclose ;
987+ return false ;
982988}
983989
984990bool webserver::is_running () {
0 commit comments