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