21#include "RConfigure.h"
50class THttpTimer :
public TTimer {
59 virtual void Timeout() { fServer.ProcessRequests(); }
147 Warning(
"THttpServer",
"problems resolving '%s', use JSROOTSYS to specify $ROOTSYS/etc/http location",
163 if (strstr(engine,
"basic_sniffer")) {
168 sniff = (
TRootSniffer *)
gROOT->ProcessLineSync(
"new TRootSnifferFull(\"sniff\");");
176 if (strchr(engine,
';') == 0) {
183 if ((strcmp(opt,
"readonly") == 0) || (strcmp(opt,
"ro") == 0)) {
185 }
else if ((strcmp(opt,
"readwrite") == 0) || (strcmp(opt,
"rw") == 0)) {
187 }
else if (strcmp(opt,
"global") == 0) {
189 }
else if (strcmp(opt,
"noglobal") == 0) {
191 }
else if (strncmp(opt,
"cors=", 5) == 0) {
193 }
else if (strcmp(opt,
"cors") == 0) {
218 std::unique_lock<std::mutex> lk(
fMutex);
225 owner = opt && !strcmp(opt,
"owner");
232 while ((engine = (
THttpEngine *)iter()) !=
nullptr)
290 if (!prefix || (*prefix == 0))
310 fJSROOT = location ? location :
"";
321 if (!filename.empty())
338 if (!filename.empty())
362 const char *arg = strchr(engine,
':');
368 clname.
Append(engine, arg - engine);
372 if ((clname.
Length() == 0) || (clname ==
"http") || (clname ==
"civetweb")) {
374 }
else if (clname ==
"https") {
376 }
else if (clname ==
"fastcgi") {
393 if (!eng->
Create(arg + 1)) {
428 Error(
"SetTimer",
"Server runs already in special thread, therefore no any timer can be created");
430 fTimer =
new THttpTimer(milliSec, mode, *
this);
453 std::thread thrd([
this] {
456 int nprocess = ProcessRequests();
463 std::this_thread::sleep_for(std::chrono::milliseconds(1));
468 fThrd = std::move(thrd);
490 if (!fname || (*fname == 0))
495 while (*fname != 0) {
498 const char *next = strpbrk(fname,
"/\\");
503 if ((next == fname + 2) && (*fname ==
'.') && (*(fname + 1) ==
'.')) {
512 if ((next == fname + 1) && (*fname ==
'.')) {
539 if (!uri || (*uri == 0))
548 fname.
Remove(0, pos + (iter->first.length() - 1));
551 res = iter->second.c_str();
552 if ((fname[0] ==
'/') && (res[res.
Length() - 1] ==
'/'))
566Bool_t THttpServer::ExecuteHttp(std::shared_ptr<THttpCallArg> arg)
580 std::unique_lock<std::mutex> lk(
fMutex);
608 std::unique_lock<std::mutex> lk(
fMutex);
639 arg->NotifyCondition();
646 std::unique_lock<std::mutex> lk(
fMutex);
648 fArgs.push(std::shared_ptr<THttpCallArg>(arg));
665Bool_t THttpServer::SubmitHttp(std::shared_ptr<THttpCallArg> arg,
Bool_t can_run_immediately)
672 arg->NotifyCondition();
677 std::unique_lock<std::mutex> lk(
fMutex);
692Int_t THttpServer::ProcessRequests()
698 Error(
"ProcessRequests",
"Should be called only from main ROOT thread");
704 std::unique_lock<std::mutex> lk(
fMutex, std::defer_lock);
708 std::shared_ptr<THttpCallArg> arg;
711 if (!
fArgs.empty()) {
720 if (arg->fFileName ==
"root_batch_holder.js") {
735 arg->NotifyCondition();
762 arg->NotifyCondition();
768 while ((engine = (
THttpEngine *)iter()) !=
nullptr) {
794 auto wsptr = FindWS(arg->GetPathName());
796 if (!wsptr || !wsptr->ProcessBatchHolder(arg)) {
798 arg->NotifyCondition();
811 }
else if ((arg->fFileName ==
"root.websocket") || (arg->fFileName ==
"root.longpoll")) {
840 auto handler = wsptr.get();
847 arg->
fContent = handler->GetDefaultPageContent().Data();
849 if (arg->
fContent.find(
"file:") == 0) {
872 std::string repl(
"=\"");
874 if (repl.back() !=
'/')
879 const char *hjsontag =
"\"$$$h.json$$$\"";
882 if (arg->
fContent.find(hjsontag) != std::string::npos) {
909 const char *rootjsontag =
"\"$$$root.json$$$\"";
910 const char *hjsontag =
"\"$$$h.json$$$\"";
916 std::string repl(
"=\"");
918 if (repl.back() !=
'/')
924 (arg->
fContent.find(hjsontag) != std::string::npos)) {
936 (arg->
fContent.find(rootjsontag) != std::string::npos)) {
967 if ((filename ==
"h.xml") || (filename ==
"get.xml")) {
973 res.
Form(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
995 }
else if (filename ==
"h.json") {
1018 if (filename ==
"root.bin") {
1038Bool_t THttpServer::Register(
const char *subfolder,
TObject *obj)
1058void THttpServer::RegisterWS(std::shared_ptr<THttpWSHandler>
ws)
1060 std::lock_guard<std::mutex> grd(
fWSMutex);
1067void THttpServer::UnregisterWS(std::shared_ptr<THttpWSHandler>
ws)
1069 std::lock_guard<std::mutex> grd(
fWSMutex);
1080std::shared_ptr<THttpWSHandler> THttpServer::FindWS(
const char *
name)
1082 std::lock_guard<std::mutex> grd(
fWSMutex);
1094Bool_t THttpServer::ExecuteWS(std::shared_ptr<THttpCallArg> &arg,
Bool_t external_thrd,
Bool_t wait_process)
1101 auto wsptr = FindWS(arg->GetPathName());
1103 auto handler = wsptr.get();
1105 if (!handler && !external_thrd)
1108 if (external_thrd && (!handler || !handler->AllowMTProcess())) {
1109 std::unique_lock<std::mutex> lk(
fMutex);
1112 if (wait_process) arg->fCond.wait(lk);
1122 if (arg->fFileName ==
"root.websocket") {
1124 process = handler->HandleWS(arg);
1125 }
else if (arg->fFileName ==
"root.longpoll") {
1127 if (arg->fQuery.BeginsWith(
"raw_connect") || arg->fQuery.BeginsWith(
"txt_connect")) {
1130 arg->SetMethod(
"WS_CONNECT");
1132 bool israw = arg->fQuery.BeginsWith(
"raw_connect");
1137 if (handler->HandleWS(arg)) {
1138 arg->SetMethod(
"WS_READY");
1140 if (handler->HandleWS(arg))
1141 arg->SetTextContent(std::string(israw ?
"txt:" :
"") + std::to_string(arg->GetWSId()));
1143 arg->TakeWSEngine();
1146 process = arg->IsText();
1152 arg->SetWSId((
UInt_t)connid);
1154 arg->SetMethod(
"WS_CLOSE");
1155 arg->SetTextContent(
"OK");
1157 arg->SetMethod(
"WS_DATA");
1160 process = handler->HandleWS(arg);
1164 if (!process) arg->Set404();
1207Bool_t THttpServer::RegisterCommand(
const char *cmdname,
const char *method,
const char *icon)
1215Bool_t THttpServer::Hide(
const char *foldername,
Bool_t hide)
1217 return SetItemField(foldername,
"_hidden", hide ?
"true" : (
const char *)0);
1226Bool_t THttpServer::SetIcon(
const char *fullname,
const char *iconname)
1228 return SetItemField(fullname,
"_icon", iconname);
1233Bool_t THttpServer::CreateItem(
const char *fullname,
const char *title)
1240Bool_t THttpServer::SetItemField(
const char *fullname,
const char *
name,
const char *value)
1247const char *THttpServer::GetItemField(
const char *fullname,
const char *
name)
1255const char *THttpServer::GetMimeType(
const char *path)
1257 static const struct {
1262 {
".json", 5,
"application/json"},
1263 {
".bin", 4,
"application/x-binary"},
1264 {
".gif", 4,
"image/gif"},
1265 {
".jpg", 4,
"image/jpeg"},
1266 {
".png", 4,
"image/png"},
1267 {
".html", 5,
"text/html"},
1268 {
".htm", 4,
"text/html"},
1269 {
".shtm", 5,
"text/html"},
1270 {
".shtml", 6,
"text/html"},
1271 {
".css", 4,
"text/css"},
1272 {
".js", 3,
"application/x-javascript"},
1273 {
".ico", 4,
"image/x-icon"},
1274 {
".jpeg", 5,
"image/jpeg"},
1275 {
".svg", 4,
"image/svg+xml"},
1276 {
".txt", 4,
"text/plain"},
1277 {
".torrent", 8,
"application/x-bittorrent"},
1278 {
".wav", 4,
"audio/x-wav"},
1279 {
".mp3", 4,
"audio/x-mp3"},
1280 {
".mid", 4,
"audio/mid"},
1281 {
".m3u", 4,
"audio/x-mpegurl"},
1282 {
".ogg", 4,
"application/ogg"},
1283 {
".ram", 4,
"audio/x-pn-realaudio"},
1284 {
".xslt", 5,
"application/xml"},
1285 {
".xsl", 4,
"application/xml"},
1286 {
".ra", 3,
"audio/x-pn-realaudio"},
1287 {
".doc", 4,
"application/msword"},
1288 {
".exe", 4,
"application/octet-stream"},
1289 {
".zip", 4,
"application/x-zip-compressed"},
1290 {
".xls", 4,
"application/excel"},
1291 {
".tgz", 4,
"application/x-tar-gz"},
1292 {
".tar", 4,
"application/x-tar"},
1293 {
".gz", 3,
"application/x-gunzip"},
1294 {
".arj", 4,
"application/x-arj-compressed"},
1295 {
".rar", 4,
"application/x-arj-compressed"},
1296 {
".rtf", 4,
"application/rtf"},
1297 {
".pdf", 4,
"application/pdf"},
1298 {
".swf", 4,
"application/x-shockwave-flash"},
1299 {
".mpg", 4,
"video/mpeg"},
1300 {
".webm", 5,
"video/webm"},
1301 {
".mpeg", 5,
"video/mpeg"},
1302 {
".mov", 4,
"video/quicktime"},
1303 {
".mp4", 4,
"video/mp4"},
1304 {
".m4v", 4,
"video/x-m4v"},
1305 {
".asf", 4,
"video/x-ms-asf"},
1306 {
".avi", 4,
"video/x-msvideo"},
1307 {
".bmp", 4,
"image/bmp"},
1308 {
".ttf", 4,
"application/x-font-ttf"},
1311 int path_len = strlen(path);
1322 return "text/plain";
1328char *THttpServer::ReadFileContent(
const char *filename,
Int_t &len)
1332 std::ifstream is(filename, std::ios::in | std::ios::binary);
1336 is.seekg(0, is.end);
1338 is.seekg(0, is.beg);
1340 char *buf = (
char *)
malloc(len);
1354std::string THttpServer::ReadFileContent(
const std::string &filename)
1356 std::ifstream is(filename, std::ios::in | std::ios::binary);
1359 is.seekg(0, std::ios::end);
1360 res.resize(is.tellg());
1361 is.seekg(0, std::ios::beg);
1362 is.read((
char *)res.data(), res.length());
char * Form(const char *fmt,...)
R__EXTERN TSystem * gSystem
static const struct @132 builtin_mime_types[]
The ROOT global object gROOT contains a list of all defined classes.
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
void Set404()
mark reply as 404 error - page/request not exists or refused
void SetJson()
Set content type as "application/json".
void SetFile(const char *filename=nullptr)
indicate that http request should response with file content
std::condition_variable fCond
! condition used to wait for processing
TString fTopName
! top item name
void AddHeader(const char *name, const char *value)
Set name: value pair to reply header Content-Type field handled separately - one should use SetConten...
TString fPathName
! item path
void ReplaceAllinContent(const std::string &from, const std::string &to)
Replace all occurrences of.
TString fQuery
! additional arguments
void AddNoCacheHeader()
Set CacheControl http header to disable browser caching.
void SetXml()
Set content type as "text/xml".
void SetContent(const char *cont)
Set content as text.
TString fFileName
! file name
void SetContentType(const char *typ)
set content type like "text/xml" or "application/json"
const char * GetPathName() const
returns path name from request URL
void SetZipping(Int_t mode=kZipLarge)
void SetServer(THttpServer *serv)
virtual Bool_t Create(const char *)
Method to create all components of engine.
virtual void Process()
Method regularly called in main ROOT context.
virtual void Terminate()
Method called when server want to be terminated.
Bool_t IsReadOnly() const
returns read-only mode
TString fJSROOT
! location of external JSROOT files
virtual void ProcessRequest(std::shared_ptr< THttpCallArg > arg)
Process single http request Depending from requested path and filename different actions will be perf...
void SetTimer(Long_t milliSec=100, Bool_t mode=kTRUE)
create timer which will invoke ProcessRequests() function periodically Timer is required to perform a...
virtual void ProcessBatchHolder(std::shared_ptr< THttpCallArg > &arg)
Process special http request for root_batch_holder.js script This kind of requests used to hold web b...
std::vector< std::shared_ptr< THttpWSHandler > > fWSHandlers
! list of WS handlers
virtual ~THttpServer()
destructor delete all http engines and sniffer
void SetTerminate()
set termination flag, no any further requests will be processed
virtual void MissedRequest(THttpCallArg *arg)
Method called when THttpServer cannot process request By default such requests replied with 404 code ...
Bool_t fOwnThread
! true when specialized thread allocated for processing requests
void SetSniffer(TRootSniffer *sniff)
Set TRootSniffer to the server Server takes ownership over sniffer.
Bool_t IsFileRequested(const char *uri, TString &res) const
Check if file is requested, thread safe.
const char * GetCors() const
Returns specified CORS domain.
std::thread fThrd
! own thread
void StopServerThread()
Stop server thread Normally called shortly before http server destructor.
TString fTopName
! name of top folder, default - "ROOT"
TRootSniffer * fSniffer
! sniffer provides access to ROOT objects hierarchy
void SetDrawPage(const std::string &filename="")
Set file name of HTML page, delivered by the server when objects drawing page is requested from the b...
THttpServer(const char *engine="civetweb:8080")
constructor
void AddLocation(const char *prefix, const char *path)
add files location, which could be used in the server one could map some system folder to the server ...
std::map< std::string, std::string > fLocations
! list of local directories, which could be accessed via server
TList fCallArgs
! submitted arguments (deprecated)
Long_t fMainThrdId
! id of the thread for processing requests
TString fJSROOTSYS
! location of local JSROOT files
TList fEngines
! engines which runs http server
void SetCors(const std::string &domain="*")
Enable CORS header to ProcessRequests() responses Specified location (typically "*") add as "Access-C...
Bool_t IsCors() const
Returns kTRUE if CORS was configured.
std::queue< std::shared_ptr< THttpCallArg > > fArgs
! submitted arguments
void SetDefaultPage(const std::string &filename="")
Set file name of HTML page, delivered by the server when http address is opened in the browser.
void CreateServerThread()
Creates special thread to process all requests, directed to http server.
std::string fDrawPageCont
! content of draw html page
THttpTimer * fTimer
! timer used to access main thread
std::mutex fWSMutex
! mutex to protect WS handler lists
Bool_t CreateEngine(const char *engine)
factory method to create different http engines At the moment two engine kinds are supported: civetwe...
std::string fDrawPage
! file name for drawing of single element
std::string fDefaultPageCont
! content of default html page
static Bool_t VerifyFilePath(const char *fname)
Checked that filename does not contains relative path below current directory Used to prevent access ...
void SetReadOnly(Bool_t readonly)
Set read-only mode for the server (default on) In read-only server is not allowed to change any ROOT ...
void SetJSROOT(const char *location)
Set location of JSROOT to use with the server One could specify address like: https://root....
std::mutex fMutex
! mutex to protect list with arguments
std::string fDefaultPage
! file name for default page name
TRootSniffer * GetSniffer() const
returns pointer on objects sniffer
Bool_t fTerminated
! termination flag, disables all requests processing
virtual void Add(TObject *obj)
virtual TObjLink * FirstLink() const
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
virtual TObject * First() const
Return the first object in the list. Returns 0 when list is empty.
The TNamed class is the base class for all named ROOT classes.
virtual const char * GetName() const
Returns name of object.
Int_t GetLast() const
Return index of last object in array.
TObject * At(Int_t idx) const
virtual Option_t * GetAddOption() const
Mother of all ROOT objects.
virtual const char * GetName() const
Returns name of object.
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
static const TString & GetRootSys()
Get the rootsys directory in the installation. Static utility function.
static const TString & GetEtcDir()
Get the sysconfig directory in the installation. Static utility function.
Storage of hierarchy scan in TRootSniffer in JSON format.
Storage of hierarchy scan in TRootSniffer in XML format.
void ScanHierarchy(const char *topname, const char *path, TRootSnifferStore *store, Bool_t only_fields=kFALSE)
Method scans normal objects, registered in ROOT.
void SetCurrentCallArg(THttpCallArg *arg)
set current http arguments, which then used in different process methods For instance,...
Bool_t RegisterObject(const char *subfolder, TObject *obj)
Register object in subfolder structure subfolder parameter can have many levels like:
Bool_t IsReadOnly() const
Returns readonly mode.
Bool_t UnregisterObject(TObject *obj)
unregister (remove) object from folders structures folder itself will remain even when it will be emp...
Bool_t CreateItem(const char *fullname, const char *title)
create item element
virtual Bool_t IsStreamerInfoItem(const char *)
void CreateOwnTopFolder()
Create own TFolder structures independent from gROOT This allows to have many independent TRootSniffe...
void Restrict(const char *path, const char *options)
Restrict access to the specified location.
void SetReadOnly(Bool_t on=kTRUE)
When readonly on (default), sniffer is not allowed to change ROOT structures For instance,...
void SetScanGlobalDir(Bool_t on=kTRUE)
When enabled (default), sniffer scans gROOT for files, canvases, histograms.
TObject * FindTObjectInHierarchy(const char *path)
Search element in hierarchy, derived from TObject.
const char * GetItemField(TFolder *parent, TObject *item, const char *name)
return field for specified item
virtual ULong_t GetStreamerInfoHash()
Bool_t SetItemField(const char *fullname, const char *name, const char *value)
set field for specified item
Bool_t RegisterCommand(const char *cmdname, const char *method, const char *icon)
Register command which can be executed from web interface.
virtual void RemoveFirst()
Bool_t EndsWith(const char *pat, ECaseCompare cmp=kExact) const
Return true if string ends with the specified string.
const char * Data() const
TString & ReplaceAll(const TString &s1, const TString &s2)
void Resize(Ssiz_t n)
Resize the string. Truncate or add blanks as necessary.
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
TString & Remove(Ssiz_t pos)
TString & Append(const char *cs)
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
virtual Bool_t ExpandPathName(TString &path)
Expand a pathname getting rid of special shell characters like ~.
virtual const char * Getenv(const char *env)
Get environment variable.
static Long_t SelfId()
Static method returning the id for the current thread.
Handles synchronous and a-synchronous timer events.
This class represents a WWW compatible URL.
Int_t GetIntValueFromOptions(const char *key) const
Return a value for a given key from the URL options as an Int_t, a missing key returns -1.
void SetOptions(const char *opt)
void ParseOptions() const
Parse URL options into a key/value map.
Bool_t HasOption(const char *key) const
Returns true if the given key appears in the URL options list.
RooCmdArg Restrict(const char *catName, const char *stateNameList)