23#include "RConfigure.h"
52class THttpTimer :
public TTimer {
144 jsrootsys =
gEnv->
GetValue(
"HttpServ.JSRootPath", jsrootsys);
146 if (jsrootsys && *jsrootsys) {
147 if ((strncmp(jsrootsys,
"http://", 7)==0) || (strncmp(jsrootsys,
"https://", 8)==0))
156 ::Warning(
"THttpServer::THttpServer",
"problems resolving '%s', set JSROOTSYS to proper JavaScript ROOT location",
172 if (strstr(engine,
"basic_sniffer")) {
177 sniff = (
TRootSniffer *)
gROOT->ProcessLineSync(
"new TRootSnifferFull(\"sniff\");");
185 if (strchr(engine,
';') == 0) {
192 if ((strcmp(opt,
"readonly") == 0) || (strcmp(opt,
"ro") == 0)) {
194 }
else if ((strcmp(opt,
"readwrite") == 0) || (strcmp(opt,
"rw") == 0)) {
196 }
else if (strcmp(opt,
"global") == 0) {
198 }
else if (strcmp(opt,
"noglobal") == 0) {
200 }
else if (strncmp(opt,
"cors=", 5) == 0) {
202 }
else if (strcmp(opt,
"cors") == 0) {
222 while (
auto engine =
dynamic_cast<THttpEngine *
>(iter()))
280 if (!prefix || (*prefix == 0))
300 fJSROOT = location ? location :
"";
311 if (!filename.empty())
328 if (!filename.empty())
352 const char *arg = strchr(engine,
':');
358 clname.
Append(engine, arg - engine);
362 if ((clname.
Length() == 0) || (clname ==
"http") || (clname ==
"civetweb")) {
364 }
else if (clname ==
"https") {
366 }
else if (clname ==
"fastcgi") {
383 if (!eng->
Create(arg + 1)) {
418 Error(
"SetTimer",
"Server runs already in special thread, therefore no any timer can be created");
420 fTimer =
new THttpTimer(milliSec, mode, *
this);
444 std::thread thrd([
this] {
454 std::this_thread::sleep_for(std::chrono::milliseconds(1));
459 fThrd = std::move(thrd);
482 if (!fname || (*fname == 0))
487 while (*fname != 0) {
490 const char *next = strpbrk(fname,
"/\\");
495 if ((next == fname + 2) && (*fname ==
'.') && (*(fname + 1) ==
'.')) {
504 if ((next == fname + 1) && (*fname ==
'.')) {
531 if (!uri || (*uri == 0))
540 fname.
Remove(0, pos + (entry.first.length() - 1));
543 res = entry.second.c_str();
544 if ((fname[0] ==
'/') && (res[res.
Length() - 1] ==
'/'))
572 std::unique_lock<std::mutex> lk(
fMutex);
598 arg->NotifyCondition();
603 std::unique_lock<std::mutex> lk(
fMutex);
623 Error(
"ProcessRequests",
"Should be called only from main ROOT thread");
629 std::unique_lock<std::mutex> lk(
fMutex, std::defer_lock);
633 std::shared_ptr<THttpCallArg> arg;
636 if (!
fArgs.empty()) {
645 if (arg->fFileName ==
"root_batch_holder.js") {
660 arg->NotifyCondition();
666 while ((engine = (
THttpEngine *)iter()) !=
nullptr) {
692 auto wsptr =
FindWS(arg->GetPathName());
694 if (!wsptr || !wsptr->ProcessBatchHolder(arg)) {
696 arg->NotifyCondition();
709 }
else if ((arg->fFileName ==
"root.websocket") || (arg->fFileName ==
"root.longpoll")) {
738 auto handler = wsptr.get();
745 arg->
fContent = handler->GetDefaultPageContent().Data();
747 if (arg->
fContent.find(
"file:") == 0) {
748 const char *fname = arg->
fContent.c_str() + 5;
772 std::string repl(
"=\"");
774 if (repl.back() !=
'/')
779 const char *hjsontag =
"\"$$$h.json$$$\"";
782 if (arg->
fContent.find(hjsontag) != std::string::npos) {
809 const char *rootjsontag =
"\"$$$root.json$$$\"";
810 const char *hjsontag =
"\"$$$h.json$$$\"";
816 std::string repl(
"=\"");
818 if (repl.back() !=
'/')
824 (arg->
fContent.find(hjsontag) != std::string::npos)) {
836 (arg->
fContent.find(rootjsontag) != std::string::npos)) {
863 auto pos = wsname.
First(
'/');
878 if (
ws &&
ws->CanServeFiles()) {
879 TString fdir =
ws->GetDefaultPageContent();
881 if (fdir.
Index(
"file:") == 0) {
883 auto separ = fdir.
Last(
'/');
905 if ((filename ==
"h.xml") || (filename ==
"get.xml")) {
911 res.
Form(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
933 }
else if (filename ==
"h.json") {
956 if (filename ==
"root.bin") {
998 std::lock_guard<std::mutex> grd(
fWSMutex);
1007 std::lock_guard<std::mutex> grd(
fWSMutex);
1020 std::lock_guard<std::mutex> grd(
fWSMutex);
1022 if (strcmp(
name,
ws->GetName()) == 0)
1039 auto wsptr =
FindWS(arg->GetPathName());
1041 auto handler = wsptr.get();
1043 if (!handler && !external_thrd)
1046 if (external_thrd && (!handler || !handler->AllowMTProcess())) {
1047 std::unique_lock<std::mutex> lk(
fMutex);
1051 arg->fCond.wait(lk);
1061 if (arg->fFileName ==
"root.websocket") {
1063 process = handler->HandleWS(arg);
1064 }
else if (arg->fFileName ==
"root.longpoll") {
1066 if (arg->fQuery.BeginsWith(
"raw_connect") || arg->fQuery.BeginsWith(
"txt_connect")) {
1069 arg->SetMethod(
"WS_CONNECT");
1071 bool israw = arg->fQuery.BeginsWith(
"raw_connect");
1076 if (handler->HandleWS(arg)) {
1077 arg->SetMethod(
"WS_READY");
1079 if (handler->HandleWS(arg))
1080 arg->SetTextContent(std::string(israw ?
"txt:" :
"") + std::to_string(arg->GetWSId()));
1082 arg->TakeWSEngine();
1085 process = arg->IsText();
1091 arg->SetWSId((
UInt_t)connid);
1093 arg->SetMethod(
"WS_CLOSE");
1094 arg->SetTextContent(
"OK");
1096 arg->SetMethod(
"WS_DATA");
1099 process = handler->HandleWS(arg);
1157 return SetItemField(foldername,
"_hidden", hide ?
"true" : (
const char *)0);
1197 static const struct {
1202 {
".json", 5,
"application/json"},
1203 {
".bin", 4,
"application/x-binary"},
1204 {
".gif", 4,
"image/gif"},
1205 {
".jpg", 4,
"image/jpeg"},
1206 {
".png", 4,
"image/png"},
1207 {
".html", 5,
"text/html"},
1208 {
".htm", 4,
"text/html"},
1209 {
".shtm", 5,
"text/html"},
1210 {
".shtml", 6,
"text/html"},
1211 {
".css", 4,
"text/css"},
1212 {
".js", 3,
"application/x-javascript"},
1213 {
".ico", 4,
"image/x-icon"},
1214 {
".jpeg", 5,
"image/jpeg"},
1215 {
".svg", 4,
"image/svg+xml"},
1216 {
".txt", 4,
"text/plain"},
1217 {
".torrent", 8,
"application/x-bittorrent"},
1218 {
".wav", 4,
"audio/x-wav"},
1219 {
".mp3", 4,
"audio/x-mp3"},
1220 {
".mid", 4,
"audio/mid"},
1221 {
".m3u", 4,
"audio/x-mpegurl"},
1222 {
".ogg", 4,
"application/ogg"},
1223 {
".ram", 4,
"audio/x-pn-realaudio"},
1224 {
".xslt", 5,
"application/xml"},
1225 {
".xsl", 4,
"application/xml"},
1226 {
".ra", 3,
"audio/x-pn-realaudio"},
1227 {
".doc", 4,
"application/msword"},
1228 {
".exe", 4,
"application/octet-stream"},
1229 {
".zip", 4,
"application/x-zip-compressed"},
1230 {
".xls", 4,
"application/excel"},
1231 {
".tgz", 4,
"application/x-tar-gz"},
1232 {
".tar", 4,
"application/x-tar"},
1233 {
".gz", 3,
"application/x-gunzip"},
1234 {
".arj", 4,
"application/x-arj-compressed"},
1235 {
".rar", 4,
"application/x-arj-compressed"},
1236 {
".rtf", 4,
"application/rtf"},
1237 {
".pdf", 4,
"application/pdf"},
1238 {
".swf", 4,
"application/x-shockwave-flash"},
1239 {
".mpg", 4,
"video/mpeg"},
1240 {
".webm", 5,
"video/webm"},
1241 {
".mpeg", 5,
"video/mpeg"},
1242 {
".mov", 4,
"video/quicktime"},
1243 {
".mp4", 4,
"video/mp4"},
1244 {
".m4v", 4,
"video/x-m4v"},
1245 {
".asf", 4,
"video/x-ms-asf"},
1246 {
".avi", 4,
"video/x-msvideo"},
1247 {
".bmp", 4,
"image/bmp"},
1248 {
".ttf", 4,
"application/x-font-ttf"},
1251 int path_len = strlen(path);
1262 return "text/plain";
1272 std::ifstream is(filename, std::ios::in | std::ios::binary);
1276 is.seekg(0, is.end);
1278 is.seekg(0, is.beg);
1280 char *buf = (
char *)
malloc(len);
1296 std::ifstream is(filename, std::ios::in | std::ios::binary);
1299 is.seekg(0, std::ios::end);
1300 res.resize(is.tellg());
1301 is.seekg(0, std::ios::beg);
1302 is.read((
char *)res.data(), res.length());
char * Form(const char *fmt,...)
R__EXTERN TSystem * gSystem
static const struct @139 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 SetJson()
Set content type as "application/json".
void SetFile(const char *filename=nullptr)
indicate that http request should response with file content
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...
void ReplaceAllinContent(const std::string &from, const std::string &to, bool once=false)
Replace all occurrences of.
TString fPathName
! item path
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
std::string fContent
! content - text or binary
void SetContentType(const char *typ)
set content type like "text/xml" or "application/json"
virtual void CheckWSPageContent(THttpWSHandler *)
Method used to modify content of web page used by web socket handler.
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...
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.
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 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.