ROOT  6.07/01
Reference Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
THttpServer.cxx
Go to the documentation of this file.
1 // $Id$
2 // Author: Sergey Linev 21/12/2013
3 
4 #include "THttpServer.h"
5 
6 #include "TThread.h"
7 #include "TTimer.h"
8 #include "TSystem.h"
9 #include "TImage.h"
10 #include "TROOT.h"
11 #include "TClass.h"
12 #include "TFolder.h"
13 #include "RVersion.h"
14 #include "RConfigure.h"
15 
16 #include "THttpEngine.h"
17 #include "TRootSniffer.h"
18 #include "TRootSnifferStore.h"
19 
20 #include <string>
21 #include <cstdlib>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <fstream>
25 
26 
27 //////////////////////////////////////////////////////////////////////////
28 // //
29 // THttpTimer //
30 // //
31 // Specialized timer for THttpServer //
32 // Provides regular call of THttpServer::ProcessRequests() method //
33 // //
34 //////////////////////////////////////////////////////////////////////////
35 
36 
37 ////////////////////////////////////////////////////////////////////////////////
38 
39 class THttpTimer : public TTimer {
40 public:
41 
42  THttpServer *fServer; //!
43 
44  THttpTimer(Long_t milliSec, Bool_t mode, THttpServer *serv) :
45  TTimer(milliSec, mode), fServer(serv)
46  {
47  // construtor
48  }
49  virtual ~THttpTimer()
50  {
51  // destructor
52  }
53  virtual void Timeout()
54  {
55  // timeout handler
56  // used to process http requests in main ROOT thread
57 
58  if (fServer) fServer->ProcessRequests();
59  }
60 };
61 
62 // =======================================================
63 
64 //////////////////////////////////////////////////////////////////////////
65 // //
66 // THttpServer //
67 // //
68 // Online http server for arbitrary ROOT application //
69 // //
70 // Idea of THttpServer - provide remote http access to running //
71 // ROOT application and enable HTML/JavaScript user interface. //
72 // Any registered object can be requested and displayed in the browser. //
73 // There are many benefits of such approach: //
74 // * standard http interface to ROOT application //
75 // * no any temporary ROOT files when access data //
76 // * user interface running in all browsers //
77 // //
78 // Starting HTTP server //
79 // //
80 // To start http server, at any time create instance //
81 // of the THttpServer class like: //
82 // serv = new THttpServer("http:8080"); //
83 // //
84 // This will starts civetweb-based http server with http port 8080. //
85 // Than one should be able to open address "http://localhost:8080" //
86 // in any modern browser (IE, Firefox, Chrome) and browse objects, //
87 // created in application. By default, server can access files, //
88 // canvases and histograms via gROOT pointer. All such objects //
89 // can be displayed with JSROOT graphics. //
90 // //
91 // At any time one could register other objects with the command: //
92 // //
93 // TGraph* gr = new TGraph(10); //
94 // gr->SetName("gr1"); //
95 // serv->Register("graphs/subfolder", gr); //
96 // //
97 // If objects content is changing in the application, one could //
98 // enable monitoring flag in the browser - than objects view //
99 // will be regularly updated. //
100 // //
101 // More information: http://root.cern.ch/drupal/content/users-guide //
102 // //
103 //////////////////////////////////////////////////////////////////////////
104 
106 
107 ////////////////////////////////////////////////////////////////////////////////
108 /// constructor
109 
110 THttpServer::THttpServer(const char *engine) :
111  TNamed("http", "ROOT http server"),
112  fEngines(),
113  fTimer(0),
114  fSniffer(0),
115  fMainThrdId(0),
116  fJSROOTSYS(),
117  fTopName("ROOT"),
118  fJSROOT(),
119  fLocations(),
120  fDefaultPage(),
121  fDefaultPageCont(),
122  fDrawPage(),
123  fDrawPageCont(),
124  fCallArgs()
125 {
126  // As argument, one specifies engine kind which should be
127  // created like "http:8080". One could specify several engines
128  // at once, separating them with ; like "http:8080;fastcgi:9000"
129  // One also can configure readonly flag for sniffer like
130  // "http:8080;readonly" or "http:8080;readwrite"
131  //
132  // Also searches for JavaScript ROOT sources, which are used in web clients
133  // Typically JSROOT sources located in $ROOTSYS/etc/http directory,
134  // but one could set JSROOTSYS variable to specify alternative location
135 
136  fLocations.SetOwner(kTRUE);
137 
138  // Info("THttpServer", "Create %p in thrd %ld", this, (long) fMainThrdId);
139 
140 #ifdef COMPILED_WITH_DABC
141  const char *dabcsys = gSystem->Getenv("DABCSYS");
142  if (dabcsys != 0)
143  fJSROOTSYS = TString::Format("%s/plugins/root/js", dabcsys);
144 #endif
145 
146  const char *jsrootsys = gSystem->Getenv("JSROOTSYS");
147  if (jsrootsys != 0) fJSROOTSYS = jsrootsys;
148 
149  if (fJSROOTSYS.Length() == 0) {
150 #ifdef ROOTETCDIR
151  TString jsdir = TString::Format("%s/http", ROOTETCDIR);
152 #else
153  TString jsdir("$(ROOTSYS)/etc/http");
154 #endif
155  if (gSystem->ExpandPathName(jsdir)) {
156  Warning("THttpServer", "problems resolving '%s', use JSROOTSYS to specify $ROOTSYS/etc/http location", jsdir.Data());
157  fJSROOTSYS = ".";
158  } else {
159  fJSROOTSYS = jsdir;
160  }
161  }
162 
163  AddLocation("currentdir/", ".");
164  AddLocation("jsrootsys/", fJSROOTSYS);
165 
166  const char *rootsys = gSystem->Getenv("ROOTSYS");
167  if (rootsys != 0) {
168  AddLocation("rootsys/", rootsys);
169  } else {
170 #ifdef ROOTPREFIX
171  TString sysdir = ROOTPREFIX;
172 #else
173  TString sysdir = "$(ROOTSYS)";
174 #endif
175  if (!gSystem->ExpandPathName(sysdir)) AddLocation("rootsys/", sysdir);
176  }
177 
178  fDefaultPage = fJSROOTSYS + "/files/online.htm";
179  fDrawPage = fJSROOTSYS + "/files/draw.htm";
180 
181  SetSniffer(new TRootSniffer("sniff"));
182 
183  // start timer
184  SetTimer(20, kTRUE);
185 
186  if (strchr(engine, ';') == 0) {
187  CreateEngine(engine);
188  } else {
189  TObjArray *lst = TString(engine).Tokenize(";");
190 
191  for (Int_t n = 0; n <= lst->GetLast(); n++) {
192  const char *opt = lst->At(n)->GetName();
193  if ((strcmp(opt, "readonly") == 0) || (strcmp(opt, "ro") == 0)) {
194  GetSniffer()->SetReadOnly(kTRUE);
195  } else if ((strcmp(opt, "readwrite") == 0) || (strcmp(opt, "rw") == 0)) {
196  GetSniffer()->SetReadOnly(kFALSE);
197  } else
198  CreateEngine(opt);
199  }
200 
201  delete lst;
202  }
203 }
204 
205 ////////////////////////////////////////////////////////////////////////////////
206 /// destructor
207 /// delete all http engines and sniffer
208 
210 {
211  fEngines.Delete();
212 
213  SetSniffer(0);
214 
215  SetTimer(0);
216 }
217 
218 ////////////////////////////////////////////////////////////////////////////////
219 /// Set TRootSniffer to the server
220 /// Server takes ownership over sniffer
221 
223 {
224  if (fSniffer) delete fSniffer;
225  fSniffer = sniff;
226 }
227 
228 ////////////////////////////////////////////////////////////////////////////////
229 /// returns read-only mode
230 
232 {
233  return fSniffer ? fSniffer->IsReadOnly() : kTRUE;
234 }
235 
236 ////////////////////////////////////////////////////////////////////////////////
237 /// Set read-only mode for the server (default on)
238 /// In read-only server is not allowed to change any ROOT object, registered to the server
239 /// Server also cannot execute objects method via exe.json request
240 
242 {
243  if (fSniffer) fSniffer->SetReadOnly(readonly);
244 }
245 
246 ////////////////////////////////////////////////////////////////////////////////
247 /// add files location, which could be used in the server
248 /// one could map some system folder to the server like AddLocation("mydir/","/home/user/specials");
249 /// Than files from this directory could be addressed via server like
250 /// http://localhost:8080/mydir/myfile.root
251 
252 void THttpServer::AddLocation(const char *prefix, const char *path)
253 {
254  if ((prefix==0) || (*prefix==0)) return;
255 
256  TNamed *obj = dynamic_cast<TNamed*> (fLocations.FindObject(prefix));
257  if (obj != 0) {
258  obj->SetTitle(path);
259  } else {
260  fLocations.Add(new TNamed(prefix, path));
261  }
262 }
263 
264 ////////////////////////////////////////////////////////////////////////////////
265 /// Set location of JSROOT to use with the server
266 /// One could specify address like:
267 /// https://root.cern.ch/js/3.3/
268 /// http://web-docs.gsi.de/~linev/js/3.3/
269 /// This allows to get new JSROOT features with old server,
270 /// reduce load on THttpServer instance, also startup time can be improved
271 /// When empty string specified (default), local copy of JSROOT is used (distributed with ROOT)
272 
273 void THttpServer::SetJSROOT(const char* location)
274 {
275  fJSROOT = location ? location : "";
276 }
277 
278 ////////////////////////////////////////////////////////////////////////////////
279 /// Set file name of HTML page, delivered by the server when
280 /// http address is opened in the browser.
281 /// By default, $ROOTSYS/etc/http/files/online.htm page is used
282 /// When empty filename is specified, default page will be used
283 
285 {
286  if ((filename!=0) && (*filename!=0))
288  else
289  fDefaultPage = fJSROOTSYS + "/files/online.htm";
290 
291  // force to read page content next time again
293 }
294 
295 ////////////////////////////////////////////////////////////////////////////////
296 /// Set file name of HTML page, delivered by the server when
297 /// objects drawing page is requested from the browser
298 /// By default, $ROOTSYS/etc/http/files/draw.htm page is used
299 /// When empty filename is specified, default page will be used
300 
302 {
303  if ((filename!=0) && (*filename!=0))
305  else
306  fDrawPage = fJSROOTSYS + "/files/draw.htm";
307 
308  // force to read page content next time again
310 }
311 
312 ////////////////////////////////////////////////////////////////////////////////
313 /// factory method to create different http engines
314 /// At the moment two engine kinds are supported:
315 /// civetweb (default) and fastcgi
316 /// Examples:
317 /// "civetweb:8080" or "http:8080" or ":8080" - creates civetweb web server with http port 8080
318 /// "fastcgi:9000" - creates fastcgi server with port 9000
319 /// "dabc:1237" - create DABC server with port 1237 (only available with DABC installed)
320 /// "dabc:master_host:port" - attach to DABC master, running on master_host:port (only available with DABC installed)
321 
323 {
324  if (engine == 0) return kFALSE;
325 
326  const char *arg = strchr(engine, ':');
327  if (arg == 0) return kFALSE;
328 
329  TString clname;
330  if (arg != engine) clname.Append(engine, arg - engine);
331 
332  if ((clname.Length() == 0) || (clname == "http") || (clname == "civetweb"))
333  clname = "TCivetweb";
334  else if (clname == "fastcgi")
335  clname = "TFastCgi";
336  else if (clname == "dabc")
337  clname = "TDabcEngine";
338 
339  // ensure that required engine class exists before we try to create it
340  TClass *engine_class = gROOT->LoadClass(clname.Data());
341  if (engine_class == 0) return kFALSE;
342 
343  THttpEngine *eng = (THttpEngine *) engine_class->New();
344  if (eng == 0) return kFALSE;
345 
346  eng->SetServer(this);
347 
348  if (!eng->Create(arg + 1)) {
349  delete eng;
350  return kFALSE;
351  }
352 
353  fEngines.Add(eng);
354 
355  return kTRUE;
356 }
357 
358 ////////////////////////////////////////////////////////////////////////////////
359 /// create timer which will invoke ProcessRequests() function periodically
360 /// Timer is required to perform all actions in main ROOT thread
361 /// Method arguments are the same as for TTimer constructor
362 /// By default, sync timer with 100 ms period is created
363 ///
364 /// If milliSec == 0, no timer will be created.
365 /// In this case application should regularly call ProcessRequests() method.
366 
367 void THttpServer::SetTimer(Long_t milliSec, Bool_t mode)
368 {
369  if (fTimer) {
370  fTimer->Stop();
371  delete fTimer;
372  fTimer = 0;
373  }
374  if (milliSec > 0) {
375  fTimer = new THttpTimer(milliSec, mode, this);
376  fTimer->TurnOn();
377  }
378 }
379 
380 ////////////////////////////////////////////////////////////////////////////////
381 /// Checked that filename does not contains relative path below current directory
382 /// Used to prevent access to files below current directory
383 
385 {
386  if ((fname == 0) || (*fname == 0)) return kFALSE;
387 
388  Int_t level = 0;
389 
390  while (*fname != 0) {
391 
392  // find next slash or backslash
393  const char *next = strpbrk(fname, "/\\");
394  if (next == 0) return kTRUE;
395 
396  // most important - change to parent dir
397  if ((next == fname + 2) && (*fname == '.') && (*(fname + 1) == '.')) {
398  fname += 3;
399  level--;
400  if (level < 0) return kFALSE;
401  continue;
402  }
403 
404  // ignore current directory
405  if ((next == fname + 1) && (*fname == '.')) {
406  fname += 2;
407  continue;
408  }
409 
410  // ignore slash at the front
411  if (next == fname) {
412  fname ++;
413  continue;
414  }
415 
416  fname = next + 1;
417  level++;
418  }
419 
420  return kTRUE;
421 }
422 
423 ////////////////////////////////////////////////////////////////////////////////
424 /// Verifies that request is just file name
425 /// File names typically contains prefix like "jsrootsys/"
426 /// If true, method returns real name of the file,
427 /// which should be delivered to the client
428 /// Method is thread safe and can be called from any thread
429 
430 Bool_t THttpServer::IsFileRequested(const char *uri, TString &res) const
431 {
432  if ((uri == 0) || (strlen(uri) == 0)) return kFALSE;
433 
434  TString fname = uri;
435 
437  TObject *obj(0);
438  while ((obj=iter()) != 0) {
439  Ssiz_t pos = fname.Index(obj->GetName());
440  if (pos == kNPOS) continue;
441  fname.Remove(0, pos + (strlen(obj->GetName()) - 1));
442  if (!VerifyFilePath(fname.Data())) return kFALSE;
443  res = obj->GetTitle();
444  if ((fname[0]=='/') && (res[res.Length()-1]=='/')) res.Resize(res.Length()-1);
445  res.Append(fname);
446  return kTRUE;
447  }
448 
449  return kFALSE;
450 }
451 
452 ////////////////////////////////////////////////////////////////////////////////
453 /// Executes http request, specified in THttpCallArg structure
454 /// Method can be called from any thread
455 /// Actual execution will be done in main ROOT thread, where analysis code is running.
456 
458 {
459  if ((fMainThrdId!=0) && (fMainThrdId == TThread::SelfId())) {
460  // should not happen, but one could process requests directly without any signaling
461 
462  ProcessRequest(arg);
463 
464  return kTRUE;
465  }
466 
467  // add call arg to the list
468  std::unique_lock<std::mutex> lk(fMutex);
469  fCallArgs.Add(arg);
470  // and now wait until request is processed
471  arg->fCond.wait(lk);
472 
473  return kTRUE;
474 }
475 
476 ////////////////////////////////////////////////////////////////////////////////
477 /// Process requests, submitted for execution
478 /// Regularly invoked by THttpTimer, when somewhere in the code
479 /// gSystem->ProcessEvents() is called.
480 /// User can call serv->ProcessRequests() directly, but only from main analysis thread.
481 
483 {
485 
486  if (fMainThrdId != TThread::SelfId()) {
487  Error("ProcessRequests", "Should be called only from main ROOT thread");
488  return;
489  }
490 
491  std::unique_lock<std::mutex> lk(fMutex, std::defer_lock);
492  while (true) {
493  THttpCallArg *arg = 0;
494 
495  lk.lock();
496  if (fCallArgs.GetSize() > 0) {
497  arg = (THttpCallArg *) fCallArgs.First();
499  }
500  lk.unlock();
501 
502  if (arg == 0) break;
503 
505 
506  try {
507  ProcessRequest(arg);
509  } catch (...) {
511  }
512 
513  arg->fCond.notify_one();
514  }
515 
516  // regularly call Process() method of engine to let perform actions in ROOT context
517  TIter iter(&fEngines);
518  THttpEngine *engine = 0;
519  while ((engine = (THttpEngine *)iter()) != 0)
520  engine->Process();
521 }
522 
523 ////////////////////////////////////////////////////////////////////////////////
524 /// Process single http request
525 /// Depending from requested path and filename different actions will be performed.
526 /// In most cases information is provided by TRootSniffer class
527 
529 {
530 
531  if (arg->fFileName.IsNull() || (arg->fFileName == "index.htm")) {
532 
533  if (fDefaultPageCont.Length() == 0) {
534  Int_t len = 0;
535  char *buf = ReadFileContent(fDefaultPage.Data(), len);
536  if (len > 0) fDefaultPageCont.Append(buf, len);
537  delete buf;
538  }
539 
540  if (fDefaultPageCont.Length() == 0) {
541  arg->Set404();
542  } else {
543  arg->fContent = fDefaultPageCont;
544 
545  // replace all references on JSROOT
546  if (fJSROOT.Length() > 0) {
547  TString repl = TString("=\"") + fJSROOT;
548  if (!repl.EndsWith("/")) repl+="/";
549  arg->fContent.ReplaceAll("=\"jsrootsys/", repl);
550  }
551 
552  const char *hjsontag = "\"$$$h.json$$$\"";
553 
554  // add h.json caching
555  if (arg->fContent.Index(hjsontag) != kNPOS) {
556  TString h_json;
557  TRootSnifferStoreJson store(h_json, kTRUE);
558  const char *topname = fTopName.Data();
559  if (arg->fTopName.Length() > 0) topname = arg->fTopName.Data();
560  fSniffer->ScanHierarchy(topname, arg->fPathName.Data(), &store);
561 
562  arg->fContent.ReplaceAll(hjsontag, h_json);
563 
564  arg->AddHeader("Cache-Control", "private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0");
565  if (arg->fQuery.Index("nozip") == kNPOS) arg->SetZipping(2);
566  }
567  arg->SetContentType("text/html");
568  }
569  return;
570  }
571 
572  if (arg->fFileName == "draw.htm") {
573  if (fDrawPageCont.Length() == 0) {
574  Int_t len = 0;
575  char *buf = ReadFileContent(fDrawPage.Data(), len);
576  if (len > 0) fDrawPageCont.Append(buf, len);
577  delete buf;
578  }
579 
580  if (fDrawPageCont.Length() == 0) {
581  arg->Set404();
582  } else {
583  const char *rootjsontag = "\"$$$root.json$$$\"";
584  const char *hjsontag = "\"$$$h.json$$$\"";
585 
586  arg->fContent = fDrawPageCont;
587 
588  // replace all references on JSROOT
589  if (fJSROOT.Length() > 0) {
590  TString repl = TString("=\"") + fJSROOT;
591  if (!repl.EndsWith("/")) repl+="/";
592  arg->fContent.ReplaceAll("=\"jsrootsys/", repl);
593  }
594 
595  if (arg->fContent.Index(hjsontag) != kNPOS) {
596  TString h_json;
597  TRootSnifferStoreJson store(h_json, kTRUE);
598  const char *topname = fTopName.Data();
599  if (arg->fTopName.Length() > 0) topname = arg->fTopName.Data();
600  fSniffer->ScanHierarchy(topname, arg->fPathName.Data(), &store, kTRUE);
601 
602  arg->fContent.ReplaceAll(hjsontag, h_json);
603  }
604 
605  if (arg->fContent.Index(rootjsontag) != kNPOS) {
606  TString str;
607  void *bindata = 0;
608  Long_t bindatalen = 0;
609  if (fSniffer->Produce(arg->fPathName.Data(), "root.json", "compact=3", bindata, bindatalen, str)) {
610  arg->fContent.ReplaceAll(rootjsontag, str);
611  }
612  }
613  arg->AddHeader("Cache-Control", "private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0");
614  if (arg->fQuery.Index("nozip") == kNPOS) arg->SetZipping(2);
615  arg->SetContentType("text/html");
616  }
617  return;
618  }
619 
621  if (IsFileRequested(arg->fFileName.Data(), filename)) {
622  arg->SetFile(filename);
623  return;
624  }
625 
626  filename = arg->fFileName;
627  Bool_t iszip = kFALSE;
628  if (filename.EndsWith(".gz")) {
629  filename.Resize(filename.Length() - 3);
630  iszip = kTRUE;
631  }
632 
633  void* bindata(0);
634  Long_t bindatalen(0);
635 
636  if ((filename == "h.xml") || (filename == "get.xml")) {
637 
638  Bool_t compact = arg->fQuery.Index("compact") != kNPOS;
639 
640  arg->fContent.Form("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
641  if (!compact) arg->fContent.Append("\n");
642  arg->fContent.Append("<root>");
643  if (!compact) arg->fContent.Append("\n");
644  {
645  TRootSnifferStoreXml store(arg->fContent, compact);
646 
647  const char *topname = fTopName.Data();
648  if (arg->fTopName.Length() > 0) topname = arg->fTopName.Data();
649  fSniffer->ScanHierarchy(topname, arg->fPathName.Data(), &store, filename == "get.xml");
650  }
651 
652  arg->fContent.Append("</root>");
653  if (!compact) arg->fContent.Append("\n");
654 
655  arg->SetXml();
656  } else
657 
658  if (filename == "h.json") {
659  TRootSnifferStoreJson store(arg->fContent, arg->fQuery.Index("compact") != kNPOS);
660  const char *topname = fTopName.Data();
661  if (arg->fTopName.Length() > 0) topname = arg->fTopName.Data();
662  fSniffer->ScanHierarchy(topname, arg->fPathName.Data(), &store);
663  arg->SetJson();
664  } else
665 
666  if (fSniffer->Produce(arg->fPathName.Data(), filename.Data(), arg->fQuery.Data(), bindata, bindatalen, arg->fContent)) {
667  if (bindata != 0) arg->SetBinData(bindata, bindatalen);
668 
669  // define content type base on extension
670  arg->SetContentType(GetMimeType(filename.Data()));
671  } else {
672  // request is not processed
673  arg->Set404();
674  }
675 
676  if (arg->Is404()) return;
677 
678  if (iszip) arg->SetZipping(3);
679 
680  if (filename == "root.bin") {
681  // only for binary data master version is important
682  // it allows to detect if streamer info was modified
683  const char *parname = fSniffer->IsStreamerInfoItem(arg->fPathName.Data()) ? "BVersion" : "MVersion";
684  arg->AddHeader(parname, Form("%u", (unsigned) fSniffer->GetStreamerInfoHash()));
685  }
686 
687  // try to avoid caching on the browser
688  arg->AddHeader("Cache-Control", "private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0");
689 }
690 
691 ////////////////////////////////////////////////////////////////////////////////
692 /// Register object in folders hierarchy
693 ///
694 /// See TRootSniffer::RegisterObject() for more details
695 
696 Bool_t THttpServer::Register(const char *subfolder, TObject *obj)
697 {
698  return fSniffer->RegisterObject(subfolder, obj);
699 }
700 
701 ////////////////////////////////////////////////////////////////////////////////
702 /// Unregister object in folders hierarchy
703 ///
704 /// See TRootSniffer::UnregisterObject() for more details
705 
707 {
708  return fSniffer->UnregisterObject(obj);
709 }
710 
711 ////////////////////////////////////////////////////////////////////////////////
712 /// Restrict access to specified object
713 ///
714 /// See TRootSniffer::Restrict() for more details
715 
716 void THttpServer::Restrict(const char *path, const char* options)
717 {
718  fSniffer->Restrict(path, options);
719 }
720 
721 ////////////////////////////////////////////////////////////////////////////////
722 /// Register command which can be executed from web interface
723 ///
724 /// As method one typically specifies string, which is executed with
725 /// gROOT->ProcessLine() method. For instance
726 /// serv->RegisterCommand("Invoke","InvokeFunction()");
727 ///
728 /// Or one could specify any method of the object which is already registered
729 /// to the server. For instance:
730 /// serv->Register("/", hpx);
731 /// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()");
732 /// Here symbols '/->' separates item name from method to be executed
733 ///
734 /// One could specify additional arguments in the command with
735 /// syntax like %arg1%, %arg2% and so on. For example:
736 /// serv->RegisterCommand("/ResetHPX", "/hpx/->SetTitle(\"%arg1%\")");
737 /// serv->RegisterCommand("/RebinHPXPY", "/hpxpy/->Rebin2D(%arg1%,%arg2%)");
738 /// Such parameter(s) will be requested when command clicked in the browser.
739 ///
740 /// Once command is registered, one could specify icon which will appear in the browser:
741 /// serv->SetIcon("/ResetHPX", "rootsys/icons/ed_execute.png");
742 ///
743 /// One also can set extra property '_fastcmd', that command appear as
744 /// tool button on the top of the browser tree:
745 /// serv->SetItemField("/ResetHPX", "_fastcmd", "true");
746 /// Or it is equivalent to specifying extra argument when register command:
747 /// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()", "button;rootsys/icons/ed_delete.png");
748 
749 Bool_t THttpServer::RegisterCommand(const char *cmdname, const char *method, const char *icon)
750 {
751  return fSniffer->RegisterCommand(cmdname, method, icon);
752 }
753 
754 ////////////////////////////////////////////////////////////////////////////////
755 /// hides folder or element from web gui
756 
757 Bool_t THttpServer::Hide(const char *foldername, Bool_t hide)
758 {
759  return SetItemField(foldername, "_hidden", hide ? "true" : (const char *) 0);
760 }
761 
762 ////////////////////////////////////////////////////////////////////////////////
763 /// set name of icon, used in browser together with the item
764 ///
765 /// One could use images from $ROOTSYS directory like:
766 /// serv->SetIcon("/ResetHPX","/rootsys/icons/ed_execute.png");
767 
768 Bool_t THttpServer::SetIcon(const char *fullname, const char *iconname)
769 {
770  return SetItemField(fullname, "_icon", iconname);
771 }
772 
773 ////////////////////////////////////////////////////////////////////////////////
774 
775 Bool_t THttpServer::CreateItem(const char *fullname, const char *title)
776 {
777  return fSniffer->CreateItem(fullname, title);
778 }
779 
780 ////////////////////////////////////////////////////////////////////////////////
781 
782 Bool_t THttpServer::SetItemField(const char *fullname, const char *name, const char *value)
783 {
784  return fSniffer->SetItemField(fullname, name, value);
785 }
786 
787 ////////////////////////////////////////////////////////////////////////////////
788 
789 const char *THttpServer::GetItemField(const char *fullname, const char *name)
790 {
791  return fSniffer->GetItemField(fullname, name);
792 }
793 
794 ////////////////////////////////////////////////////////////////////////////////
795 /// Returns MIME type base on file extension
796 
797 const char *THttpServer::GetMimeType(const char *path)
798 {
799  static const struct {
800  const char *extension;
801  int ext_len;
802  const char *mime_type;
803  } builtin_mime_types[] = {
804  {".xml", 4, "text/xml"},
805  {".json", 5, "application/json"},
806  {".bin", 4, "application/x-binary"},
807  {".gif", 4, "image/gif"},
808  {".jpg", 4, "image/jpeg"},
809  {".png", 4, "image/png"},
810  {".html", 5, "text/html"},
811  {".htm", 4, "text/html"},
812  {".shtm", 5, "text/html"},
813  {".shtml", 6, "text/html"},
814  {".css", 4, "text/css"},
815  {".js", 3, "application/x-javascript"},
816  {".ico", 4, "image/x-icon"},
817  {".jpeg", 5, "image/jpeg"},
818  {".svg", 4, "image/svg+xml"},
819  {".txt", 4, "text/plain"},
820  {".torrent", 8, "application/x-bittorrent"},
821  {".wav", 4, "audio/x-wav"},
822  {".mp3", 4, "audio/x-mp3"},
823  {".mid", 4, "audio/mid"},
824  {".m3u", 4, "audio/x-mpegurl"},
825  {".ogg", 4, "application/ogg"},
826  {".ram", 4, "audio/x-pn-realaudio"},
827  {".xslt", 5, "application/xml"},
828  {".xsl", 4, "application/xml"},
829  {".ra", 3, "audio/x-pn-realaudio"},
830  {".doc", 4, "application/msword"},
831  {".exe", 4, "application/octet-stream"},
832  {".zip", 4, "application/x-zip-compressed"},
833  {".xls", 4, "application/excel"},
834  {".tgz", 4, "application/x-tar-gz"},
835  {".tar", 4, "application/x-tar"},
836  {".gz", 3, "application/x-gunzip"},
837  {".arj", 4, "application/x-arj-compressed"},
838  {".rar", 4, "application/x-arj-compressed"},
839  {".rtf", 4, "application/rtf"},
840  {".pdf", 4, "application/pdf"},
841  {".swf", 4, "application/x-shockwave-flash"},
842  {".mpg", 4, "video/mpeg"},
843  {".webm", 5, "video/webm"},
844  {".mpeg", 5, "video/mpeg"},
845  {".mov", 4, "video/quicktime"},
846  {".mp4", 4, "video/mp4"},
847  {".m4v", 4, "video/x-m4v"},
848  {".asf", 4, "video/x-ms-asf"},
849  {".avi", 4, "video/x-msvideo"},
850  {".bmp", 4, "image/bmp"},
851  {".ttf", 4, "application/x-font-ttf"},
852  {NULL, 0, NULL}
853  };
854 
855  int path_len = strlen(path);
856 
857  for (int i = 0; builtin_mime_types[i].extension != NULL; i++) {
858  if (path_len <= builtin_mime_types[i].ext_len) continue;
859  const char *ext = path + (path_len - builtin_mime_types[i].ext_len);
860  if (strcmp(ext, builtin_mime_types[i].extension) == 0) {
861  return builtin_mime_types[i].mime_type;
862  }
863  }
864 
865  return "text/plain";
866 }
867 
868 ////////////////////////////////////////////////////////////////////////////////
869 /// reads file content
870 
872 {
873  len = 0;
874 
875  std::ifstream is(filename);
876  if (!is) return 0;
877 
878  is.seekg(0, is.end);
879  len = is.tellg();
880  is.seekg(0, is.beg);
881 
882  char *buf = (char *) malloc(len);
883  is.read(buf, len);
884  if (!is) {
885  free(buf);
886  len = 0;
887  return 0;
888  }
889 
890  return buf;
891 }
void SetZipping(Int_t kind)
Definition: THttpCallArg.h:271
Bool_t RegisterObject(const char *subfolder, TObject *obj)
Register object in subfolder structure subfolder parameter can have many levels like: ...
An array of TObjects.
Definition: TObjArray.h:39
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
Definition: TList.cxx:405
Bool_t Produce(const char *path, const char *file, const char *options, void *&ptr, Long_t &length, TString &str)
Method produce different kind of data out of object Parameter 'path' specifies object or object membe...
Bool_t IsStreamerInfoItem(const char *itemname)
Return true if it is streamer info item name.
virtual void Process()
Method regularly called in main ROOT context.
Definition: THttpEngine.h:27
ClassImp(TSeqCollection) Int_t TSeqCollection TIter next(this)
Return index of object in collection.
const char * mime_type
Definition: civetweb.c:2469
Ssiz_t Length() const
Definition: TString.h:390
static const struct @203 builtin_mime_types[]
Int_t GetLast() const
Return index of last object in array.
Definition: TObjArray.cxx:528
Storage of hierarchy scan in TRootSniffer in JSON format.
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition: TString.h:635
const char * GetItemField(const char *fullname, const char *name)
Bool_t Is404() const
Definition: THttpCallArg.h:304
static const char * filename()
#define gROOT
Definition: TROOT.h:344
TString fQuery
authenticated user name (if any)
Definition: THttpCallArg.h:30
Basic string class.
Definition: TString.h:137
TString fTopName
location of local JSROOT files
Definition: THttpServer.h:41
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kFALSE
Definition: Rtypes.h:92
virtual TObject * FindObject(const char *name) const
Find an object in this list using its name.
Definition: TList.cxx:497
void Restrict(const char *path, const char *options)
Restrict access to the specified location.
Bool_t UnregisterObject(TObject *obj)
unregister (remove) object from folders structures folder itself will remain even when it will be emp...
TList fEngines
Definition: THttpServer.h:34
void SetServer(THttpServer *serv)
Definition: THttpEngine.h:21
void SetContentType(const char *typ)
Definition: THttpCallArg.h:201
Bool_t CreateItem(const char *fullname, const char *title)
create item element
void ProcessRequests()
Process submitted requests, must be called from main thread.
Bool_t CreateItem(const char *fullname, const char *title)
const char * Data() const
Definition: TString.h:349
TRootSniffer * fSniffer
timer used to access main thread
Definition: THttpServer.h:36
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString...
Definition: TString.cxx:2321
Bool_t SetItemField(const char *fullname, const char *name, const char *value)
set field for specified item
Bool_t IsReadOnly() const
Definition: TRootSniffer.h:177
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:33
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4602
std::map< std::string, std::string >::const_iterator iter
Definition: TAlienJob.cxx:54
void Clear()
Clear string without changing its capacity.
Definition: TString.cxx:1126
THttpTimer * fTimer
engines which runs http server
Definition: THttpServer.h:35
virtual const char * Getenv(const char *env)
Get environment variable.
Definition: TSystem.cxx:1575
TString fPathName
request method like GET or POST
Definition: THttpCallArg.h:27
TString & Append(const char *cs)
Definition: TString.h:492
static Long_t SelfId()
Static method returning the id for the current thread.
Definition: TThread.cxx:538
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 Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:918
ClassImp(THttpServer) THttpServer
constructor
TList fLocations
location of external JSROOT files
Definition: THttpServer.h:43
TString fJSROOTSYS
id of the main ROOT process
Definition: THttpServer.h:40
Storage of hierarchy scan in TRootSniffer in XML format.
Bool_t Register(const char *subfolder, TObject *obj)
Register object in subfolder.
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 ...
TString fTopName
Definition: THttpCallArg.h:25
void SetBinData(void *data, Long_t length)
set binary data, which will be returned as reply body
void SetJson()
Definition: THttpCallArg.h:230
Bool_t CreateEngine(const char *engine)
factory method to create different http engines At the moment two engine kinds are supported: civetwe...
size_t ext_len
Definition: civetweb.c:2468
Bool_t EndsWith(const char *pat, ECaseCompare cmp=kExact) const
Return true if string ends with the specified string.
Definition: TString.cxx:2207
R__EXTERN TSystem * gSystem
Definition: TSystem.h:545
TPaveLabel title(3, 27.1, 15, 28.7,"ROOT Environment and Tools")
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2308
virtual ~THttpServer()
destructor delete all http engines and sniffer
Bool_t RegisterCommand(const char *cmdname, const char *method, const char *icon)
Register command which can be executed from web interface.
char * Form(const char *fmt,...)
Bool_t IsFileRequested(const char *uri, TString &res) const
Check if file is requested, thread safe.
TString fDefaultPage
list of local directories, which could be accessed via server
Definition: THttpServer.h:45
Bool_t IsReadOnly() const
returns read-only mode
virtual Bool_t Create(const char *)
Method to create all components of engine.
Definition: THttpEngine.h:33
Handles synchronous and a-synchronous timer events.
Definition: TTimer.h:57
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:81
Bool_t IsNull() const
Definition: TString.h:387
void Warning(const char *location, const char *msgfmt,...)
void SetSniffer(TRootSniffer *sniff)
Set TRootSniffer to the server Server takes ownership over sniffer.
void ScanHierarchy(const char *topname, const char *path, TRootSnifferStore *store, Bool_t only_fields=kFALSE)
Method scans normal objects, registered in ROOT.
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition: TString.cxx:2227
tuple free
Definition: fildir.py:30
Bool_t ExecuteHttp(THttpCallArg *arg)
Execute HTTP request.
const char * extension
Definition: civetweb.c:2467
TString fDrawPage
content of the file content
Definition: THttpServer.h:47
TString & Remove(Ssiz_t pos)
Definition: TString.h:616
long Long_t
Definition: RtypesCore.h:50
int Ssiz_t
Definition: RtypesCore.h:63
std::condition_variable fCond
length of binary data
Definition: THttpCallArg.h:35
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 ...
virtual Int_t GetSize() const
Definition: TCollection.h:95
Bool_t Hide(const char *fullname, Bool_t hide=kTRUE)
hides folder or element from web gui
std::mutex fMutex
content of draw page
Definition: THttpServer.h:50
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:415
virtual void ProcessRequest(THttpCallArg *arg)
submitted arguments
TString fDrawPageCont
file name for drawing of single element
Definition: THttpServer.h:48
TNamed()
Definition: TNamed.h:40
TString fDefaultPageCont
file name for default page name
Definition: THttpServer.h:46
Bool_t RegisterCommand(const char *cmdname, const char *method, const char *icon=0)
Register command which can be executed from web interface.
#define name(a, b)
Definition: linkTestLib0.cpp:5
Mother of all ROOT objects.
Definition: TObject.h:58
static const char * GetMimeType(const char *path)
Guess mime type base on file extension.
Bool_t Unregister(TObject *obj)
Unregister object.
TString fContent
response header like ContentEncoding, Cache-Control and so on
Definition: THttpCallArg.h:40
virtual TObject * First() const
Return the first object in the list. Returns 0 when list is empty.
Definition: TList.cxx:557
Long_t fMainThrdId
sniffer provides access to ROOT objects hierarchy
Definition: THttpServer.h:38
void AddHeader(const char *name, const char *value)
Set name: value pair to reply header Content-Type field handled separately - one should use SetConten...
static char * ReadFileContent(const char *filename, Int_t &len)
Reads content of file from the disk.
void SetReadOnly(Bool_t on=kTRUE)
Definition: TRootSniffer.h:169
virtual void Add(TObject *obj)
Definition: TList.h:81
const Ssiz_t kNPOS
Definition: Rtypes.h:115
void SetFile(const char *filename=0)
Definition: THttpCallArg.h:215
Bool_t SetIcon(const char *fullname, const char *iconname)
set name of icon, used in browser together with the item
virtual void Timeout()
Definition: TTimer.h:102
#define NULL
Definition: Rtypes.h:82
TList fCallArgs
mutex to protect list with arguments
Definition: THttpServer.h:51
static Bool_t VerifyFilePath(const char *fname)
Checked that filename does not contains relative path below current directory Used to prevent access ...
virtual Bool_t ExpandPathName(TString &path)
Expand a pathname getting rid of special shell characters like ~.
Definition: TSystem.cxx:1191
TString fJSROOT
name of top folder, default - "ROOT"
Definition: THttpServer.h:42
TObject * At(Int_t idx) const
Definition: TObjArray.h:167
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:582
const Bool_t kTRUE
Definition: Rtypes.h:91
void SetCurrentCallArg(THttpCallArg *arg)
set current http arguments, which then used in different process methods For instance, if user authorized with some user name, depending from restrictions some objects will be invisible or user get full access to the element
virtual const char * GetTitle() const
Returns title of object.
Definition: TObject.cxx:459
virtual void SetTitle(const char *title="")
Change (i.e. set) the title of the TNamed.
Definition: TNamed.cxx:152
TObject * obj
float value
Definition: math.cpp:443
Vc_ALWAYS_INLINE_L T *Vc_ALWAYS_INLINE_R malloc(size_t n)
Allocates memory on the Heap with alignment and padding suitable for vectorized access.
Definition: memory.h:67
void SetDrawPage(const char *filename)
Set file name of HTML page, delivered by the server when objects drawing page is requested from the b...
const Int_t n
Definition: legend1.C:16
TString fFileName
item path
Definition: THttpCallArg.h:28
Bool_t SetItemField(const char *fullname, const char *name, const char *value)
const char * GetItemField(TFolder *parent, TObject *item, const char *name)
return field for specified item
void Restrict(const char *path, const char *options)
Restrict access to specified object.
void Resize(Ssiz_t n)
Resize the string. Truncate or add blanks as necessary.
Definition: TString.cxx:1045
ULong_t GetStreamerInfoHash()
Returns hash value for streamer infos At the moment - just number of items in streamer infos list...
void SetDefaultPage(const char *filename)
Set file name of HTML page, delivered by the server when http address is opened in the browser...
virtual void RemoveFirst()
void SetJSROOT(const char *location)
Set location of JSROOT to use with the server One could specify address like: https://root.cern.ch/js/3.3/ http://web-docs.gsi.de/~linev/js/3.3/ This allows to get new JSROOT features with old server, reduce load on THttpServer instance, also startup time can be improved When empty string specified (default), local copy of JSROOT is used (distributed with ROOT)