1 // This may look like C code, but it's really -*- C++ -*-
2 /*
3  * Copyright (C) 2008 Emweb bv, Herent, Belgium.
4  *
5  * All rights reserved.
6  */
7 
8 #ifndef CONFIGURATION_H
9 #define CONFIGURATION_H
10 
11 #include <exception>
12 #include <iostream>
13 #include <string>
14 #include <utility>
15 #include <vector>
16 
17 #if defined(WT_THREADED) && !defined(WT_CONF_NO_SHARED_LOCK)
18 #if _MSC_VER >= 1900 || __cplusplus >= 201703L
19 // we're using Visual Studio 2015 or higher, so we can use std::shared_mutex
20 #define WT_STD_CONF_LOCK
21 #define WT_CONF_LOCK
22 #else
23 #define WT_BOOST_CONF_LOCK
24 #define WT_CONF_LOCK
25 #endif
26 #endif
27 
28 #ifdef WT_CONF_LOCK
29 #include <thread>
30 #endif // WT_CONF_LOCK
31 
32 #ifdef WT_STD_CONF_LOCK
33 #include <shared_mutex>
34 #endif  // WT_STD_CONF_LOCK
35 
36 #ifdef WT_BOOST_CONF_LOCK
37 #include <boost/thread/shared_mutex.hpp>
38 #endif // WT_BOOST_CONF_LOCK
39 
40 #include "Wt/WApplication.h"
41 
42 #include "WebSession.h"
43 #include "Wt/WRandom.h"
44 
45 #ifndef WT_TARGET_JAVA
46 #include "Wt/AsioWrapper/asio.hpp"
47 #endif // WT_TARGET_JAVA
48 
49 #ifndef WT_TARGET_JAVA
50 #include "EntryPoint.h"
51 #endif // WT_TARGET_JAVA
52 
53 namespace boost {
54   namespace program_options {
55     class variables_map;
56   }
57 }
58 
59 namespace Wt {
60   namespace rapidxml {
61     template<class Ch> class xml_node;
62   }
63 
64   class WLogger;
65   class WServer;
66 
67 #ifndef WT_TARGET_JAVA
68 
69 /// A segment in the deployment path of an entry point,
70 /// used for routing.
71 struct WT_API PathSegment {
PathSegmentPathSegment72   PathSegment()
73     : parent(nullptr),
74       entryPoint(nullptr)
75   { }
76 
PathSegmentPathSegment77   PathSegment(const std::string &s,
78               PathSegment *p)
79     : parent(p),
80       entryPoint(nullptr),
81       segment(s)
82   { }
83 
84   PathSegment *parent;
85   const EntryPoint *entryPoint;
86   std::vector<std::unique_ptr<PathSegment>> children; // Static path segments
87   std::unique_ptr<PathSegment> dynamicChild; // Dynamic path segment, lowest priority
88   std::string segment;
89 };
90 
91 #endif // WT_TARGET_JAVA
92 
93 class WT_API HeadMatter {
94 public:
95   HeadMatter(std::string contents,
96              std::string userAgent);
97 
contents()98   const std::string& contents() const { return contents_; }
userAgent()99   const std::string& userAgent() const { return userAgent_; }
100 
101 private:
102   std::string contents_;
103   std::string userAgent_;
104 };
105 
106 class WT_API Configuration
107 {
108 public:
109   enum SessionPolicy {
110     DedicatedProcess,
111     SharedProcess
112   };
113 
114   enum SessionTracking {
115     CookiesURL, // Use cookies if available, or fallback to URL-based,
116 		// does not support multiple sessions in same browser when
117 		// using cookies
118     URL, // Use URL-based session tracking, support multiple sessions in the same
119 	 // browser
120     Combined // Use a combination of multi-session cookie + URL-based session tracking
121 	     // Will error if cookies are not available (no fallback)
122 	     // This should be the most secure option, and supports multiple sessions
123 	     // in the same browser.
124   };
125 
126   enum ErrorReporting {
127     NoErrors, /* do not even catch them */
128     ServerSideOnly,
129     ErrorMessage
130   };
131 
132   enum BootstrapMethod {
133     DetectAjax,
134     Progressive
135   };
136 
137   typedef std::map<std::string, std::string> PropertyMap;
138   typedef std::vector<std::string> AgentList;
139 
140   Configuration(const std::string& applicationPath,
141 		const std::string& appRoot,
142 		const std::string& configurationFile,
143 		WServer *server);
144 
145   void rereadConfiguration();
146 
147   // finds a configured approot based on the environment
148   static std::string locateAppRoot();
149 
150   // finds a config file based on the environment, in the approot,
151   // or the default location
152   static std::string locateConfigFile(const std::string& appRoot);
153 
154   /*
155    * Override the sessionIdPrefix setting in the config file
156    */
157   void setSessionIdPrefix(const std::string& prefix);
158 
159 #ifndef WT_TARGET_JAVA
160   void addEntryPoint(const EntryPoint& entryPoint);
161   bool tryAddResource(const EntryPoint& entryPoint); // Returns bool indicating success:
162 						     // false if entry point existed already
163   void removeEntryPoint(const std::string& path);
164   void setDefaultEntryPoint(const std::string& path);
165   // Returns matching entry point and match length
166   EntryPointMatch matchEntryPoint(const std::string &scriptName,
167                                   const std::string &path,
168                                   bool matchAfterSlash) const;
169   static bool matchesPath(const std::string &path,
170                           const std::string &prefix,
171 		          bool matchAfterSlash);
172   void setNumThreads(int threads);
173 #endif // WT_TARGET_JAVA
174 
metaHeaders()175   const std::vector<MetaHeader>& metaHeaders() const { return metaHeaders_; }
headMatter()176   const std::vector<HeadMatter>& headMatter() const { return headMatter_; }
177   SessionPolicy sessionPolicy() const;
178   int numProcesses() const;
179   int numThreads() const;
180   int maxNumSessions() const;
181   ::int64_t maxRequestSize() const;
182   ::int64_t maxFormDataSize() const;
183   int maxPendingEvents() const;
184   ::int64_t isapiMaxMemoryRequestSize() const;
185   SessionTracking sessionTracking() const;
186   bool reloadIsNewSession() const;
187   int sessionTimeout() const;
188   int idleTimeout() const;
189   int keepAlive() const; // sessionTimeout() / 2, or if sessionTimeout == -1, 1000000
190   int multiSessionCookieTimeout() const; // sessionTimeout() * 2
191   int bootstrapTimeout() const;
192   int indicatorTimeout() const;
193   int doubleClickTimeout() const;
194   int serverPushTimeout() const;
195   std::string valgrindPath() const;
196   ErrorReporting errorReporting() const;
197   bool debug() const;
198   std::string runDirectory() const;
199   int sessionIdLength() const;
200   std::string sessionIdPrefix() const;
201   int fullSessionIdLength() const; // length of prefix + session id
202   int numSessionThreads() const;
203 
204   bool isAllowedOrigin(const std::string &origin) const;
205 
206 #ifndef WT_TARGET_JAVA
207   bool readConfigurationProperty(const std::string& name, std::string& value)
208     const;
209 #else
210   const std::string *property(const std::string& name) const;
211 #endif
212 
213 #ifndef WT_TARGET_JAVA
214   using IpAddress = AsioWrapper::asio::ip::address;
215 #else
216   struct IpAddress {};
217 #endif
218 
219   struct WT_API Network {
220       IpAddress address;
221       unsigned char prefixLength;
222 
223 #ifndef WT_TARGET_JAVA
224       bool operator==(const Network &other) const noexcept
225       {
226         return address == other.address && prefixLength == other.prefixLength;
227       }
228 
229       bool operator!=(const Network &other) const noexcept
230       {
231         return !operator==(other);
232       }
233 #endif
234 
235       static Network fromString(const std::string &s);
236       bool contains(const IpAddress &address) const;
237   };
238 
239   void setAppRoot(const std::string& path);
240   std::string appRoot() const;
241   bool behindReverseProxy() const; // Deprecated
242   std::string originalIPHeader() const;
243   std::vector<Network> trustedProxies() const;
244   bool isTrustedProxy(const std::string &ipAddress) const;
245   std::string redirectMessage() const;
246   bool serializedEvents() const;
247   bool webSockets() const;
248   bool inlineCss() const;
249   bool persistentSessions() const;
250   bool progressiveBoot(const std::string& internalPath) const;
251   bool splitScript() const;
252   float maxPlainSessionsRatio() const;
253   bool ajaxPuzzle() const;
254   bool sessionIdCookie() const;
255   bool cookieChecks() const;
256   bool useSlashExceptionForInternalPaths() const;
257   bool needReadBodyBeforeResponse() const;
258   bool webglDetect() const;
259 
260   bool agentIsBot(const std::string& agent) const;
261   bool agentSupportsAjax(const std::string& agent) const;
262   std::string uaCompatible() const;
263 
264   // Things which are overridden by the connector
265   void setSessionTimeout(int sessionTimeout);
266   void setWebSockets(bool enabled);
267   void setRunDirectory(const std::string& path);
268   void setUseSlashExceptionForInternalPaths(bool enabled);
269   void setNeedReadBodyBeforeResponse(bool needed);
270   void setBehindReverseProxy(bool enabled);
271   void setOriginalIPHeader(const std::string &originalIPHeader);
272   void setTrustedProxies(const std::vector<Network> &trustedProxies);
273 
274   void setBootstrapMethod(BootstrapMethod method);
275 
276   std::string generateSessionId();
277   bool registerSessionId(const std::string& oldId, const std::string& newId);
278 
279   std::string sessionSocketPath(const std::string& sessionId);
defaultEntryPoint()280   const std::string &defaultEntryPoint() const { return defaultEntryPoint_; }
281 private:
282   struct BootstrapEntry {
283     bool prefix;
284     std::string path;
285     BootstrapMethod method;
286   };
287 
288 #ifdef WT_STD_CONF_LOCK
289   mutable std::shared_mutex mutex_;
290 #endif // WT_STD_CONF_LOCK
291 #ifdef WT_BOOST_CONF_LOCK
292   mutable boost::shared_mutex mutex_;
293 #endif // WT_BOOST_CONF_LOCK
294 
295   WServer *server_;
296   std::string applicationPath_;
297   std::string appRoot_;
298   std::string configurationFile_;
299   std::string uaCompatible_;
300 
301 #ifndef WT_TARGET_JAVA
302   EntryPointList entryPoints_;
303   PathSegment rootPathSegment_; /// The toplevel path segment ('/') for routing,
304                                 /// root of the rounting tree.
305 #endif // WT_TARGET_JAVA
306 
307   SessionPolicy   sessionPolicy_;
308   int             numProcesses_;
309   int             numThreads_;
310   int             maxNumSessions_;
311   ::int64_t       maxRequestSize_;
312   ::int64_t       maxFormDataSize_;
313   int             maxPendingEvents_;
314   ::int64_t       isapiMaxMemoryRequestSize_;
315   SessionTracking sessionTracking_;
316   bool            reloadIsNewSession_;
317   int             sessionTimeout_;
318   int             idleTimeout_;
319   int             bootstrapTimeout_;
320   int		  indicatorTimeout_;
321   int             doubleClickTimeout_;
322   int             serverPushTimeout_;
323   std::string     valgrindPath_;
324   ErrorReporting  errorReporting_;
325   std::string     runDirectory_;
326   int             sessionIdLength_;
327   PropertyMap     properties_;
328   bool            xhtmlMimeType_;
329   bool            behindReverseProxy_;
330 
331   // trusted-proxy-config
332   std::string     originalIPHeader_;
333   std::vector<Network> trustedProxies_;
334 
335   std::string     redirectMsg_;
336   bool            serializedEvents_;
337   bool		  webSockets_;
338   bool            inlineCss_;
339   AgentList       ajaxAgentList_, botList_;
340   bool            ajaxAgentWhiteList_;
341   bool            persistentSessions_;
342   bool            splitScript_;
343   float           maxPlainSessionsRatio_;
344   bool            ajaxPuzzle_;
345   bool            sessionIdCookie_;
346   bool            cookieChecks_;
347   bool            webglDetection_;
348   int             numSessionThreads_;
349 
350   std::vector<std::string> allowedOrigins_;
351 
352   std::vector<BootstrapEntry> bootstrapConfig_;
353   std::vector<MetaHeader> metaHeaders_;
354   std::vector<HeadMatter> headMatter_;
355 
356   bool connectorSlashException_;
357   bool connectorNeedReadBody_;
358   bool connectorWebSockets_;
359   std::string connectorSessionIdPrefix_;
360   std::string defaultEntryPoint_;
361 
362   void reset();
363   void readApplicationSettings(Wt::rapidxml::xml_node<char> *app);
364   void readConfiguration(bool silent);
365   WLogEntry log(const std::string& type) const;
366 
367   // Add the given entryPoint to the routing tree
368   // NOTE: Server may not be running, or WRITE_LOCK should
369   // be grabbed before registerEntryPoint is invoked.
370   // This is to be used by the other entry point functions
371   // (addEntryPoint, tryAddResource, removeEntryPoint,...)
372   void registerEntryPoint(const EntryPoint &entryPoint);
373 };
374 
375 }
376 
377 #endif // HTTP_CONFIGURATION_HPP
378