1 // This may look like C code, but it's really -*- C++ -*- 2 /* 3 * Copyright (C) 2008 Emweb bv, Herent, Belgium. 4 * 5 * See the LICENSE file for terms of use. 6 */ 7 #ifndef WSERVER_H_ 8 #define WSERVER_H_ 9 10 #include <Wt/WApplication.h> 11 #include <Wt/WException.h> 12 #include <Wt/WLogger.h> 13 14 #include <chrono> 15 16 namespace http { 17 namespace server { 18 class Server; 19 } 20 } 21 namespace Wt { 22 23 class Configuration; 24 class WebController; 25 class WIOService; 26 /*! \class WServer Wt/WServer.h Wt/WServer.h 27 * \brief A class encapsulating a web application server. 28 * 29 * This server class represents an instance of an application server. 30 * 31 * It offers support for multiple application entry points and control 32 * over starting and stopping the server. This may be used as an 33 * alternative to using WRun() when you wish to support multiple 34 * application entry points, or for integrating a %Wt (stand-alone 35 * httpd) server application into an existing application, with control 36 * over starting and stopping the server as appropriate. 37 * 38 * As an example usage, consider the implementation of WRun(), which 39 * starts the server until a Ctrl-C is pressed or a termination signal 40 * has been received, or a restart is indicated using SIGHUP or a changed 41 * binary (argv[0]): 42 * 43 * \code 44 int WRun(int argc, char *argv[], ApplicationCreator createApplication) 45 { 46 try { 47 // use argv[0] as the application name to match a suitable entry 48 // in the Wt configuration file, and use the default configuration 49 // file (which defaults to /etc/wt/wt_config.xml unless the environment 50 // variable WT_CONFIG_XML is set) 51 WServer server(argv[0]); 52 53 // WTHTTP_CONFIGURATION is e.g. "/etc/wt/wthttpd" 54 server.setServerConfiguration(argc, argv, WTHTTP_CONFIGURATION); 55 56 // add a single entry point, at the default location (as determined 57 // by the server configuration's deploy-path) 58 server.addEntryPoint(Wt::EntryPointType::Application, createApplication); 59 if (server.start()) { 60 int sig = WServer::waitForShutdown(argv[0]); 61 62 std::cerr << "Shutdown (signal = " << sig << ")" << std::endl; 63 server.stop(); 64 65 if (sig == SIGHUP) 66 WServer::restart(argc, argv, environ); 67 } 68 } catch (WServer::Exception& e) { 69 std::cerr << e.what() << "\n"; 70 return 1; 71 } catch (std::exception& e) { 72 std::cerr << "exception: " << e.what() << "\n"; 73 return 1; 74 } 75 } 76 * \endcode 77 */ 78 #ifdef WT_WIN32 79 class WServer 80 #else // WT_WIN32 81 class WTCONNECTOR_API WServer 82 #endif // WT_WIN32 83 { 84 public: 85 typedef std::function<std::string (std::size_t max_length, int purpose)> 86 SslPasswordCallback; 87 88 /*! \class Exception 89 * \brief Server %Exception class. 90 */ 91 class WT_API Exception : public WException 92 { 93 public: 94 Exception(const std::string& what); 95 }; 96 97 #ifndef WT_TARGET_JAVA 98 /*! \class SessionInfo 99 * 100 * \brief Contains the information for one session. 101 */ 102 struct WT_API SessionInfo 103 { 104 int64_t processId; //!< The process id of the process the session is running in. 105 std::string sessionId; //!< The session id. 106 }; 107 #endif // WT_TARGET_JAVA 108 109 /*! \brief Creates a new server instance. 110 * 111 * The \p wtApplicationPath is used to match specific 112 * application-settings in the %Wt configuration file. If no 113 * specific match could be found, the general settings are used 114 * (corresponding to the '*' selector). 115 * 116 * The %Wt application configuration is read from the 117 * \p wtConfigurationFile. If empty, this defaults to the value 118 * configured at build time. 119 * 120 * For more information on configuring %Wt applications, see \ref 121 * configuration_sec "Configuration". 122 * 123 * \throws Exception : indicates a configuration problem. 124 * 125 * \sa setServerConfiguration() 126 */ 127 WTCONNECTOR_API 128 WServer(const std::string& wtApplicationPath = std::string(), 129 const std::string& wtConfigurationFile = std::string()); 130 131 WServer(const WServer &) = delete; 132 133 /*! \brief Creates a new server instance and configures it. 134 * 135 * This is equivalent to: 136 * \code 137 WServer server(argv[0]); 138 server.setServerConfiguration(argc, argv, wtConfigurationFile); 139 \endcode 140 * 141 * \throws Exception : indicates a configuration problem. 142 * 143 * \sa WServer(const std::string&, const std::string&) 144 * \sa setServerConfiguration() 145 */ 146 WTCONNECTOR_API 147 WServer(int argc, char *argv[], const std::string& wtConfigurationFile = std::string()); 148 149 /*! \brief Creates a new server instance and configures it. 150 * 151 * This is equivalent to: 152 * \code 153 WServer server(applicationPath); 154 server.setServerConfiguration(applicationPath, args, wtConfigurationFile); 155 \endcode 156 * 157 * This version of the WServer constructor takes a std::string 158 * for the application path, and a vector of arguments (not including 159 * argv[0], the application path) instead of argc and argv, 160 * for better convenience when arguments are not provided via 161 * the command line. 162 * 163 * \throws Exception : indicates a configuration problem. 164 * 165 * \sa WServer(const std::string&, const std::string&) 166 * \sa setServerConfiguration() 167 */ 168 WTCONNECTOR_API 169 WServer(const std::string &applicationPath, 170 const std::vector<std::string> &args, 171 const std::string& wtConfigurationFile = std::string()); 172 173 /*! \brief Destructor. 174 * 175 * If the server was still running, it is stopped first by calling 176 * stop(). It is probably safer to call stop() first yourself, since 177 * this allows exceptions to be caught. 178 * 179 * \sa isRunning(), stop() 180 */ 181 WTCONNECTOR_API virtual ~WServer(); 182 183 #ifndef WT_TARGET_JAVA 184 /*! \brief Sets the I/O service. 185 * 186 * The server will use an I/O service for scheduling functions into a 187 * thread-pool, and to implement asynchronous networking, whose call-back 188 * funtions are scheduled in the same thread pool. 189 * 190 * By default, a server will create its own I/O service, but you may 191 * configure it to reuse another I/O service. 192 */ 193 WT_API void setIOService(WIOService& ioService); 194 195 /*! \brief Returns the I/O service. 196 * 197 * \sa setIOService() 198 */ 199 WT_API WIOService& ioService(); 200 #endif 201 202 /*! \brief Returns the server instance. 203 * 204 * Returns the single server instance. This may be useful when using 205 * WRun(), which does not provide direct access to the instantiated 206 * server, but still you want to use functions like 207 * post(). 208 * 209 * \note When instantiating multiple servers, this will simply return the 210 * last instance. You probably want to avoid this function then. 211 */ instance()212 static WServer *instance() { return instance_; } 213 214 #ifndef WT_TARGET_JAVA 215 /*! \brief Configures the HTTP(S) server or FastCGI process. 216 * 217 * Configures the HTTP(S) server using command-line arguments, a 218 * configuration file, or both. The valid options are described in 219 * \ref config_wthttpd "Built-in httpd configuration". 220 * 221 * The applications themselves are configured using the configuration 222 * file passed to the constructor. 223 * 224 * The server configuration must be set before any other 225 * functionality can be used. 226 * 227 * In case of FastCGI deployment, the \p serverConfigurationFile 228 * argument is ignored, and depending on the command-line arguments, 229 * this process may become a FastCGI protocol relay process which 230 * never returning from this call but directs the FastCGI stream to 231 * the correct session, rather than a Wt application server. 232 * 233 * \throws Exception : indicates a configuration problem. 234 */ 235 WTCONNECTOR_API 236 void setServerConfiguration(int argc, char *argv[], 237 const std::string& serverConfigurationFile 238 = std::string()); 239 240 /*! \brief Configures the HTTP(S) server or FastCGI process. 241 * 242 * Configures the HTTP(S) server using command-line arguments, a 243 * configuration file, or both. The valid options are described in 244 * \ref config_wthttpd "Built-in httpd configuration". 245 * 246 * The applications themselves are configured using the configuration 247 * file passed to the constructor. 248 * 249 * The server configuration must be set before any other 250 * functionality can be used. 251 * 252 * In case of FastCGI deployment, the \p serverConfigurationFile 253 * argument is ignored, and depending on the command-line arguments, 254 * this process may become a FastCGI protocol relay process which 255 * never returning from this call but directs the FastCGI stream to 256 * the correct session, rather than a Wt application server. 257 * 258 * This version of setServerConfiguration() takes a std::string 259 * for the application path, and a vector of arguments (not including 260 * argv[0], the application path) instead of argc and argv, 261 * for better convenience when arguments are not provided via 262 * the command line. 263 * 264 * \throws Exception : indicates a configuration problem. 265 */ 266 WTCONNECTOR_API 267 void setServerConfiguration(const std::string &applicationPath, 268 const std::vector<std::string> &args, 269 const std::string &serverConfigurationFile = std::string()); 270 271 /*! \brief Binds an entry-point to a callback function to create 272 * a new application. 273 * 274 * The \p path is the local URL at which the application is 275 * deployed: when a user visits this URL, the callback will be 276 * called to create a new application. 277 * 278 * If the \p path does not start with a slash ('/'), the deployment path 279 * will be prepended. The deployment path defaults to '/' but can be overridden 280 * in the wthttp connector with the --deploy-path option (see also \ref 281 * config_wthttpd "Built-in httpd configuration"). This implies that when 282 * the \p path is empty (the default), it is set to the deployment path. 283 * 284 * The optional \p favicon is a URL path (which should not 285 * contain the host part!) to a favicon, which is the icon displayed 286 * in the browser for your application. Alternatively, you may 287 * specify a favicon using the "favicon" property in the 288 * configuration file (see also \ref config_general). 289 * 290 * \sa removeEntryPoint() 291 */ 292 WT_API void addEntryPoint(EntryPointType type, ApplicationCreator callback, 293 const std::string& path = std::string(), 294 const std::string& favicon = std::string()); 295 #endif 296 297 /*! \brief Binds a resource to a fixed path. 298 * 299 * Resources may either be private to a single session or 300 * public. Use this method to add a public resource with a fixed 301 * path. 302 * 303 * \sa removeEntryPoint() 304 */ 305 WT_API void addResource(WResource *resource, const std::string& path); 306 307 /*! \brief Removes an entry point. 308 * 309 * Use this method to remove an entry point or static resource. 310 * 311 * In a multi-threaded environment, this may only be done when the 312 * server is not running. 313 * 314 * \note If the entry point is a resource, the resource will not be deleted 315 * 316 * \sa addEntryPoint(), addResource() 317 */ 318 WT_API void removeEntryPoint(const std::string& path); 319 320 #ifndef WT_TARGET_JAVA 321 /*! \brief Starts the server in the background. 322 * 323 * Returns whether the server could be successfully started. 324 * 325 * \throws Exception : indicates a problem starting the server. 326 * 327 * \sa isRunning(), stop() 328 */ 329 WTCONNECTOR_API bool start(); 330 331 /*! \brief Stops the server. 332 * 333 * All active application sessions are terminated cleanly, and the 334 * HTTP(S) server is shut down. 335 * 336 * \note This will also stop the underlying ioService(), and will block 337 * until all pending tasks have completed. 338 * 339 * \throw Exception : indicates a problem while stopping the server. 340 * 341 * \sa isRunning(), start() 342 */ 343 WTCONNECTOR_API void stop(); 344 345 /*! \brief Returns whether the server is running. 346 * 347 * \sa start(), stop() 348 */ 349 WTCONNECTOR_API bool isRunning() const; 350 351 /*! \brief Starts the server, waits for shutdown, then stops the server. 352 * 353 * This is equivalent to: 354 * \code 355 if (start()) { 356 WServer::waitForShutdown(); 357 stop(); 358 } 359 \endcode 360 * \sa start() 361 * \sa stop() 362 * \sa waitForShutdown() 363 */ 364 WTCONNECTOR_API void run(); 365 366 /*! \brief Resumes the server. 367 * 368 * This closes and reopens the listen socket(s) for accepting new 369 * TCP and/or SSL connections. This may be needed when the OS (like 370 * IPhoneOS) has closed the sockets while suspending the 371 * application. 372 */ 373 WTCONNECTOR_API void resume(); 374 375 /*! \brief Waits for a shutdown signal. 376 * 377 * This static method blocks the current thread, waiting for a 378 * shutdown signal. The implementation and details are platform 379 * dependent, but this is usually Ctrl-C (SIGINT) or SIGKILL. 380 * 381 * This method is convenient if you want to customize how the server 382 * is started (by instantiating a WServer object yourself, instead 383 * of using Wt::WRun()), but still want to use %Wt as a standalone 384 * server that cleanly terminates on interruption. 385 * 386 * This will also catch SIGHUP, to reread the configuration file. 387 */ 388 WT_API static int waitForShutdown(); 389 390 /*! \brief A utility method to restart. 391 * 392 * This will result the application with the new image (argv[0]), effectively 393 * loading a newly deployed version. <i>(Experimental, UNIX only)</i> 394 */ 395 WT_API static void restart(int argc, char **argv, char **envp); 396 397 /*! \brief A utility method to restart. 398 * 399 * This will result the application with the new image (applicationPath), effectively 400 * loading a newly deployed version. <i>(Experimental, UNIX only)</i> 401 * 402 * This version of restart() takes a std::string 403 * for the application path, and a vector of arguments (not including 404 * argv[0], the application path) instead of argc and argv, 405 * for better convenience when arguments are not provided via 406 * the command line. 407 */ 408 WT_API static void restart(const std::string &applicationPath, 409 const std::vector<std::string> &args); 410 411 /*! \brief Returns the server HTTP port number. 412 * 413 * Returns -1 if the port is not known (i.e. because the connector is 414 * not aware of how the http server is configured). 415 * 416 * \note If the server listens on multiple ports, only the first 417 * port is returned. 418 */ 419 WTCONNECTOR_API int httpPort() const; 420 421 WT_API void setAppRoot(const std::string& path); 422 423 /*! \brief Returns the approot special property 424 * 425 * \sa WApplication::appRoot() 426 */ 427 WT_API std::string appRoot() const; 428 429 /*! \brief Returns the docroot (if using wthttp) 430 * 431 * If you're using wthttp, this returns the location passed to the 432 * --docroot argument, just like WApplication::docRoot(). This allows access 433 * to this parameter outside of the context of a WApplication. 434 * 435 * If you're using any other connector, this returns the empty string. 436 */ 437 WTCONNECTOR_API std::string docRoot() const; 438 439 /*! \brief Posts a function to a session. 440 * 441 * This is a thread-safe method to post a particular event 442 * (implemented as a function object) to be run within the context 443 * of a session, identified by its WApplication::sessionId(). The 444 * method will safely handle the case where the session is being 445 * terminated, and the session lock will be taken to execute the 446 * function in the context of the session (with 447 * WApplication::instance() pointing to the correct application), 448 * just as with a request initiated by the browser. You will 449 * typically also want to push the changes to the client using 450 * server-initiated updates (WApplication::triggerUpdate()). 451 * 452 * The method returns immediately, and the function will be run 453 * within the thread-pool that handles incoming web requests. In 454 * this way, it avoids dead-lock scenarios. 455 * 456 * If a \p fallbackFunction is specified then in case the session 457 * is dead, it is called instead. 458 * 459 * This provides a good alternative to grabbing the update lock of 460 * an application to directly push changes to a session out of its 461 * event loop. 462 * 463 * Note that if you post an event to a method of a widget (or other 464 * object), it may still be that the targeted object has been 465 * deleted, if the life-time of that object is not the same as the 466 * life-time of the application. It may be useful to protect 467 * yourself from this by using WApplication::bind(). 468 */ 469 WT_API void post(const std::string& sessionId, 470 const std::function<void ()>& function, 471 const std::function<void ()>& fallBackFunction 472 = std::function<void ()>()); 473 474 /*! \brief Posts a function to all currently active sessions. 475 * 476 * \sa post() 477 */ 478 WT_API void postAll(const std::function<void ()>& function); 479 480 /*! \brief Schedules a function to be executed in a session. 481 * 482 * The \p function will run in the session specified by \p sessionId, 483 * after \p duration. If the session does not exist anymore, 484 * \p fallBackFunction will be executed. 485 * 486 * \sa post() 487 */ 488 WT_API void schedule(std::chrono::steady_clock::duration duration, 489 const std::string& sessionId, 490 const std::function<void ()>& function, 491 const std::function<void ()>& fallBackFunction 492 = std::function<void ()>()); 493 494 /*! \brief Change input method for server certificate passwords (http backend) 495 * 496 * The private server identity key may be protected by a password. If you 497 * want to control how the password is retrieved, set a password handler 498 * by calling this function. If no password handler is set, the OpenSSL 499 * default handler will be used, which asks to enter the password on stdio. 500 * 501 * This function must be called before calling start(). 502 * 503 * The max_length parameter is informational and indicates that the 504 * underlying implementation will truncate the password to this length. 505 */ 506 WTCONNECTOR_API void setSslPasswordCallback(const SslPasswordCallback& cb); 507 508 #endif // WT_TARGET_JAVA 509 510 #ifndef WT_TARGET_JAVA 511 /*! \brief Reads a configuration property. 512 * 513 * As properties are unique to an executable location, they are defined 514 * from the moment that setServerConfiguration() is invoked. Use this 515 * method to access configuration properties outside of an active 516 * session, e.g. from within the main() function. 517 * 518 * \sa WApplication::readConfigurationProperty() 519 520 */ 521 WT_API bool readConfigurationProperty(const std::string& name, 522 std::string& value) const; 523 524 #else 525 /*! \brief Reads a configuration property. 526 * 527 * Tries to read a configured value for the property \p name. If no 528 * value was configured, the default \p value is returned. 529 * 530 * \sa WApplication::readConfigurationProperty() 531 */ 532 std::string *readConfigurationProperty(const std::string& name, 533 const std::string& value); 534 #endif // WT_TARGET_JAVA 535 536 /*! \brief Sets the resource object that provides localized strings. 537 * 538 * This is used only for WString::tr() used from within static 539 * resources. 540 * 541 * The default value is 0. 542 */ 543 WT_API void setLocalizedStrings(const std::shared_ptr<WLocalizedStrings>& 544 stringResolver); 545 546 /*! \brief Sets the resource object that provides localized strings. 547 * 548 * \sa setLocalizedStrings() 549 */ 550 WT_API std::shared_ptr<WLocalizedStrings> localizedStrings() const; 551 552 #ifndef WT_TARGET_JAVA 553 554 /*! \brief Retrieve information on all sessions. 555 * 556 * This is only implemented for the wthttp connector. 557 * 558 * If the dedicated process session policy is used, only the original 559 * process has access to the full list of sessions. Public resources 560 * (those registered with addResource()) run in the original process, 561 * so they can access this list. 562 */ 563 WTCONNECTOR_API std::vector<SessionInfo> sessions() const; 564 565 void updateProcessSessionId(const std::string& sessionId); 566 567 /*! \brief Returns the logger instance. 568 * 569 * This is the logger class used in WApplication::log() and 570 * Wt::log() functions. 571 */ 572 WT_API WLogger& logger(); 573 574 /*! \brief Sets a custom logger to redirect all logging to. 575 * 576 * Instead of using the server's default logger, this will send 577 * all logging to some custom WLogSink. 578 */ 579 WT_API void setCustomLogger(const WLogSink &customLogger); 580 581 const WLogSink * customLogger() const; 582 583 /*! \brief Adds an entry to the log. 584 * 585 * \sa Wt::log(), WApplication::log() 586 */ 587 WT_API WLogEntry log(const std::string& type) const; 588 589 WT_API void initLogger(const std::string& logFile, 590 const std::string& logConfig); 591 592 /*! \brief Reflects whether the current process is a dedicated session process 593 * 594 * \note This will only be accurate after the WServer has been configured, either 595 * through setServerConfiguration() or one of the constructors that immediately 596 * configures the server. 597 */ 598 WT_API bool dedicatedSessionProcess() const; 599 #endif // WT_TARGET_JAVA 600 601 WT_API bool expireSessions(); 602 603 WT_API Configuration& configuration(); 604 605 WT_API WebController *controller(); 606 607 #ifndef WT_TARGET_JAVA 608 WT_API void scheduleStop(); 609 #endif // WT_TARGET_JAVA 610 611 #ifdef WT_WIN32 612 WT_API static void terminate(); 613 #endif // WT_WIN32 614 615 #ifdef WT_TARGET_JAVA 616 std::string getContextPath(); 617 int servletMajorVersion(); 618 #endif 619 620 private: 621 WebController *webController_; 622 623 #ifndef WT_TARGET_JAVA 624 WLogger logger_; 625 const WLogSink * customLogger_; 626 #endif // WT_TARGET_JAVA 627 628 std::string application_, configurationFile_, appRoot_, description_; 629 Configuration *configuration_; 630 std::shared_ptr<WLocalizedStrings> localizedStrings_; 631 632 bool ownsIOService_; 633 WIOService *ioService_; 634 635 bool dedicatedProcessEnabled_; 636 637 struct Impl; 638 Impl *impl_; 639 640 WT_API void setConfiguration(const std::string& file, 641 const std::string& application); 642 643 WT_API void setConfiguration(const std::string& file); configurationFile()644 const std::string& configurationFile() const { 645 return configurationFile_; 646 } 647 648 WT_API void init(const std::string& wtApplicationPath, 649 const std::string& configurationFile); 650 WT_API void destroy(); 651 WT_API void setCatchSignals(bool catchSignals); 652 WT_API std::string prependDefaultPath(const std::string& path); 653 654 655 WT_API static WServer *instance_; 656 std::function<std::string (std::size_t max_length, int purpose)> sslPasswordCallback_; 657 #ifndef WT_TARGET_JAVA 658 std::function<void ()> stopCallback_; 659 std::function<void (const std::string& sessionId)> updateProcessSessionIdCallback_; 660 #endif // WT_TARGET_JAVA 661 }; 662 663 } 664 #endif // WSERVER_H_ 665