22#include "RConfigure.h"
51class THttpTimer :
public TTimer {
143 jsrootsys =
gEnv->
GetValue(
"HttpServ.JSRootPath", jsrootsys);
145 if (jsrootsys && *jsrootsys) {
146 if ((strncmp(jsrootsys,
"http://", 7)==0) || (strncmp(jsrootsys,
"https://", 8)==0))
155 ::Warning(
"THttpServer::THttpServer",
"problems resolving '%s', set JSROOTSYS to proper JavaScript ROOT location",
171 if (strstr(engine,
"basic_sniffer")) {
176 sniff = (
TRootSniffer *)
gROOT->ProcessLineSync(
"new TRootSnifferFull(\"sniff\");");
184 if (strchr(engine,
';') == 0) {
191 if ((strcmp(opt,
"readonly") == 0) || (strcmp(opt,
"ro") == 0)) {
193 }
else if ((strcmp(opt,
"readwrite") == 0) || (strcmp(opt,
"rw") == 0)) {
195 }
else if (strcmp(opt,
"global") == 0) {
197 }
else if (strcmp(opt,
"noglobal") == 0) {
199 }
else if (strncmp(opt,
"cors=", 5) == 0) {
201 }
else if (strcmp(opt,
"cors") == 0) {
221 while (
auto engine =
dynamic_cast<THttpEngine *
>(iter()))
279 if (!prefix || (*prefix == 0))
299 fJSROOT = location ? location :
"";
310 if (!filename.empty())
327 if (!filename.empty())
351 const char *arg = strchr(engine,
':');
357 clname.
Append(engine, arg - engine);
361 if ((clname.
Length() == 0) || (clname ==
"http") || (clname ==
"civetweb")) {
363 }
else if (clname ==
"https") {
365 }
else if (clname ==
"fastcgi") {
382 if (!eng->
Create(arg + 1)) {
417 Error(
"SetTimer",
"Server runs already in special thread, therefore no any timer can be created");
419 fTimer =
new THttpTimer(milliSec, mode, *
this);
443 std::thread thrd([
this] {
453 std::this_thread::sleep_for(std::chrono::milliseconds(1));
458 fThrd = std::move(thrd);
481 if (!fname || (*fname == 0))
486 while (*fname != 0) {
489 const char *next = strpbrk(fname,
"/\\");
494 if ((next == fname + 2) && (*fname ==
'.') && (*(fname + 1) ==
'.')) {
503 if ((next == fname + 1) && (*fname ==
'.')) {
530 if (!uri || (*uri == 0))
539 fname.
Remove(0, pos + (entry.first.length() - 1));
542 res = entry.second.c_str();
543 if ((fname[0] ==
'/') && (res[res.
Length() - 1] ==
'/'))
571 std::unique_lock<std::mutex> lk(
fMutex);
597 arg->NotifyCondition();
602 std::unique_lock<std::mutex> lk(
fMutex);
622 Error(
"ProcessRequests",
"Should be called only from main ROOT thread");
628 std::unique_lock<std::mutex> lk(
fMutex, std::defer_lock);
632 std::shared_ptr<THttpCallArg> arg;
635 if (!
fArgs.empty()) {
644 if (arg->fFileName ==
"root_batch_holder.js") {
659 arg->NotifyCondition();
665 while ((engine = (
THttpEngine *)iter()) !=
nullptr) {
691 auto wsptr =
FindWS(arg->GetPathName());
693 if (!wsptr || !wsptr->ProcessBatchHolder(arg)) {
695 arg->NotifyCondition();
711 if ((arg->fFileName ==
"root.websocket") || (arg->fFileName ==
"root.longpoll")) {
720 Error(
"ProcessRequest",
"Deprecated signature is used, please used std::shared_ptr<THttpCallArg>");
724 if (arg->fFileName.IsNull() || (arg->fFileName ==
"index.htm") || (arg->fFileName ==
"default.htm")) {
726 if (arg->fFileName ==
"default.htm") {
731 auto wsptr =
FindWS(arg->GetPathName());
733 auto handler = wsptr.get();
742 if (arg->fContent.find(
"file:") == 0) {
743 const char *fname = arg->fContent.c_str() + 5;
749 handler->VerifyDefaultPageContent(arg);
751 arg->CheckWSPageContent(handler);
755 if (arg->fContent.empty()) {
763 if (arg->fContent.empty()) {
768 std::string repl(
"=\"");
770 if (repl.back() !=
'/')
772 arg->ReplaceAllinContent(
"=\"jsrootsys/", repl);
775 const char *hjsontag =
"\"$$$h.json$$$\"";
778 if (arg->fContent.find(hjsontag) != std::string::npos) {
782 if (arg->fTopName.Length() > 0)
783 topname = arg->fTopName.Data();
786 arg->ReplaceAllinContent(hjsontag, h_json.
Data());
788 arg->AddNoCacheHeader();
790 if (arg->fQuery.Index(
"nozip") ==
kNPOS)
793 arg->SetContentType(
"text/html");
798 if (arg->fFileName ==
"draw.htm") {
805 const char *rootjsontag =
"\"$$$root.json$$$\"";
806 const char *hjsontag =
"\"$$$h.json$$$\"";
812 std::string repl(
"=\"");
814 if (repl.back() !=
'/')
816 arg->ReplaceAllinContent(
"=\"jsrootsys/", repl);
819 if ((arg->fQuery.Index(
"no_h_json") ==
kNPOS) && (arg->fQuery.Index(
"webcanvas") ==
kNPOS) &&
820 (arg->fContent.find(hjsontag) != std::string::npos)) {
824 if (arg->fTopName.Length() > 0)
825 topname = arg->fTopName.Data();
828 arg->ReplaceAllinContent(hjsontag, h_json.
Data());
831 if ((arg->fQuery.Index(
"no_root_json") ==
kNPOS) && (arg->fQuery.Index(
"webcanvas") ==
kNPOS) &&
832 (arg->fContent.find(rootjsontag) != std::string::npos)) {
834 if (
fSniffer->
Produce(arg->fPathName.Data(),
"root.json",
"compact=23", str))
835 arg->ReplaceAllinContent(rootjsontag, str);
837 arg->AddNoCacheHeader();
838 if (arg->fQuery.Index(
"nozip") ==
kNPOS)
840 arg->SetContentType(
"text/html");
845 if ((arg->fFileName ==
"favicon.ico") && arg->fPathName.IsNull()) {
846 arg->SetFile(
fJSROOTSYS +
"/img/RootIcon.ico");
852 arg->SetFile(filename);
857 if (!arg->fPathName.IsNull() && !arg->fFileName.IsNull()) {
858 TString wsname = arg->fPathName, fname;
859 auto pos = wsname.
First(
'/');
861 wsname = arg->fPathName;
863 wsname = arg->fPathName(0, pos);
864 fname = arg->fPathName(pos + 1, arg->fPathName.Length() - pos);
868 fname.
Append(arg->fFileName);
874 if (
ws &&
ws->CanServeFiles()) {
875 TString fdir =
ws->GetDefaultPageContent();
877 if (fdir.
Index(
"file:") == 0) {
879 auto separ = fdir.
Last(
'/');
893 filename = arg->fFileName;
901 if ((filename ==
"h.xml") || (filename ==
"get.xml")) {
903 Bool_t compact = arg->fQuery.Index(
"compact") !=
kNPOS;
907 res.
Form(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
917 if (arg->fTopName.Length() > 0)
918 topname = arg->fTopName.Data();
926 arg->SetContent(std::string(res.
Data()));
929 }
else if (filename ==
"h.json") {
933 if (arg->fTopName.Length() > 0)
934 topname = arg->fTopName.Data();
936 arg->SetContent(std::string(res.
Data()));
938 }
else if (
fSniffer->
Produce(arg->fPathName.Data(), filename.
Data(), arg->fQuery.Data(), arg->fContent)) {
952 if (filename ==
"root.bin") {
960 arg->AddNoCacheHeader();
964 arg->AddHeader(
"Access-Control-Allow-Origin",
GetCors());
1002 std::lock_guard<std::mutex> grd(
fWSMutex);
1011 std::lock_guard<std::mutex> grd(
fWSMutex);
1024 std::lock_guard<std::mutex> grd(
fWSMutex);
1026 if (strcmp(
name,
ws->GetName()) == 0)
1043 auto wsptr =
FindWS(arg->GetPathName());
1045 auto handler = wsptr.get();
1047 if (!handler && !external_thrd)
1050 if (external_thrd && (!handler || !handler->AllowMTProcess())) {
1051 std::unique_lock<std::mutex> lk(
fMutex);
1055 arg->fCond.wait(lk);
1065 if (arg->fFileName ==
"root.websocket") {
1067 process = handler->HandleWS(arg);
1068 }
else if (arg->fFileName ==
"root.longpoll") {
1070 if (arg->fQuery.BeginsWith(
"raw_connect") || arg->fQuery.BeginsWith(
"txt_connect")) {
1073 arg->SetMethod(
"WS_CONNECT");
1075 bool israw = arg->fQuery.BeginsWith(
"raw_connect");
1080 if (handler->HandleWS(arg)) {
1081 arg->SetMethod(
"WS_READY");
1083 if (handler->HandleWS(arg))
1084 arg->SetTextContent(std::string(israw ?
"txt:" :
"") + std::to_string(arg->GetWSId()));
1086 arg->TakeWSEngine();
1089 process = arg->IsText();
1095 arg->SetWSId((
UInt_t)connid);
1097 arg->SetMethod(
"WS_CLOSE");
1098 arg->SetTextContent(
"OK");
1100 arg->SetMethod(
"WS_DATA");
1103 process = handler->HandleWS(arg);
1161 return SetItemField(foldername,
"_hidden", hide ?
"true" : (
const char *)0);
1201 static const struct {
1206 {
".json", 5,
"application/json"},
1207 {
".bin", 4,
"application/x-binary"},
1208 {
".gif", 4,
"image/gif"},
1209 {
".jpg", 4,
"image/jpeg"},
1210 {
".png", 4,
"image/png"},
1211 {
".html", 5,
"text/html"},
1212 {
".htm", 4,
"text/html"},
1213 {
".shtm", 5,
"text/html"},
1214 {
".shtml", 6,
"text/html"},
1215 {
".css", 4,
"text/css"},
1216 {
".js", 3,
"application/x-javascript"},
1217 {
".ico", 4,
"image/x-icon"},
1218 {
".jpeg", 5,
"image/jpeg"},
1219 {
".svg", 4,
"image/svg+xml"},
1220 {
".txt", 4,
"text/plain"},
1221 {
".torrent", 8,
"application/x-bittorrent"},
1222 {
".wav", 4,
"audio/x-wav"},
1223 {
".mp3", 4,
"audio/x-mp3"},
1224 {
".mid", 4,
"audio/mid"},
1225 {
".m3u", 4,
"audio/x-mpegurl"},
1226 {
".ogg", 4,
"application/ogg"},
1227 {
".ram", 4,
"audio/x-pn-realaudio"},
1228 {
".xslt", 5,
"application/xml"},
1229 {
".xsl", 4,
"application/xml"},
1230 {
".ra", 3,
"audio/x-pn-realaudio"},
1231 {
".doc", 4,
"application/msword"},
1232 {
".exe", 4,
"application/octet-stream"},
1233 {
".zip", 4,
"application/x-zip-compressed"},
1234 {
".xls", 4,
"application/excel"},
1235 {
".tgz", 4,
"application/x-tar-gz"},
1236 {
".tar", 4,
"application/x-tar"},
1237 {
".gz", 3,
"application/x-gunzip"},
1238 {
".arj", 4,
"application/x-arj-compressed"},
1239 {
".rar", 4,
"application/x-arj-compressed"},
1240 {
".rtf", 4,
"application/rtf"},
1241 {
".pdf", 4,
"application/pdf"},
1242 {
".swf", 4,
"application/x-shockwave-flash"},
1243 {
".mpg", 4,
"video/mpeg"},
1244 {
".webm", 5,
"video/webm"},
1245 {
".mpeg", 5,
"video/mpeg"},
1246 {
".mov", 4,
"video/quicktime"},
1247 {
".mp4", 4,
"video/mp4"},
1248 {
".m4v", 4,
"video/x-m4v"},
1249 {
".asf", 4,
"video/x-ms-asf"},
1250 {
".avi", 4,
"video/x-msvideo"},
1251 {
".bmp", 4,
"image/bmp"},
1252 {
".ttf", 4,
"application/x-font-ttf"},
1255 int path_len = strlen(path);
1266 return "text/plain";
1276 std::ifstream is(filename, std::ios::in | std::ios::binary);
1280 is.seekg(0, is.end);
1282 is.seekg(0, is.beg);
1284 char *buf = (
char *)
malloc(len);
1300 std::ifstream is(filename, std::ios::in | std::ios::binary);
1303 is.seekg(0, std::ios::end);
1304 res.resize(is.tellg());
1305 is.seekg(0, std::ios::beg);
1306 is.read((
char *)res.data(), res.length());
char * Form(const char *fmt,...)
R__EXTERN TSystem * gSystem
static const struct @137 builtin_mime_types[]
TClass instances represent classes, structs and namespaces in the ROOT type system.
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
void Set404()
mark reply as 404 error - page/request not exists or refused
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...
std::shared_ptr< THttpWSHandler > FindWS(const char *name)
Find web-socket handler with given name.
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 * GetItemField(const char *fullname, const char *name)
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.
Int_t ProcessRequests()
Process submitted requests, must be called from appropriate thread.
Bool_t ExecuteWS(std::shared_ptr< THttpCallArg > &arg, Bool_t external_thrd=kFALSE, Bool_t wait_process=kFALSE)
Execute WS request.
void RegisterWS(std::shared_ptr< THttpWSHandler > ws)
Register WS handler.
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...
Bool_t CreateItem(const char *fullname, const char *title)
Bool_t ExecuteHttp(std::shared_ptr< THttpCallArg > arg)
Execute HTTP request.
Bool_t Hide(const char *fullname, Bool_t hide=kTRUE)
hides folder or element from web gui
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
Bool_t SubmitHttp(std::shared_ptr< THttpCallArg > arg, Bool_t can_run_immediately=kFALSE)
Submit HTTP request.
Long_t fMainThrdId
! id of the thread for processing requests
TString fJSROOTSYS
! location of local JSROOT files
Bool_t Register(const char *subfolder, TObject *obj)
Register object in subfolder.
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.
static char * ReadFileContent(const char *filename, Int_t &len)
Reads content of file from the disk.
Bool_t fOldProcessSignature
! flag used to detect usage of old signature of Process() method
void CreateServerThread()
Creates special thread to process all requests, directed to http server.
std::string fDrawPageCont
! content of draw html page
Bool_t Unregister(TObject *obj)
Unregister object.
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...
Bool_t SetIcon(const char *fullname, const char *iconname)
set name of icon, used in browser together with the item
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 ...
Bool_t SetItemField(const char *fullname, const char *name, const char *value)
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
void UnregisterWS(std::shared_ptr< THttpWSHandler > ws)
Unregister WS handler.
static const char * GetMimeType(const char *path)
Guess mime type base on file extension.
TRootSniffer * GetSniffer() const
returns pointer on objects sniffer
Bool_t RegisterCommand(const char *cmdname, const char *method, const char *icon=0)
Register command which can be executed from web interface.
Bool_t fTerminated
! termination flag, disables all requests processing
void Restrict(const char *path, const char *options)
Restrict access to specified object.
virtual TString GetDefaultPageContent()
Provides content of default web page for registered web-socket handler Can be content of HTML page or...
virtual void Add(TObject *obj)
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
The TNamed class is the base class for all named ROOT classes.
Int_t GetLast() const
Return index of last object in array.
TObject * At(Int_t idx) 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 & GetDataDir()
Get the data 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 *)
Bool_t Produce(const std::string &path, const std::string &file, const std::string &options, std::string &res)
Method produce different kind of data out of object Parameter 'path' specifies object or object membe...
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.
Bool_t EndsWith(const char *pat, ECaseCompare cmp=kExact) const
Return true if string ends with the specified string.
Ssiz_t First(char c) const
Find first occurrence of a character c.
const char * Data() const
void Resize(Ssiz_t n)
Resize the string. Truncate or add blanks as necessary.
Ssiz_t Last(char c) const
Find last occurrence of a character c.
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.