From 1d203644ec96dd7390e28a2e34be3ce8152b050c Mon Sep 17 00:00:00 2001 From: Sergey Linev <S.Linev@gsi.de> Date: Fri, 20 Oct 2017 15:17:41 +0200 Subject: [PATCH] http: handle WS connections inside THttpWSHandler Now all WS connections and correspondent THttpWSEngine instances preserved in the THttpWSHandler. User only works with WS Id (UInt_t) and use it to accept connection, close connections, send data via connection --- net/http/inc/THttpWSHandler.h | 25 ++++++++ net/http/src/THttpServer.cxx | 12 ++-- net/http/src/THttpWSHandler.cxx | 100 +++++++++++++++++++++++++++++++- 3 files changed, 130 insertions(+), 7 deletions(-) diff --git a/net/http/inc/THttpWSHandler.h b/net/http/inc/THttpWSHandler.h index 92e081a4714..8685d4200d7 100644 --- a/net/http/inc/THttpWSHandler.h +++ b/net/http/inc/THttpWSHandler.h @@ -14,11 +14,27 @@ #include "TNamed.h" +#include "TList.h" + class THttpCallArg; +class THttpWSEngine; +class THttpServer; class THttpWSHandler : public TNamed { +friend class THttpServer; + +private: + + THttpWSEngine *FindEngine(UInt_t id) const; + + Bool_t DirecltyHandle(THttpCallArg *arg); + + protected: + + TList fEngines; ///<! list of of engines in use, cleaned automatically at the end + THttpWSHandler(const char *name, const char *title); public: @@ -31,6 +47,15 @@ public: /// Used by the webcanvas virtual TString GetDefaultPageContent() { return ""; } + /// Return kTRUE if websocket with given ID exists + Bool_t HasWS(UInt_t wsid) const { return FindEngine(wsid) != 0; } + + void CloseWS(UInt_t wsid); + + void SendWS(UInt_t wsid, const void *buf, int len); + + void SendCharStarWS(UInt_t wsid, const char *str); + virtual Bool_t ProcessWS(THttpCallArg *arg) = 0; ClassDef(THttpWSHandler, 0) // abstract class for handling websocket requests diff --git a/net/http/src/THttpServer.cxx b/net/http/src/THttpServer.cxx index dd296f1aa8a..c11cf374320 100644 --- a/net/http/src/THttpServer.cxx +++ b/net/http/src/THttpServer.cxx @@ -863,7 +863,7 @@ void THttpServer::ProcessRequest(THttpCallArg *arg) THttpWSHandler *handler = dynamic_cast<THttpWSHandler *>(fSniffer->FindTObjectInHierarchy(arg->fPathName.Data())); if (handler) { - handler->ProcessWS(arg); + handler->DirecltyHandle(arg); } else { arg->Set404(); } @@ -881,7 +881,7 @@ void THttpServer::ProcessRequest(THttpCallArg *arg) // if accepted, reply with connection id, which must be used in the following communications arg->SetMethod("WS_CONNECT"); - if (handler && handler->ProcessWS(arg)) { + if (handler && handler->DirecltyHandle(arg)) { arg->SetMethod("WS_READY"); TLongPollEngine *handle = new TLongPollEngine("longpoll", arg->fPathName.Data()); @@ -889,7 +889,7 @@ void THttpServer::ProcessRequest(THttpCallArg *arg) arg->SetWSId(handle->GetId()); arg->SetWSHandle(handle); - if (handler->ProcessWS(arg)) { + if (handler->DirecltyHandle(arg)) { arg->SetContent(TString::Format("%u", arg->GetWSId())); arg->SetContentType("text/plain"); } @@ -921,7 +921,7 @@ void THttpServer::ProcessRequest(THttpCallArg *arg) arg->SetPostData(buf, len / 2); } } - if (handler && !handler->ProcessWS(arg)) + if (handler && !handler->DirecltyHandle(arg)) arg->Set404(); } return; @@ -930,11 +930,11 @@ void THttpServer::ProcessRequest(THttpCallArg *arg) // ROOT emulation of websocket THttpWSHandler *handler = dynamic_cast<THttpWSHandler *>(fSniffer->FindTObjectInHierarchy(arg->fPathName.Data())); - if (!handler || !handler->ProcessWS(arg)) + if (!handler || !handler->DirecltyHandle(arg)) arg->Set404(); if (!arg->Is404() && (arg->fMethod == "WS_CONNECT") && arg->fWSHandle) { arg->SetMethod("WS_READY"); - if (handler->ProcessWS(arg)) { + if (handler->DirecltyHandle(arg)) { arg->SetContent(TString::Format("%u", arg->GetWSId())); arg->SetContentType("text/plain"); } else { diff --git a/net/http/src/THttpWSHandler.cxx b/net/http/src/THttpWSHandler.cxx index 5bf476d0cbf..49baddc9397 100644 --- a/net/http/src/THttpWSHandler.cxx +++ b/net/http/src/THttpWSHandler.cxx @@ -11,6 +11,10 @@ #include "THttpWSHandler.h" +#include "THttpWSEngine.h" +#include "THttpCallArg.h" + + ////////////////////////////////////////////////////////////////////////// // // // THttpWSHandler // @@ -25,10 +29,104 @@ ClassImp(THttpWSHandler); /// normal constructor THttpWSHandler::THttpWSHandler(const char *name, const char *title) : - TNamed(name, title) + TNamed(name, title), fEngines() { } THttpWSHandler::~THttpWSHandler() { + TIter iter(&fEngines); + THttpWSEngine *engine = 0; + + while ((engine = (THttpWSEngine *)iter()) != 0) + engine->ClearHandle(); + + fEngines.Delete(); +} + + +THttpWSEngine *THttpWSHandler::FindEngine(UInt_t id) const +{ + TIter iter(&fEngines); + THttpWSEngine *engine = 0; + + while ((engine = (THttpWSEngine *)iter()) != 0) { + if (engine->GetId() == id) return engine; + } + + return 0; +} + +Bool_t THttpWSHandler::DirecltyHandle(THttpCallArg *arg) +{ + if (!arg->GetWSId()) return ProcessWS(arg); + + THttpWSEngine* engine = FindEngine(arg->GetWSId()); + + if (strcmp(arg->GetMethod(), "WS_CONNECT") == 0) { + // accept all requests, in future one could limit number of connections + return ProcessWS(arg); + } + + if (strcmp(arg->GetMethod(), "WS_READY") == 0) { + + if (engine) { + Error("DirecltyHandle","WS engine with similar id exists %u\n", arg->GetWSId()); + fEngines.Remove(engine); + delete engine; + } + + THttpWSEngine *wshandle = dynamic_cast<THttpWSEngine *>(arg->TakeWSHandle()); + + fEngines.Add(wshandle); + + if (!ProcessWS(arg)) { + // if connection refused, remove engine again + fEngines.Remove(wshandle); + delete wshandle; + return kFALSE; + } + + return kTRUE; + } + + if (strcmp(arg->GetMethod(), "WS_CLOSE") == 0) { + // connection is closed, one can remove handle + + if (engine) { + engine->ClearHandle(); + fEngines.Remove(engine); + delete engine; + } + + return ProcessWS(arg); + } + + if (engine && engine->PreviewData(arg)) return kTRUE; + + return ProcessWS(arg); +} + +void THttpWSHandler::CloseWS(UInt_t wsid) +{ + THttpWSEngine* engine = FindEngine(wsid); + + if (engine) { + fEngines.Remove(engine); + delete engine; + } +} + +void THttpWSHandler::SendWS(UInt_t wsid, const void *buf, int len) +{ + THttpWSEngine* engine = FindEngine(wsid); + + if (engine) engine->Send(buf, len); +} + +void THttpWSHandler::SendCharStarWS(UInt_t wsid, const char *str) +{ + THttpWSEngine* engine = FindEngine(wsid); + + if (engine) engine->SendCharStar(str); } -- GitLab