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 WT_WEB_CONTROLLER_H_ 8 #define WT_WEB_CONTROLLER_H_ 9 10 #include <string> 11 #include <vector> 12 #include <set> 13 #include <map> 14 15 #include <Wt/WDllDefs.h> 16 #include <Wt/WServer.h> 17 #include <Wt/WSocketNotifier.h> 18 19 #include "EntryPoint.h" 20 #include "SocketNotifier.h" 21 22 #if defined(WT_THREADED) && !defined(WT_TARGET_JAVA) 23 #include <thread> 24 #include <mutex> 25 #endif 26 27 namespace http { 28 namespace server { 29 class ProxyReply; 30 } 31 } 32 33 namespace Wt { 34 35 class Configuration; 36 class EntryPoint; 37 38 class WebRequest; 39 class WebSession; 40 41 class WApplication; 42 class WServer; 43 44 #ifdef WT_CNOR 45 class Runnable { 46 public: 47 void run(); 48 }; 49 50 typedef Runnable *Function; 51 52 #define WT_CALL_FUNCTION(f) (f)->run(); 53 54 #else 55 typedef std::function<void ()> Function; 56 #define WT_CALL_FUNCTION(f) (f)(); 57 #endif 58 59 /* 60 * An event to be delivered to a session which is not caused by a web 61 * request (or, probably not one for that session). 62 */ 63 struct ApplicationEvent { 64 ApplicationEvent(const std::string& aSessionId, 65 const Function& aFunction, 66 const Function& aFallbackFunction = Function()) sessionIdApplicationEvent67 : sessionId(aSessionId), 68 function(aFunction), 69 fallbackFunction(aFallbackFunction) 70 { } 71 72 std::string sessionId; 73 Function function; 74 Function fallbackFunction; 75 }; 76 77 /* 78 * The controller handle incoming request, in handleRequest(). 79 * Optionally, it will expire session on each incoming request. Seems 80 * harmless to me (but causes confusion to others). 81 * 82 * There is a method shutdown() to quit the controller. 83 * 84 * It has the following tasks: 85 * - handle session life-cycle: create new sessions, delete quit()ed 86 * sessions, expire sessions on timeout 87 * - handles web requests and application events 88 */ 89 class WT_API WebController 90 #ifdef WT_TARGET_JAVA 91 : public WServer 92 #endif // WT_TARGET_JAVA 93 { 94 public: isAsyncSupported()95 static bool isAsyncSupported() { return true; } 96 97 std::unique_ptr<WApplication> doCreateApplication(WebSession *session); 98 Configuration& configuration(); 99 100 void addSession(const std::shared_ptr<WebSession>& session); 101 void removeSession(const std::string& sessionId); 102 void sessionDeleted(); 103 104 void newAjaxSession(); 105 bool limitPlainHtmlSessions(); server()106 WServer *server() { return &server_; } 107 108 std::string computeRedirectHash(const std::string& url); 109 110 #ifdef WT_TARGET_JAVA 111 int getIdForWebSocket(); 112 std::string getContextPath(); 113 #else // WT_TARGET_JAVA 114 WebController(WServer& server, 115 const std::string& singleSessionId = std::string(), 116 bool autoExpire = true); 117 ~WebController(); 118 119 int sessionCount() const; 120 121 // Returns whether we should continue receiving data. 122 bool requestDataReceived(WebRequest *request, std::uintmax_t current, 123 std::uintmax_t total); 124 125 void handleRequest(WebRequest *request); 126 127 #ifndef WT_CNOR 128 bool handleApplicationEvent(const std::shared_ptr<ApplicationEvent>& event); 129 #endif // WT_CNOR 130 131 std::vector<std::string> sessions(bool onlyRendered = false); 132 bool expireSessions(); 133 void start(); 134 void shutdown(); 135 136 static std::string sessionFromCookie(const char * const cookies, 137 const std::string& scriptName, 138 const int sessionIdLength); 139 140 typedef std::map<int, WSocketNotifier *> SocketNotifierMap; 141 142 void addSocketNotifier(WSocketNotifier *notifier); 143 void removeSocketNotifier(WSocketNotifier *notifier); 144 145 void addUploadProgressUrl(const std::string& url); 146 void removeUploadProgressUrl(const std::string& url); 147 148 // returns false if removeSocketNotifier was called while processing 149 void socketSelected(int descriptor, WSocketNotifier::Type type); 150 151 std::string switchSession(WebSession *session, 152 const std::string& newSessionId); 153 std::string generateNewSessionId(const std::shared_ptr<WebSession>& session); 154 155 private: 156 Configuration& conf_; 157 std::string singleSessionId_; 158 bool autoExpire_; 159 int plainHtmlSessions_, ajaxSessions_; 160 volatile int zombieSessions_; 161 std::string redirectSecret_; 162 bool running_; 163 164 #ifdef WT_THREADED 165 std::mutex uploadProgressUrlsMutex_; 166 #endif // WT_THREADED 167 std::set<std::string> uploadProgressUrls_; 168 169 typedef std::map<std::string, std::shared_ptr<WebSession> > SessionMap; 170 SessionMap sessions_; 171 172 #ifdef WT_THREADED 173 // mutex to protect access to the sessions map and plain/ajax session 174 // counts 175 mutable std::recursive_mutex mutex_; 176 177 SocketNotifier socketNotifier_; 178 // mutex to protect access to notifier maps. This cannot be protected 179 // by mutex_ as this lock is grabbed while the application lock is 180 // being held, which would potentially deadlock if we took mutex_. 181 std::recursive_mutex notifierMutex_; 182 SocketNotifierMap socketNotifiersRead_; 183 SocketNotifierMap socketNotifiersWrite_; 184 SocketNotifierMap socketNotifiersExcept_; 185 // assumes that you did grab the notifierMutex_ 186 SocketNotifierMap& socketNotifiers(WSocketNotifier::Type type); 187 void socketNotify(int descriptor, WSocketNotifier::Type type); 188 #endif 189 190 struct UpdateResourceProgressParams { 191 std::string requestParam; 192 std::string resourceParam; 193 ::int64_t postDataExceeded; 194 std::string pathInfo; 195 std::uintmax_t current; 196 std::uintmax_t total; 197 }; 198 void updateResourceProgress(const UpdateResourceProgressParams ¶ms); 199 200 EntryPointMatch getEntryPoint(WebRequest *request); 201 202 static std::string appSessionCookie(const std::string& url); 203 204 #endif // WT_TARGET_JAVA 205 206 WServer& server_; 207 208 friend class http::server::ProxyReply; 209 friend class WEnvironment; 210 }; 211 212 } 213 214 #endif // WT_WEB_CONTROLLER_H_ 215