Coverage Report

Created: 2025-10-10 06:09

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