diff --git a/net/http/inc/THttpWSHandler.h b/net/http/inc/THttpWSHandler.h index 92e081a4714d2f879e89bd6b8d3e379635a2d82d..8685d4200d755c61fc2f2872f537c14e474034c2 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 dd296f1aa8a306d7cc2e63a85514da7093e7067b..c11cf3743204dc18c031b4fa4cb2bcd048fce7c8 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 5bf476d0cbf8cc718416c11f9935594ab3d262e3..49baddc9397c2d44cd4f38ee0cd6afd9bbbc038d 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); }