Skip to content

Commit

Permalink
wip commit
Browse files Browse the repository at this point in the history
Signed-off-by: Rashesh Padia <[email protected]>
Change-Id: I848f853be8c14d3367f8501c603114a3e23a617b
  • Loading branch information
Rash419 committed Aug 16, 2024
1 parent e7966c8 commit f893695
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 8 deletions.
48 changes: 45 additions & 3 deletions wsd/Admin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include <Poco/JSON/Array.h>
#include <Poco/JSON/Object.h>
#include <config.h>

#include <chrono>
#include <cstddef>
#include <iomanip>
#include <string>
#include <sys/poll.h>
#include <unistd.h>

Expand Down Expand Up @@ -41,7 +45,6 @@

using namespace COOLProtocol;

using Poco::Net::HTTPResponse;
using Poco::Util::Application;

const int Admin::MinStatsIntervalMs = 50;
Expand Down Expand Up @@ -416,6 +419,10 @@ void AdminSocketHandler::handleMessage(const std::vector<char> &payload)
{
_admin->setCloseMonitorFlag();
}
else if (tokens.equals(0, "rollingupdate") && tokens.size() > 1)
{
_admin->setRollingUpdateInfo(tokens[1]);
}
}

AdminSocketHandler::AdminSocketHandler(Admin* adminManager,
Expand Down Expand Up @@ -496,8 +503,7 @@ bool AdminSocketHandler::handleInitialRequest(
return true;
}

HTTPResponse response;
response.setStatusAndReason(HTTPResponse::HTTP_BAD_REQUEST);
http::Response response(http::StatusCode::BadRequest);
response.setContentLength(0);
LOG_INF_S("Admin::handleInitialRequest bad request");
socket->send(response);
Expand Down Expand Up @@ -1293,6 +1299,42 @@ void Admin::deleteMonitorSocket(const std::string& uriWithoutParam)
}
}

void Admin::setRollingUpdateInfo(const std::string& jsonString)
{
Poco::JSON::Object::Ptr object;
if (JsonUtil::parseJSON(jsonString, object))
{
bool status = JsonUtil::getJSONValue<bool>(object, "inprogress");
setRollingUpdateStatus(status);
Poco::JSON::Array::Ptr infoArray = object->getArray("serverinfo");
if (!infoArray.isNull())
{
for(size_t i=0; i < infoArray->size(); i++)
{
if (!infoArray->isObject(i))
{
return;
}
const auto serverInfoObject = infoArray->getObject(i);
const std::string gitHash = JsonUtil::getJSONValue<std::string>(serverInfoObject , "gitHash");
const std::string serverId = JsonUtil::getJSONValue<std::string>(serverInfoObject, "serverId");
const std::string routeToken = JsonUtil::getJSONValue<std::string>(serverInfoObject, "routeToken");
_rollingUpdateInfo.try_emplace(gitHash, RollingUpdateServerInfo(gitHash, serverId, routeToken));
}
}
}
}

std::string Admin::getBuddyServer(const std::string& gitHash)
{
auto iterator = _rollingUpdateInfo.find(gitHash);
if (iterator != _rollingUpdateInfo.end())
{
return iterator->second.getRouteToken();
}
return std::string();
}

void Admin::stop()
{
joinThread();
Expand Down
34 changes: 34 additions & 0 deletions wsd/Admin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

#include "net/WebSocketHandler.hpp"
#include "COOLWSD.hpp"
#include <string>
#include <vector>

class Admin;

Expand Down Expand Up @@ -186,6 +188,14 @@ class Admin : public SocketPoll

void setCloseMonitorFlag() { _closeMonitor = true; }

void setRollingUpdateInfo(const std::string& jsonString);

void setRollingUpdateStatus(bool status) { _rollingUpdateStatus = status; }

bool getRollingUpdateStatus() { return _rollingUpdateStatus; }

std::string getBuddyServer(const std::string& gitHash);

private:
/// Notify Forkit of changed settings.
void notifyForkit();
Expand Down Expand Up @@ -253,6 +263,30 @@ class Admin : public SocketPoll
std::map<std::string, std::shared_ptr<MonitorSocketHandler>> _monitorSockets;

std::atomic<bool> _closeMonitor = false;

class RollingUpdateServerInfo
{
public:
std::string getGitHash() { return _gitHash; }
std::string getServerId() { return _serverId; }
std::string getRouteToken() { return _routeToken; }

RollingUpdateServerInfo(const std::string& gitHash, const std::string& serverId,
const std::string& routeToken)
: _gitHash(gitHash)
, _serverId(serverId)
, _routeToken(routeToken)
{
}

private:
std::string _gitHash;
std::string _serverId;
std::string _routeToken;
};

std::map<std::string, RollingUpdateServerInfo> _rollingUpdateInfo;
std::atomic<bool> _rollingUpdateStatus;
};

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
42 changes: 37 additions & 5 deletions wsd/COOLWSD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4323,19 +4323,26 @@ class ClientRequestDispatcher final : public SimpleSocketHandler
}
else if (requestDetails.equals(RequestDetails::Field::Type, "browser") || requestDetails.equals(RequestDetails::Field::Type, "wopi"))
{
std::string requestUri = requestDetails.getURI();
bool versionMismatch = false;
if (requestUri.find("browser/" COOLWSD_VERSION_HASH "/") == std::string::npos &&
requestUri.find("admin/") == std::string::npos)
{
versionMismatch = true;
}

// File server
assert(socket && "Must have a valid socket");
constexpr auto ProxyRemote = "/remote/";
constexpr auto ProxyRemoteLen = sizeof(ProxyRemote) - 1;
constexpr auto ProxyRemoteStatic = "/remote/static/";
const auto uri = requestDetails.getURI();
const auto pos = uri.find(ProxyRemoteStatic);
const auto pos = requestUri.find(ProxyRemoteStatic);
if (pos != std::string::npos)
{
if (Util::endsWith(uri, "lokit-extra-img.svg"))
if (Util::endsWith(requestUri, "lokit-extra-img.svg"))
{
ProxyRequestHandler::handleRequest(
uri.substr(pos + ProxyRemoteLen), socket,
requestUri .substr(pos + ProxyRemoteLen), socket,
ProxyRequestHandler::getProxyRatingServer());
}
#if ENABLE_FEATURE_LOCK
Expand All @@ -4347,12 +4354,37 @@ class ClientRequestDispatcher final : public SimpleSocketHandler
{
const std::string& serverUri =
unlockImageUri.getScheme() + "://" + unlockImageUri.getAuthority();
ProxyRequestHandler::handleRequest(uri.substr(pos + sizeof("/remote/static") - 1),
ProxyRequestHandler::handleRequest(requestUri.substr(pos + sizeof("/remote/static") - 1),
socket, serverUri);
}
}
#endif
}
else if (COOLWSD::IndirectionServerEnabled && versionMismatch &&
Admin::instance().getRollingUpdateStatus())
{
std::string searchString = "/browser/";
size_t startHashPos = requestUri.find(searchString);
if (startHashPos != std::string::npos)
{
startHashPos += searchString.length();
size_t endHashPos = requestUri.find('/', startHashPos);

std::string gitHash;
if (endHashPos != std::string::npos)
{
gitHash = requestUri.substr(startHashPos, endHashPos - startHashPos);
}
else
{
gitHash = requestUri.substr(startHashPos);
}
std::string routeToken = Admin::instance().getBuddyServer(gitHash);
if (!routeToken.empty())
requestUri = requestUri + "?RouteToken=" + routeToken;
ProxyRequestHandler::handleRequest(requestUri, socket);
}
}
else
{
COOLWSD::FileRequestHandler->handleRequest(request, requestDetails, message, socket);
Expand Down
74 changes: 74 additions & 0 deletions wsd/ProxyRequestHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,80 @@
std::unordered_map<std::string, std::shared_ptr<http::Response>> ProxyRequestHandler::CacheFileHash;
std::chrono::system_clock::time_point ProxyRequestHandler::MaxAge;

// TODO: merge below functions into one, to reduce the code duplication
void ProxyRequestHandler::handleRequest(const std::string& requestUri,
const std::shared_ptr<StreamSocket>& socket)
{
Poco::URI uriProxy(requestUri);
constexpr const auto zero = std::chrono::system_clock::time_point();
const auto timeNow = std::chrono::system_clock::now();

if (MaxAge > zero && timeNow > MaxAge)
{
CacheFileHash.clear();
MaxAge = zero;
}

const auto cacheEntry = CacheFileHash.find(uriProxy.getPath());
if (cacheEntry != CacheFileHash.end())
{
socket->sendAndShutdown(*cacheEntry->second);
return;
}

std::cerr << "proxyUri: " << uriProxy.toString() << "\n";
auto protocol = uriProxy.getScheme() == "https" ? http::Session::Protocol::HttpSsl
: http::Session::Protocol::HttpUnencrypted;

auto sessionProxy = http::Session::create(uriProxy.getHost(), protocol, uriProxy.getPort());

sessionProxy->setTimeout(std::chrono::seconds(10));
http::Request requestProxy(uriProxy.getPathAndQuery());
http::Session::FinishedCallback proxyCallback =
[socket, zero](const std::shared_ptr<http::Session>& httpSession)
{
try
{
const auto callbackNow = std::chrono::system_clock::now();
std::shared_ptr<http::Response> httpResponse = httpSession->response();
if (httpResponse->statusLine().statusCode() == http::StatusCode::OK)
{
if (MaxAge == zero)
{
MaxAge = callbackNow + std::chrono::hours(10);
}

CacheFileHash[httpSession->getUrl()] = httpResponse;

// We're proxying, we take responsibility.
httpResponse->set("Server", HTTP_SERVER_STRING);

socket->sendAndShutdown(*httpResponse);
}
else
{
HttpHelper::sendErrorAndShutdown(http::StatusCode::BadRequest, socket);
}
}
catch (std::exception& exc)
{
LOG_ERR("ProxyCallback: " << exc.what());
HttpHelper::sendErrorAndShutdown(http::StatusCode::BadRequest, socket);
}
catch (...)
{
LOG_ERR("ProxyCallback: Unknown exception");
HttpHelper::sendErrorAndShutdown(http::StatusCode::BadRequest, socket);
}
};

sessionProxy->setFinishedHandler(std::move(proxyCallback));
if (!sessionProxy->asyncRequest(requestProxy, *COOLWSD::getWebServerPoll()))
{
HttpHelper::sendErrorAndShutdown(http::StatusCode::BadRequest, socket);
}
}

void ProxyRequestHandler::handleRequest(const std::string& relPath,
const std::shared_ptr<StreamSocket>& socket,
const std::string& serverUri)
Expand Down
4 changes: 4 additions & 0 deletions wsd/ProxyRequestHandler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ class ProxyRequestHandler
static void handleRequest(const std::string& relPath,
const std::shared_ptr<StreamSocket>& socket,
const std::string& serverUri);

static void handleRequest(const std::string& requestUri,
const std::shared_ptr<StreamSocket>& socket);

static std::string getProxyRatingServer() { return ProxyRatingServer; }

private:
Expand Down

0 comments on commit f893695

Please sign in to comment.