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