ROOT  6.06/09
Reference Guide
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 "TTimer.h"
7 #include "TSystem.h"
8 #include "TImage.h"
9 #include "TROOT.h"
10 #include "TClass.h"
11 #include "TFolder.h"
12 #include "RVersion.h"
13 #include "RConfigure.h"
14 
15 #include "THttpEngine.h"
16 #include "TRootSniffer.h"
17 #include "TRootSnifferStore.h"
18 
19 #include <string>
20 #include <cstdlib>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <fstream>
24 
25 
26 //////////////////////////////////////////////////////////////////////////
27 // //
28 // THttpTimer //
29 // //
30 // Specialized timer for THttpServer //
31 // Provides regular call of THttpServer::ProcessRequests() method //
32 // //
33 //////////////////////////////////////////////////////////////////////////
34 
35 
36 ////////////////////////////////////////////////////////////////////////////////
37 
38 class THttpTimer : public TTimer {
39 public:
40 
41  THttpServer *fServer; //!
42 
43  THttpTimer(Long_t milliSec, Bool_t mode, THttpServer *serv) :
44  TTimer(milliSec, mode), fServer(serv)
45  {
46  // construtor
47  }
48  virtual ~THttpTimer()
49  {
50  // destructor
51  }
52  virtual void Timeout()
53  {
54  // timeout handler
55  // used to process http requests in main ROOT thread
56 
57  if (fServer) fServer->ProcessRequests();
58  }
59 };
60 
61 // =======================================================
62 
63 //////////////////////////////////////////////////////////////////////////
64 // //
65 // THttpServer //
66 // //
67 // Online http server for arbitrary ROOT application //
68 // //
69 // Idea of THttpServer - provide remote http access to running //
70 // ROOT application and enable HTML/JavaScript user interface. //
71 // Any registered object can be requested and displayed in the browser. //
72 // There are many benefits of such approach: //
73 // * standard http interface to ROOT application //
74 // * no any temporary ROOT files when access data //
75 // * user interface running in all browsers //
76 // //
77 // Starting HTTP server //
78 // //
79 // To start http server, at any time create instance //
80 // of the THttpServer class like: //
81 // serv = new THttpServer("http:8080"); //
82 // //
83 // This will starts civetweb-based http server with http port 8080. //
84 // Than one should be able to open address "http://localhost:8080" //
85 // in any modern browser (IE, Firefox, Chrome) and browse objects, //
86 // created in application. By default, server can access files, //
87 // canvases and histograms via gROOT pointer. All such objects //
88 // can be displayed with JSROOT graphics. //
89 // //
90 // At any time one could register other objects with the command: //
91 // //
92 // TGraph* gr = new TGraph(10); //
93 // gr->SetName("gr1"); //
94 // serv->Register("graphs/subfolder", gr); //
95 // //
96 // If objects content is changing in the application, one could //
97 // enable monitoring flag in the browser - than objects view //
98 // will be regularly updated. //
99 // //
100 // More information: http://root.cern.ch/drupal/content/users-guide //
101 // //
102 //////////////////////////////////////////////////////////////////////////
103 
105 
106 ////////////////////////////////////////////////////////////////////////////////
107 /// constructor
108 
109 THttpServer::THttpServer(const char *engine) :
110  TNamed("http", "ROOT http server"),
111  fEngines(),
112  fTimer(0),
113  fSniffer(0),
114  fMainThrdId(0),
115  fJSROOTSYS(),
116  fTopName("ROOT"),
117  fJSROOT(),
118  fLocations(),
119  fDefaultPage(),
120  fDefaultPageCont(),
121  fDrawPage(),
122  fDrawPageCont(),
123  fMutex(),
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  fMutex.Lock();
469  fCallArgs.Add(arg);
470  fMutex.UnLock();
471 
472  // and now wait until request is processed
473  arg->fCond.Wait();
474 
475  return kTRUE;
476 }
477 
478 ////////////////////////////////////////////////////////////////////////////////
479 /// Process requests, submitted for execution
480 /// Regularly invoked by THttpTimer, when somewhere in the code
481 /// gSystem->ProcessEvents() is called.
482 /// User can call serv->ProcessRequests() directly, but only from main analysis thread.
483 
485 {
487 
488  if (fMainThrdId != TThread::SelfId()) {
489  Error("ProcessRequests", "Should be called only from main ROOT thread");
490  return;
491  }
492 
493  while (true) {
494  THttpCallArg *arg = 0;
495 
496  fMutex.Lock();
497  if (fCallArgs.GetSize() > 0) {
498  arg = (THttpCallArg *) fCallArgs.First();
500  }
501  fMutex.UnLock();
502 
503  if (arg == 0) break;
504 
506 
507  try {
508  ProcessRequest(arg);
510  } catch (...) {
512  }
513 
514  arg->fCond.Signal();
515  }
516 
517  // regularly call Process() method of engine to let perform actions in ROOT context
518  TIter iter(&fEngines);
519  THttpEngine *engine = 0;
520  while ((engine = (THttpEngine *)iter()) != 0)
521  engine->Process();
522 }
523 
524 ////////////////////////////////////////////////////////////////////////////////
525 /// Process single http request
526 /// Depending from requested path and filename different actions will be performed.
527 /// In most cases information is provided by TRootSniffer class
528 
530 {
531 
532  if (arg->fFileName.IsNull() || (arg->fFileName == "index.htm")) {
533 
534  if (fDefaultPageCont.Length() == 0) {
535  Int_t len = 0;
536  char *buf = ReadFileContent(fDefaultPage.Data(), len);
537  if (len > 0) fDefaultPageCont.Append(buf, len);
538  delete buf;
539  }
540 
541  if (fDefaultPageCont.Length() == 0) {
542  arg->Set404();
543  } else {
544  arg->fContent = fDefaultPageCont;
545 
546  // replace all references on JSROOT
547  if (fJSROOT.Length() > 0) {
548  TString repl = TString("=\"") + fJSROOT;
549  if (!repl.EndsWith("/")) repl+="/";
550  arg->fContent.ReplaceAll("=\"jsrootsys/", repl);
551  }
552 
553  const char *hjsontag = "\"$$$h.json$$$\"";
554 
555  // add h.json caching
556  if (arg->fContent.Index(hjsontag) != kNPOS) {
557  TString h_json;
558  TRootSnifferStoreJson store(h_json, kTRUE);
559  const char *topname = fTopName.Data();
560  if (arg->fTopName.Length() > 0) topname = arg->fTopName.Data();
561  fSniffer->ScanHierarchy(topname, arg->fPathName.Data(), &store);
562 
563  arg->fContent.ReplaceAll(hjsontag, h_json);
564 
565  arg->AddHeader("Cache-Control", "private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0");
566  if (arg->fQuery.Index("nozip") == kNPOS) arg->SetZipping(2);
567  }
568  arg->SetContentType("text/html");
569  }
570  return;
571  }
572 
573  if (arg->fFileName == "draw.htm") {
574  if (fDrawPageCont.Length() == 0) {
575  Int_t len = 0;
576  char *buf = ReadFileContent(fDrawPage.Data(), len);
577  if (len > 0) fDrawPageCont.Append(buf, len);
578  delete buf;
579  }
580 
581  if (fDrawPageCont.Length() == 0) {
582  arg->Set404();
583  } else {
584  const char *rootjsontag = "\"$$$root.json$$$\"";
585  const char *hjsontag = "\"$$$h.json$$$\"";
586 
587  arg->fContent = fDrawPageCont;
588 
589  // replace all references on JSROOT
590  if (fJSROOT.Length() > 0) {
591  TString repl = TString("=\"") + fJSROOT;
592  if (!repl.EndsWith("/")) repl+="/";
593  arg->fContent.ReplaceAll("=\"jsrootsys/", repl);
594  }
595 
596  if (arg->fContent.Index(hjsontag) != kNPOS) {
597  TString h_json;
598  TRootSnifferStoreJson store(h_json, kTRUE);
599  const char *topname = fTopName.Data();
600  if (arg->fTopName.Length() > 0) topname = arg->fTopName.Data();
601  fSniffer->ScanHierarchy(topname, arg->fPathName.Data(), &store, kTRUE);
602 
603  arg->fContent.ReplaceAll(hjsontag, h_json);
604  }
605 
606  if (arg->fContent.Index(rootjsontag) != kNPOS) {
607  TString str;
608  void *bindata = 0;
609  Long_t bindatalen = 0;
610  if (fSniffer->Produce(arg->fPathName.Data(), "root.json", "compact=3", bindata, bindatalen, str)) {
611  arg->fContent.ReplaceAll(rootjsontag, str);
612  }
613  }
614  arg->AddHeader("Cache-Control", "private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0");
615  if (arg->fQuery.Index("nozip") == kNPOS) arg->SetZipping(2);
616  arg->SetContentType("text/html");
617  }
618  return;
619  }
620 
622  if (IsFileRequested(arg->fFileName.Data(), filename)) {
623  arg->SetFile(filename);
624  return;
625  }
626 
627  filename = arg->fFileName;
628  Bool_t iszip = kFALSE;
629  if (filename.EndsWith(".gz")) {
630  filename.Resize(filename.Length() - 3);
631  iszip = kTRUE;
632  }
633 
634  void* bindata(0);
635  Long_t bindatalen(0);
636 
637  if ((filename == "h.xml") || (filename == "get.xml")) {
638 
639  Bool_t compact = arg->fQuery.Index("compact") != kNPOS;
640 
641  arg->fContent.Form("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
642  if (!compact) arg->fContent.Append("\n");
643  arg->fContent.Append("<root>");
644  if (!compact) arg->fContent.Append("\n");
645  {
646  TRootSnifferStoreXml store(arg->fContent, compact);
647 
648  const char *topname = fTopName.Data();
649  if (arg->fTopName.Length() > 0) topname = arg->fTopName.Data();
650  fSniffer->ScanHierarchy(topname, arg->fPathName.Data(), &store, filename == "get.xml");
651  }
652 
653  arg->fContent.Append("</root>");
654  if (!compact) arg->fContent.Append("\n");
655 
656  arg->SetXml();
657  } else
658 
659  if (filename == "h.json") {
660  TRootSnifferStoreJson store(arg->fContent, arg->fQuery.Index("compact") != kNPOS);
661  const char *topname = fTopName.Data();
662  if (arg->fTopName.Length() > 0) topname = arg->fTopName.Data();
663  fSniffer->ScanHierarchy(topname, arg->fPathName.Data(), &store);
664  arg->SetJson();
665  } else
666 
667  if (fSniffer->Produce(arg->fPathName.Data(), filename.Data(), arg->fQuery.Data(), bindata, bindatalen, arg->fContent)) {
668  if (bindata != 0) arg->SetBinData(bindata, bindatalen);
669 
670  // define content type base on extension
671  arg->SetContentType(GetMimeType(filename.Data()));
672  } else {
673  // request is not processed
674  arg->Set404();
675  }
676 
677  if (arg->Is404()) return;
678 
679  if (iszip) arg->SetZipping(3);
680 
681  if (filename == "root.bin") {
682  // only for binary data master version is important
683  // it allows to detect if streamer info was modified
684  const char *parname = fSniffer->IsStreamerInfoItem(arg->fPathName.Data()) ? "BVersion" : "MVersion";
685  arg->AddHeader(parname, Form("%u", (unsigned) fSniffer->GetStreamerInfoHash()));
686  }
687 
688  // try to avoid caching on the browser
689  arg->AddHeader("Cache-Control", "private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0");
690 }
691 
692 ////////////////////////////////////////////////////////////////////////////////
693 /// Register object in folders hierarchy
694 ///
695 /// See TRootSniffer::RegisterObject() for more details
696 
697 Bool_t THttpServer::Register(const char *subfolder, TObject *obj)
698 {
699  return fSniffer->RegisterObject(subfolder, obj);
700 }
701 
702 ////////////////////////////////////////////////////////////////////////////////
703 /// Unregister object in folders hierarchy
704 ///
705 /// See TRootSniffer::UnregisterObject() for more details
706 
708 {
709  return fSniffer->UnregisterObject(obj);
710 }
711 
712 ////////////////////////////////////////////////////////////////////////////////
713 /// Restrict access to specified object
714 ///
715 /// See TRootSniffer::Restrict() for more details
716 
717 void THttpServer::Restrict(const char *path, const char* options)
718 {
719  fSniffer->Restrict(path, options);
720 }
721 
722 ////////////////////////////////////////////////////////////////////////////////
723 /// Register command which can be executed from web interface
724 ///
725 /// As method one typically specifies string, which is executed with
726 /// gROOT->ProcessLine() method. For instance
727 /// serv->RegisterCommand("Invoke","InvokeFunction()");
728 ///
729 /// Or one could specify any method of the object which is already registered
730 /// to the server. For instance:
731 /// serv->Register("/", hpx);
732 /// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()");
733 /// Here symbols '/->' separates item name from method to be executed
734 ///
735 /// One could specify additional arguments in the command with
736 /// syntax like %arg1%, %arg2% and so on. For example:
737 /// serv->RegisterCommand("/ResetHPX", "/hpx/->SetTitle(\"%arg1%\")");
738 /// serv->RegisterCommand("/RebinHPXPY", "/hpxpy/->Rebin2D(%arg1%,%arg2%)");
739 /// Such parameter(s) will be requested when command clicked in the browser.
740 ///
741 /// Once command is registered, one could specify icon which will appear in the browser:
742 /// serv->SetIcon("/ResetHPX", "rootsys/icons/ed_execute.png");
743 ///
744 /// One also can set extra property '_fastcmd', that command appear as
745 /// tool button on the top of the browser tree:
746 /// serv->SetItemField("/ResetHPX", "_fastcmd", "true");
747 /// Or it is equivalent to specifying extra argument when register command:
748 /// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()", "button;rootsys/icons/ed_delete.png");
749 
750 Bool_t THttpServer::RegisterCommand(const char *cmdname, const char *method, const char *icon)
751 {
752  return fSniffer->RegisterCommand(cmdname, method, icon);
753 }
754 
755 ////////////////////////////////////////////////////////////////////////////////
756 /// hides folder or element from web gui
757 
758 Bool_t THttpServer::Hide(const char *foldername, Bool_t hide)
759 {
760  return SetItemField(foldername, "_hidden", hide ? "true" : (const char *) 0);
761 }
762 
763 ////////////////////////////////////////////////////////////////////////////////
764 /// set name of icon, used in browser together with the item
765 ///
766 /// One could use images from $ROOTSYS directory like:
767 /// serv->SetIcon("/ResetHPX","/rootsys/icons/ed_execute.png");
768 
769 Bool_t THttpServer::SetIcon(const char *fullname, const char *iconname)
770 {
771  return SetItemField(fullname, "_icon", iconname);
772 }
773 
774 ////////////////////////////////////////////////////////////////////////////////
775 
776 Bool_t THttpServer::CreateItem(const char *fullname, const char *title)
777 {
778  return fSniffer->CreateItem(fullname, title);
779 }
780 
781 ////////////////////////////////////////////////////////////////////////////////
782 
783 Bool_t THttpServer::SetItemField(const char *fullname, const char *name, const char *value)
784 {
785  return fSniffer->SetItemField(fullname, name, value);
786 }
787 
788 ////////////////////////////////////////////////////////////////////////////////
789 
790 const char *THttpServer::GetItemField(const char *fullname, const char *name)
791 {
792  return fSniffer->GetItemField(fullname, name);
793 }
794 
795 ////////////////////////////////////////////////////////////////////////////////
796 /// Returns MIME type base on file extension
797 
798 const char *THttpServer::GetMimeType(const char *path)
799 {
800  static const struct {
801  const char *extension;
802  int ext_len;
803  const char *mime_type;
804  } builtin_mime_types[] = {
805  {".xml", 4, "text/xml"},
806  {".json", 5, "application/json"},
807  {".bin", 4, "application/x-binary"},
808  {".gif", 4, "image/gif"},
809  {".jpg", 4, "image/jpeg"},
810  {".png", 4, "image/png"},
811  {".html", 5, "text/html"},
812  {".htm", 4, "text/html"},
813  {".shtm", 5, "text/html"},
814  {".shtml", 6, "text/html"},
815  {".css", 4, "text/css"},
816  {".js", 3, "application/x-javascript"},
817  {".ico", 4, "image/x-icon"},
818  {".jpeg", 5, "image/jpeg"},
819  {".svg", 4, "image/svg+xml"},
820  {".txt", 4, "text/plain"},
821  {".torrent", 8, "application/x-bittorrent"},
822  {".wav", 4, "audio/x-wav"},
823  {".mp3", 4, "audio/x-mp3"},
824  {".mid", 4, "audio/mid"},
825  {".m3u", 4, "audio/x-mpegurl"},
826  {".ogg", 4, "application/ogg"},
827  {".ram", 4, "audio/x-pn-realaudio"},
828  {".xslt", 5, "application/xml"},
829  {".xsl", 4, "application/xml"},
830  {".ra", 3, "audio/x-pn-realaudio"},
831  {".doc", 4, "application/msword"},
832  {".exe", 4, "application/octet-stream"},
833  {".zip", 4, "application/x-zip-compressed"},
834  {".xls", 4, "application/excel"},
835  {".tgz", 4, "application/x-tar-gz"},
836  {".tar", 4, "application/x-tar"},
837  {".gz", 3, "application/x-gunzip"},
838  {".arj", 4, "application/x-arj-compressed"},
839  {".rar", 4, "application/x-arj-compressed"},
840  {".rtf", 4, "application/rtf"},
841  {".pdf", 4, "application/pdf"},
842  {".swf", 4, "application/x-shockwave-flash"},
843  {".mpg", 4, "video/mpeg"},
844  {".webm", 5, "video/webm"},
845  {".mpeg", 5, "video/mpeg"},
846  {".mov", 4, "video/quicktime"},
847  {".mp4", 4, "video/mp4"},
848  {".m4v", 4, "video/x-m4v"},
849  {".asf", 4, "video/x-ms-asf"},
850  {".avi", 4, "video/x-msvideo"},
851  {".bmp", 4, "image/bmp"},
852  {".ttf", 4, "application/x-font-ttf"},
853  {NULL, 0, NULL}
854  };
855 
856  int path_len = strlen(path);
857 
858  for (int i = 0; builtin_mime_types[i].extension != NULL; i++) {
859  if (path_len <= builtin_mime_types[i].ext_len) continue;
860  const char *ext = path + (path_len - builtin_mime_types[i].ext_len);
861  if (strcmp(ext, builtin_mime_types[i].extension) == 0) {
862  return builtin_mime_types[i].mime_type;
863  }
864  }
865 
866  return "text/plain";
867 }
868 
869 ////////////////////////////////////////////////////////////////////////////////
870 /// reads file content
871 
873 {
874  len = 0;
875 
876  std::ifstream is(filename);
877  if (!is) return 0;
878 
879  is.seekg(0, is.end);
880  len = is.tellg();
881  is.seekg(0, is.beg);
882 
883  char *buf = (char *) malloc(len);
884  is.read(buf, len);
885  if (!is) {
886  free(buf);
887  len = 0;
888  return 0;
889  }
890 
891  return buf;
892 }
void SetZipping(Int_t kind)
Definition: THttpCallArg.h:273
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:404
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
Namespace for new ROOT classes and functions.
Definition: ROOT.py:1
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
Int_t GetLast() const
Return index of last object in array.
Definition: TObjArray.cxx:527
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:306
static const struct @204 builtin_mime_types[]
static const char * filename()
#define gROOT
Definition: TROOT.h:340
TString fQuery
authenticated user name (if any)
Definition: THttpCallArg.h:32
Basic string class.
Definition: TString.h:137
TString fTopName
location of local JSROOT files
Definition: THttpServer.h:40
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:496
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:33
void SetServer(THttpServer *serv)
Definition: THttpEngine.h:21
void SetContentType(const char *typ)
Definition: THttpCallArg.h:203
Bool_t CreateItem(const char *fullname, const char *title)
create item element
void ProcessRequests()
Process submitted requests, must be called from main thread.
Int_t UnLock()
Unlock the mutex.
Definition: TMutex.cxx:68
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:35
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:2334
Vc_ALWAYS_INLINE void free(T *p)
Frees memory that was allocated with Vc::malloc.
Definition: memory.h:94
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:4683
std::map< std::string, std::string >::const_iterator iter
Definition: TAlienJob.cxx:54
void Clear()
Clear string without changing its capacity.
Definition: TString.cxx:1139
THttpTimer * fTimer
engines which runs http server
Definition: THttpServer.h:34
virtual const char * Getenv(const char *env)
Get environment variable.
Definition: TSystem.cxx:1627
TString fPathName
request method like GET or POST
Definition: THttpCallArg.h:29
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:537
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:42
TString fJSROOTSYS
id of the main ROOT process
Definition: THttpServer.h:39
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 ...
Int_t Wait()
Wait to be signaled.
Definition: TCondition.cxx:74
TString fTopName
Definition: THttpCallArg.h:27
void SetBinData(void *data, Long_t length)
set binary data, which will be returned as reply body
void SetJson()
Definition: THttpCallArg.h:232
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:2220
R__EXTERN TSystem * gSystem
Definition: TSystem.h:549
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2321
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:44
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:2240
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:46
TString & Remove(Ssiz_t pos)
Definition: TString.h:616
long Long_t
Definition: RtypesCore.h:50
int Ssiz_t
Definition: RtypesCore.h:63
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
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:47
TNamed()
Definition: TNamed.h:40
TString fDefaultPageCont
file name for default page name
Definition: THttpServer.h:45
Int_t Lock()
Lock the mutex.
Definition: TMutex.cxx:46
Bool_t RegisterCommand(const char *cmdname, const char *method, const char *icon=0)
Register command which can be executed from web interface.
TCondition fCond
length of binary data
Definition: THttpCallArg.h:37
#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:42
virtual TObject * First() const
Return the first object in the list. Returns 0 when list is empty.
Definition: TList.cxx:556
Long_t fMainThrdId
sniffer provides access to ROOT objects hierarchy
Definition: THttpServer.h:37
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:217
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:50
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:1243
TString fJSROOT
name of top folder, default - "ROOT"
Definition: THttpServer.h:41
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:30
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
TMutex fMutex
content of draw page
Definition: THttpServer.h:49
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:1058
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...
Int_t Signal()
Definition: TCondition.h:57
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)