From 6a48cb501381739f1ab6623b7fb20f2f2a255831 Mon Sep 17 00:00:00 2001
From: Bruce Toll <btoll@dhsus.com>
Date: Tue, 2 Jun 2020 12:01:51 -0400
Subject: [PATCH 3/4] Add weakSessionId support for dedicated sessions

---
 src/http/ProxyReply.C            | 10 ++++++++-
 src/http/SessionProcess.C        |  5 +++++
 src/http/SessionProcess.h        |  4 ++++
 src/http/SessionProcessManager.C | 30 ++++++++++++++++---------
 src/http/SessionProcessManager.h | 38 ++++++++++++++++++++++++++++++--
 src/web/WebRenderer.C            |  3 ++-
 6 files changed, 76 insertions(+), 14 deletions(-)

diff --git a/src/http/ProxyReply.C b/src/http/ProxyReply.C
index 76463ac0..db978676 100644
--- a/src/http/ProxyReply.C
+++ b/src/http/ProxyReply.C
@@ -441,7 +441,15 @@ void ProxyReply::handleHeadersRead(const Wt::AsioWrapper::error_code &ec)
 	  webSocketConnection = true;
 	}
       } else if (boost::iequals(name, "X-Wt-Session")) {
-	sessionManager_.addSessionProcess(value, sessionProcess_);
+        std::vector<std::string> id_v;
+        boost::split(id_v, value, boost::is_any_of(","));
+        if (id_v.size() != 2) {
+          LOG_ERROR("unexpected X-Wt-Session header value: " << value);
+          if (!sendReload())
+	    error(internal_server_error);
+          return;
+        }
+	sessionManager_.addSessionProcess(id_v[0], id_v[1], sessionProcess_);
       } else if (boost::iequals(name, "Upgrade")) {
 	// Remove hop-by-hop header
 	if (boost::icontains(value, "websocket")) {
diff --git a/src/http/SessionProcess.C b/src/http/SessionProcess.C
index 2a1d8f51..5d3e0a82 100644
--- a/src/http/SessionProcess.C
+++ b/src/http/SessionProcess.C
@@ -137,6 +137,11 @@ void SessionProcess::setSessionId(const std::string& sessionId)
   sessionId_ = sessionId;
 }
 
+void SessionProcess::setWeakSessionId(const std::string& weakSessionId)
+{
+  weakSessionId_ = weakSessionId;
+}
+
 asio::ip::tcp::endpoint SessionProcess::endpoint() const
 {
   return asio::ip::tcp::endpoint(asio::ip::address_v4::loopback(), port_);
diff --git a/src/http/SessionProcess.h b/src/http/SessionProcess.h
index 236d10bf..9e2e019c 100644
--- a/src/http/SessionProcess.h
+++ b/src/http/SessionProcess.h
@@ -52,6 +52,9 @@ public:
   const std::string& sessionId() const { return sessionId_; }
   void setSessionId(const std::string& sessionId);
 
+  const std::string& weakSessionId() const { return weakSessionId_; }
+  void setWeakSessionId(const std::string& weakSessionId);
+
   // Get the endpoint to connect to
   asio::ip::tcp::endpoint endpoint() const;
 
@@ -76,6 +79,7 @@ private:
   char			   buf_[6];
 
   std::string		   sessionId_;
+  std::string		   weakSessionId_;
 #ifndef WT_WIN32
   pid_t			   pid_;
 #else // WT_WIN32
diff --git a/src/http/SessionProcessManager.C b/src/http/SessionProcessManager.C
index 6365439e..12563465 100644
--- a/src/http/SessionProcessManager.C
+++ b/src/http/SessionProcessManager.C
@@ -91,8 +91,17 @@ const std::shared_ptr<SessionProcess>& SessionProcessManager
 #endif // WT_THREADED
   SessionMap::const_iterator it = sessions_.find(sessionId);
   if (it != sessions_.end()) {
-    return it->second;
+    return it->sessionProcessRef();
   }
+
+  // Not a valid regular sessionId, perhaps it is a weakSessionId (used for resources)?
+  SessionMap::index<WeakSessionIdTag>::type::iterator itw =
+    sessions_.get<WeakSessionIdTag>().find(sessionId);
+
+  if (itw != sessions_.get<WeakSessionIdTag>().end()) {
+    return itw->sessionProcessRef();
+  }
+
   return nullProcessPtr;
 }
 
@@ -107,14 +116,14 @@ void SessionProcessManager
 }
 
 void SessionProcessManager
-::addSessionProcess(std::string sessionId, 
+::addSessionProcess(std::string sessionId, std::string weakSessionId,
 		    const std::shared_ptr<SessionProcess>& process)
 {
 #ifdef WT_THREADED
   std::unique_lock<std::mutex> lock(sessionsMutex_);
 #endif // WT_THREADED
 
-  LOG_DEBUG("addSessionProcess()" << sessionId);
+  LOG_DEBUG("addSessionProcess(): sessionId: " << sessionId << ", weakSessionId" << weakSessionId);
   for (SessionProcessList::iterator it = pendingProcesses_.begin();
        it != pendingProcesses_.end(); ++it) {
     if (process == *it) {
@@ -126,7 +135,8 @@ void SessionProcessManager
     sessions_.erase(process->sessionId());
   }
   process->setSessionId(sessionId);
-  sessions_[sessionId] = process;
+  process->setWeakSessionId(weakSessionId);
+  sessions_.insert(SessionEntry(sessionId, weakSessionId, process));
 }
 
 std::vector<Wt::WServer::SessionInfo> SessionProcessManager::sessions() const
@@ -139,11 +149,11 @@ std::vector<Wt::WServer::SessionInfo> SessionProcessManager::sessions() const
        it != sessions_.end(); ++it) {
     Wt::WServer::SessionInfo sessionInfo;
 #ifndef WT_WIN32
-    sessionInfo.processId = it->second->pid();
+    sessionInfo.processId = it->sessionProcessRef()->pid();
 #else // WT_WIN32
-    sessionInfo.processId = it->second->processInfo().dwProcessId;
+    sessionInfo.processId = it->sessionProcessRef()->processInfo().dwProcessId;
 #endif // WT_WIN32
-    sessionInfo.sessionId = it->first;
+    sessionInfo.sessionId = it->sessionId();
     result.push_back(sessionInfo);
   }
   return result;
@@ -233,10 +243,10 @@ void SessionProcessManager::removeSessionForPid(pid_t cpid)
 #endif // WT_THREADED
   for (SessionMap::iterator it = sessions_.begin();
        it != sessions_.end(); ++it) {
-    if(it->second->pid() == cpid) {
-      LOG_INFO("Child process " << cpid << " died, removing session " << it->first
+    if(it->sessionProcessRef()->pid() == cpid) {
+      LOG_INFO("Child process " << cpid << " died, removing session " << it->sessionId()
 	  << " (#sessions: " << (sessions_.size() - 1) << ")");
-      it->second->stop();
+      it->sessionProcessRef()->stop();
       sessions_.erase(it);
       -- numSessions_;
       return;
diff --git a/src/http/SessionProcessManager.h b/src/http/SessionProcessManager.h
index 346d9872..b19d24f0 100644
--- a/src/http/SessionProcessManager.h
+++ b/src/http/SessionProcessManager.h
@@ -17,7 +17,6 @@
 namespace http {
 namespace server {
 
-typedef std::map<std::string, std::shared_ptr<SessionProcess> > SessionMap;
 typedef std::vector<std::shared_ptr<SessionProcess> > SessionProcessList;
 
 /// For dedicated processes: maps session ids to child processes and their sockets
@@ -35,12 +34,47 @@ public:
   bool tryToIncrementSessionCount();
   const std::shared_ptr<SessionProcess>& sessionProcess(std::string sessionId);
   void addPendingSessionProcess(const std::shared_ptr<SessionProcess>& process);
-  void addSessionProcess(std::string sessionId,
+  void addSessionProcess(std::string sessionId, std::string weakSessionId,
 			 const std::shared_ptr<SessionProcess>& process);
 
   std::vector<Wt::WServer::SessionInfo> sessions() const;
 
 private:
+  class SessionMap;
+  class SessionEntry {
+  public:
+    SessionEntry(std::string sessionId, std::string weakSessionId, std::shared_ptr<SessionProcess> sessionProcess) :
+      sessionId_(sessionId), weakSessionId_(weakSessionId), sessionProcess_(sessionProcess) {}
+
+    std::string sessionId() const { return sessionId_; }
+    std::string weakSessionId() const { return weakSessionId_; }
+    std::shared_ptr<SessionProcess> sessionProcess() const { return sessionProcess_; }
+    const std::shared_ptr<SessionProcess>& sessionProcessRef() const { return sessionProcess_; }
+
+  private:
+    std::string sessionId_;
+    std::string weakSessionId_;
+    std::shared_ptr<SessionProcess> sessionProcess_;
+
+  friend class SessionMap;
+  };
+
+  struct SessionIdTag { };
+  struct WeakSessionIdTag { };
+  class SessionMap : public boost::multi_index_container<
+    SessionEntry,
+    boost::multi_index::indexed_by<
+      boost::multi_index::ordered_unique<
+        boost::multi_index::tag<SessionIdTag>,
+        boost::multi_index::member<SessionEntry, std::string, &SessionEntry::sessionId_>
+      >,
+      boost::multi_index::hashed_unique<
+        boost::multi_index::tag<WeakSessionIdTag>,
+        boost::multi_index::member<SessionEntry, std::string, &SessionEntry::weakSessionId_>
+      >
+    >
+  >{ };
+
   void processDeadChildren(Wt::AsioWrapper::error_code ec);
 #ifndef WT_WIN32
   void removeSessionForPid(pid_t cpid);
diff --git a/src/web/WebRenderer.C b/src/web/WebRenderer.C
index f683d438..1a3e58ef 100644
--- a/src/web/WebRenderer.C
+++ b/src/web/WebRenderer.C
@@ -575,7 +575,8 @@ void WebRenderer::setHeaders(WebResponse& response, const std::string mimeType)
 #ifndef WT_TARGET_JAVA
   const WServer *s = session_.controller()->server();
   if (s->dedicatedSessionProcess()) {
-    response.addHeader("X-Wt-Session", session_.sessionId());
+    response.addHeader("X-Wt-Session",
+                       session_.sessionId() + "," + session_.weakSessionId());
   }
 #endif // WT_TARGET_JAVA
 
-- 
2.23.2

