ROOT  6.06/08
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  TString jsdir = TString::Format("%s/http", TROOT::GetEtcDir().Data());
151  if (gSystem->ExpandPathName(jsdir)) {
152  Warning("THttpServer", "problems resolving '%s', use JSROOTSYS to specify $ROOTSYS/etc/http location", jsdir.Data());
153  fJSROOTSYS = ".";
154  } else {
155  fJSROOTSYS = jsdir;
156  }
157  }
158 
159  AddLocation("currentdir/", ".");
160  AddLocation("jsrootsys/", fJSROOTSYS);
161  AddLocation("rootsys/", TROOT::GetRootSys());
162 
163  fDefaultPage = fJSROOTSYS + "/files/online.htm";
164  fDrawPage = fJSROOTSYS + "/files/draw.htm";
165 
166  SetSniffer(new TRootSniffer("sniff"));
167 
168  // start timer
169  SetTimer(20, kTRUE);
170 
171  if (strchr(engine, ';') == 0) {
172  CreateEngine(engine);
173  } else {
174  TObjArray *lst = TString(engine).Tokenize(";");
175 
176  for (Int_t n = 0; n <= lst->GetLast(); n++) {
177  const char *opt = lst->At(n)->GetName();
178  if ((strcmp(opt, "readonly") == 0) || (strcmp(opt, "ro") == 0)) {
179  GetSniffer()->SetReadOnly(kTRUE);
180  } else if ((strcmp(opt, "readwrite") == 0) || (strcmp(opt, "rw") == 0)) {
181  GetSniffer()->SetReadOnly(kFALSE);
182  } else
183  CreateEngine(opt);
184  }
185 
186  delete lst;
187  }
188 }
189 
190 ////////////////////////////////////////////////////////////////////////////////
191 /// destructor
192 /// delete all http engines and sniffer
193 
195 {
196  fEngines.Delete();
197 
198  SetSniffer(0);
199 
200  SetTimer(0);
201 }
202 
203 ////////////////////////////////////////////////////////////////////////////////
204 /// Set TRootSniffer to the server
205 /// Server takes ownership over sniffer
206 
208 {
209  if (fSniffer) delete fSniffer;
210  fSniffer = sniff;
211 }
212 
213 ////////////////////////////////////////////////////////////////////////////////
214 /// returns read-only mode
215 
217 {
218  return fSniffer ? fSniffer->IsReadOnly() : kTRUE;
219 }
220 
221 ////////////////////////////////////////////////////////////////////////////////
222 /// Set read-only mode for the server (default on)
223 /// In read-only server is not allowed to change any ROOT object, registered to the server
224 /// Server also cannot execute objects method via exe.json request
225 
227 {
228  if (fSniffer) fSniffer->SetReadOnly(readonly);
229 }
230 
231 ////////////////////////////////////////////////////////////////////////////////
232 /// add files location, which could be used in the server
233 /// one could map some system folder to the server like AddLocation("mydir/","/home/user/specials");
234 /// Than files from this directory could be addressed via server like
235 /// http://localhost:8080/mydir/myfile.root
236 
237 void THttpServer::AddLocation(const char *prefix, const char *path)
238 {
239  if ((prefix==0) || (*prefix==0)) return;
240 
241  TNamed *obj = dynamic_cast<TNamed*> (fLocations.FindObject(prefix));
242  if (obj != 0) {
243  obj->SetTitle(path);
244  } else {
245  fLocations.Add(new TNamed(prefix, path));
246  }
247 }
248 
249 ////////////////////////////////////////////////////////////////////////////////
250 /// Set location of JSROOT to use with the server
251 /// One could specify address like:
252 /// https://root.cern.ch/js/3.3/
253 /// http://web-docs.gsi.de/~linev/js/3.3/
254 /// This allows to get new JSROOT features with old server,
255 /// reduce load on THttpServer instance, also startup time can be improved
256 /// When empty string specified (default), local copy of JSROOT is used (distributed with ROOT)
257 
258 void THttpServer::SetJSROOT(const char* location)
259 {
260  fJSROOT = location ? location : "";
261 }
262 
263 ////////////////////////////////////////////////////////////////////////////////
264 /// Set file name of HTML page, delivered by the server when
265 /// http address is opened in the browser.
266 /// By default, $ROOTSYS/etc/http/files/online.htm page is used
267 /// When empty filename is specified, default page will be used
268 
270 {
271  if ((filename!=0) && (*filename!=0))
272  fDefaultPage = filename;
273  else
274  fDefaultPage = fJSROOTSYS + "/files/online.htm";
275 
276  // force to read page content next time again
277  fDefaultPageCont.Clear();
278 }
279 
280 ////////////////////////////////////////////////////////////////////////////////
281 /// Set file name of HTML page, delivered by the server when
282 /// objects drawing page is requested from the browser
283 /// By default, $ROOTSYS/etc/http/files/draw.htm page is used
284 /// When empty filename is specified, default page will be used
285 
287 {
288  if ((filename!=0) && (*filename!=0))
289  fDrawPage = filename;
290  else
291  fDrawPage = fJSROOTSYS + "/files/draw.htm";
292 
293  // force to read page content next time again
294  fDrawPageCont.Clear();
295 }
296 
297 ////////////////////////////////////////////////////////////////////////////////
298 /// factory method to create different http engines
299 /// At the moment two engine kinds are supported:
300 /// civetweb (default) and fastcgi
301 /// Examples:
302 /// "civetweb:8080" or "http:8080" or ":8080" - creates civetweb web server with http port 8080
303 /// "fastcgi:9000" - creates fastcgi server with port 9000
304 /// "dabc:1237" - create DABC server with port 1237 (only available with DABC installed)
305 /// "dabc:master_host:port" - attach to DABC master, running on master_host:port (only available with DABC installed)
306 
308 {
309  if (engine == 0) return kFALSE;
310 
311  const char *arg = strchr(engine, ':');
312  if (arg == 0) return kFALSE;
313 
314  TString clname;
315  if (arg != engine) clname.Append(engine, arg - engine);
316 
317  if ((clname.Length() == 0) || (clname == "http") || (clname == "civetweb"))
318  clname = "TCivetweb";
319  else if (clname == "fastcgi")
320  clname = "TFastCgi";
321  else if (clname == "dabc")
322  clname = "TDabcEngine";
323 
324  // ensure that required engine class exists before we try to create it
325  TClass *engine_class = gROOT->LoadClass(clname.Data());
326  if (engine_class == 0) return kFALSE;
327 
328  THttpEngine *eng = (THttpEngine *) engine_class->New();
329  if (eng == 0) return kFALSE;
330 
331  eng->SetServer(this);
332 
333  if (!eng->Create(arg + 1)) {
334  delete eng;
335  return kFALSE;
336  }
337 
338  fEngines.Add(eng);
339 
340  return kTRUE;
341 }
342 
343 ////////////////////////////////////////////////////////////////////////////////
344 /// create timer which will invoke ProcessRequests() function periodically
345 /// Timer is required to perform all actions in main ROOT thread
346 /// Method arguments are the same as for TTimer constructor
347 /// By default, sync timer with 100 ms period is created
348 ///
349 /// If milliSec == 0, no timer will be created.
350 /// In this case application should regularly call ProcessRequests() method.
351 
352 void THttpServer::SetTimer(Long_t milliSec, Bool_t mode)
353 {
354  if (fTimer) {
355  fTimer->Stop();
356  delete fTimer;
357  fTimer = 0;
358  }
359  if (milliSec > 0) {
360  fTimer = new THttpTimer(milliSec, mode, this);
361  fTimer->TurnOn();
362  }
363 }
364 
365 ////////////////////////////////////////////////////////////////////////////////
366 /// Checked that filename does not contains relative path below current directory
367 /// Used to prevent access to files below current directory
368 
370 {
371  if ((fname == 0) || (*fname == 0)) return kFALSE;
372 
373  Int_t level = 0;
374 
375  while (*fname != 0) {
376 
377  // find next slash or backslash
378  const char *next = strpbrk(fname, "/\\");
379  if (next == 0) return kTRUE;
380 
381  // most important - change to parent dir
382  if ((next == fname + 2) && (*fname == '.') && (*(fname + 1) == '.')) {
383  fname += 3;
384  level--;
385  if (level < 0) return kFALSE;
386  continue;
387  }
388 
389  // ignore current directory
390  if ((next == fname + 1) && (*fname == '.')) {
391  fname += 2;
392  continue;
393  }
394 
395  // ignore slash at the front
396  if (next == fname) {
397  fname ++;
398  continue;
399  }
400 
401  fname = next + 1;
402  level++;
403  }
404 
405  return kTRUE;
406 }
407 
408 ////////////////////////////////////////////////////////////////////////////////
409 /// Verifies that request is just file name
410 /// File names typically contains prefix like "jsrootsys/"
411 /// If true, method returns real name of the file,
412 /// which should be delivered to the client
413 /// Method is thread safe and can be called from any thread
414 
415 Bool_t THttpServer::IsFileRequested(const char *uri, TString &res) const
416 {
417  if ((uri == 0) || (strlen(uri) == 0)) return kFALSE;
418 
419  TString fname = uri;
420 
421  TIter iter(&fLocations);
422  TObject *obj(0);
423  while ((obj=iter()) != 0) {
424  Ssiz_t pos = fname.Index(obj->GetName());
425  if (pos == kNPOS) continue;
426  fname.Remove(0, pos + (strlen(obj->GetName()) - 1));
427  if (!VerifyFilePath(fname.Data())) return kFALSE;
428  res = obj->GetTitle();
429  if ((fname[0]=='/') && (res[res.Length()-1]=='/')) res.Resize(res.Length()-1);
430  res.Append(fname);
431  return kTRUE;
432  }
433 
434  return kFALSE;
435 }
436 
437 ////////////////////////////////////////////////////////////////////////////////
438 /// Executes http request, specified in THttpCallArg structure
439 /// Method can be called from any thread
440 /// Actual execution will be done in main ROOT thread, where analysis code is running.
441 
443 {
444  if ((fMainThrdId!=0) && (fMainThrdId == TThread::SelfId())) {
445  // should not happen, but one could process requests directly without any signaling
446 
447  ProcessRequest(arg);
448 
449  return kTRUE;
450  }
451 
452  // add call arg to the list
453  fMutex.Lock();
454  fCallArgs.Add(arg);
455  fMutex.UnLock();
456 
457  // and now wait until request is processed
458  arg->fCond.Wait();
459 
460  return kTRUE;
461 }
462 
463 ////////////////////////////////////////////////////////////////////////////////
464 /// Process requests, submitted for execution
465 /// Regularly invoked by THttpTimer, when somewhere in the code
466 /// gSystem->ProcessEvents() is called.
467 /// User can call serv->ProcessRequests() directly, but only from main analysis thread.
468 
470 {
471  if (fMainThrdId==0) fMainThrdId = TThread::SelfId();
472 
473  if (fMainThrdId != TThread::SelfId()) {
474  Error("ProcessRequests", "Should be called only from main ROOT thread");
475  return;
476  }
477 
478  while (true) {
479  THttpCallArg *arg = 0;
480 
481  fMutex.Lock();
482  if (fCallArgs.GetSize() > 0) {
483  arg = (THttpCallArg *) fCallArgs.First();
484  fCallArgs.RemoveFirst();
485  }
486  fMutex.UnLock();
487 
488  if (arg == 0) break;
489 
490  fSniffer->SetCurrentCallArg(arg);
491 
492  try {
493  ProcessRequest(arg);
494  fSniffer->SetCurrentCallArg(0);
495  } catch (...) {
496  fSniffer->SetCurrentCallArg(0);
497  }
498 
499  arg->fCond.Signal();
500  }
501 
502  // regularly call Process() method of engine to let perform actions in ROOT context
503  TIter iter(&fEngines);
504  THttpEngine *engine = 0;
505  while ((engine = (THttpEngine *)iter()) != 0)
506  engine->Process();
507 }
508 
509 ////////////////////////////////////////////////////////////////////////////////
510 /// Process single http request
511 /// Depending from requested path and filename different actions will be performed.
512 /// In most cases information is provided by TRootSniffer class
513 
515 {
516 
517  if (arg->fFileName.IsNull() || (arg->fFileName == "index.htm")) {
518 
519  if (fDefaultPageCont.Length() == 0) {
520  Int_t len = 0;
521  char *buf = ReadFileContent(fDefaultPage.Data(), len);
522  if (len > 0) fDefaultPageCont.Append(buf, len);
523  delete buf;
524  }
525 
526  if (fDefaultPageCont.Length() == 0) {
527  arg->Set404();
528  } else {
529  arg->fContent = fDefaultPageCont;
530 
531  // replace all references on JSROOT
532  if (fJSROOT.Length() > 0) {
533  TString repl = TString("=\"") + fJSROOT;
534  if (!repl.EndsWith("/")) repl+="/";
535  arg->fContent.ReplaceAll("=\"jsrootsys/", repl);
536  }
537 
538  const char *hjsontag = "\"$$$h.json$$$\"";
539 
540  // add h.json caching
541  if (arg->fContent.Index(hjsontag) != kNPOS) {
542  TString h_json;
543  TRootSnifferStoreJson store(h_json, kTRUE);
544  const char *topname = fTopName.Data();
545  if (arg->fTopName.Length() > 0) topname = arg->fTopName.Data();
546  fSniffer->ScanHierarchy(topname, arg->fPathName.Data(), &store);
547 
548  arg->fContent.ReplaceAll(hjsontag, h_json);
549 
550  arg->AddHeader("Cache-Control", "private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0");
551  if (arg->fQuery.Index("nozip") == kNPOS) arg->SetZipping(2);
552  }
553  arg->SetContentType("text/html");
554  }
555  return;
556  }
557 
558  if (arg->fFileName == "draw.htm") {
559  if (fDrawPageCont.Length() == 0) {
560  Int_t len = 0;
561  char *buf = ReadFileContent(fDrawPage.Data(), len);
562  if (len > 0) fDrawPageCont.Append(buf, len);
563  delete buf;
564  }
565 
566  if (fDrawPageCont.Length() == 0) {
567  arg->Set404();
568  } else {
569  const char *rootjsontag = "\"$$$root.json$$$\"";
570  const char *hjsontag = "\"$$$h.json$$$\"";
571 
572  arg->fContent = fDrawPageCont;
573 
574  // replace all references on JSROOT
575  if (fJSROOT.Length() > 0) {
576  TString repl = TString("=\"") + fJSROOT;
577  if (!repl.EndsWith("/")) repl+="/";
578  arg->fContent.ReplaceAll("=\"jsrootsys/", repl);
579  }
580 
581  if (arg->fContent.Index(hjsontag) != kNPOS) {
582  TString h_json;
583  TRootSnifferStoreJson store(h_json, kTRUE);
584  const char *topname = fTopName.Data();
585  if (arg->fTopName.Length() > 0) topname = arg->fTopName.Data();
586  fSniffer->ScanHierarchy(topname, arg->fPathName.Data(), &store, kTRUE);
587 
588  arg->fContent.ReplaceAll(hjsontag, h_json);
589  }
590 
591  if (arg->fContent.Index(rootjsontag) != kNPOS) {
592  TString str;
593  void *bindata = 0;
594  Long_t bindatalen = 0;
595  if (fSniffer->Produce(arg->fPathName.Data(), "root.json", "compact=3", bindata, bindatalen, str)) {
596  arg->fContent.ReplaceAll(rootjsontag, str);
597  }
598  }
599  arg->AddHeader("Cache-Control", "private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0");
600  if (arg->fQuery.Index("nozip") == kNPOS) arg->SetZipping(2);
601  arg->SetContentType("text/html");
602  }
603  return;
604  }
605 
607  if (IsFileRequested(arg->fFileName.Data(), filename)) {
608  arg->SetFile(filename);
609  return;
610  }
611 
612  filename = arg->fFileName;
613  Bool_t iszip = kFALSE;
614  if (filename.EndsWith(".gz")) {
615  filename.Resize(filename.Length() - 3);
616  iszip = kTRUE;
617  }
618 
619  void* bindata(0);
620  Long_t bindatalen(0);
621 
622  if ((filename == "h.xml") || (filename == "get.xml")) {
623 
624  Bool_t compact = arg->fQuery.Index("compact") != kNPOS;
625 
626  arg->fContent.Form("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
627  if (!compact) arg->fContent.Append("\n");
628  arg->fContent.Append("<root>");
629  if (!compact) arg->fContent.Append("\n");
630  {
631  TRootSnifferStoreXml store(arg->fContent, compact);
632 
633  const char *topname = fTopName.Data();
634  if (arg->fTopName.Length() > 0) topname = arg->fTopName.Data();
635  fSniffer->ScanHierarchy(topname, arg->fPathName.Data(), &store, filename == "get.xml");
636  }
637 
638  arg->fContent.Append("</root>");
639  if (!compact) arg->fContent.Append("\n");
640 
641  arg->SetXml();
642  } else
643 
644  if (filename == "h.json") {
645  TRootSnifferStoreJson store(arg->fContent, arg->fQuery.Index("compact") != kNPOS);
646  const char *topname = fTopName.Data();
647  if (arg->fTopName.Length() > 0) topname = arg->fTopName.Data();
648  fSniffer->ScanHierarchy(topname, arg->fPathName.Data(), &store);
649  arg->SetJson();
650  } else
651 
652  if (fSniffer->Produce(arg->fPathName.Data(), filename.Data(), arg->fQuery.Data(), bindata, bindatalen, arg->fContent)) {
653  if (bindata != 0) arg->SetBinData(bindata, bindatalen);
654 
655  // define content type base on extension
656  arg->SetContentType(GetMimeType(filename.Data()));
657  } else {
658  // request is not processed
659  arg->Set404();
660  }
661 
662  if (arg->Is404()) return;
663 
664  if (iszip) arg->SetZipping(3);
665 
666  if (filename == "root.bin") {
667  // only for binary data master version is important
668  // it allows to detect if streamer info was modified
669  const char *parname = fSniffer->IsStreamerInfoItem(arg->fPathName.Data()) ? "BVersion" : "MVersion";
670  arg->AddHeader(parname, Form("%u", (unsigned) fSniffer->GetStreamerInfoHash()));
671  }
672 
673  // try to avoid caching on the browser
674  arg->AddHeader("Cache-Control", "private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0");
675 }
676 
677 ////////////////////////////////////////////////////////////////////////////////
678 /// Register object in folders hierarchy
679 ///
680 /// See TRootSniffer::RegisterObject() for more details
681 
682 Bool_t THttpServer::Register(const char *subfolder, TObject *obj)
683 {
684  return fSniffer->RegisterObject(subfolder, obj);
685 }
686 
687 ////////////////////////////////////////////////////////////////////////////////
688 /// Unregister object in folders hierarchy
689 ///
690 /// See TRootSniffer::UnregisterObject() for more details
691 
693 {
694  return fSniffer->UnregisterObject(obj);
695 }
696 
697 ////////////////////////////////////////////////////////////////////////////////
698 /// Restrict access to specified object
699 ///
700 /// See TRootSniffer::Restrict() for more details
701 
702 void THttpServer::Restrict(const char *path, const char* options)
703 {
704  fSniffer->Restrict(path, options);
705 }
706 
707 ////////////////////////////////////////////////////////////////////////////////
708 /// Register command which can be executed from web interface
709 ///
710 /// As method one typically specifies string, which is executed with
711 /// gROOT->ProcessLine() method. For instance
712 /// serv->RegisterCommand("Invoke","InvokeFunction()");
713 ///
714 /// Or one could specify any method of the object which is already registered
715 /// to the server. For instance:
716 /// serv->Register("/", hpx);
717 /// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()");
718 /// Here symbols '/->' separates item name from method to be executed
719 ///
720 /// One could specify additional arguments in the command with
721 /// syntax like %arg1%, %arg2% and so on. For example:
722 /// serv->RegisterCommand("/ResetHPX", "/hpx/->SetTitle(\"%arg1%\")");
723 /// serv->RegisterCommand("/RebinHPXPY", "/hpxpy/->Rebin2D(%arg1%,%arg2%)");
724 /// Such parameter(s) will be requested when command clicked in the browser.
725 ///
726 /// Once command is registered, one could specify icon which will appear in the browser:
727 /// serv->SetIcon("/ResetHPX", "rootsys/icons/ed_execute.png");
728 ///
729 /// One also can set extra property '_fastcmd', that command appear as
730 /// tool button on the top of the browser tree:
731 /// serv->SetItemField("/ResetHPX", "_fastcmd", "true");
732 /// Or it is equivalent to specifying extra argument when register command:
733 /// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()", "button;rootsys/icons/ed_delete.png");
734 
735 Bool_t THttpServer::RegisterCommand(const char *cmdname, const char *method, const char *icon)
736 {
737  return fSniffer->RegisterCommand(cmdname, method, icon);
738 }
739 
740 ////////////////////////////////////////////////////////////////////////////////
741 /// hides folder or element from web gui
742 
743 Bool_t THttpServer::Hide(const char *foldername, Bool_t hide)
744 {
745  return SetItemField(foldername, "_hidden", hide ? "true" : (const char *) 0);
746 }
747 
748 ////////////////////////////////////////////////////////////////////////////////
749 /// set name of icon, used in browser together with the item
750 ///
751 /// One could use images from $ROOTSYS directory like:
752 /// serv->SetIcon("/ResetHPX","/rootsys/icons/ed_execute.png");
753 
754 Bool_t THttpServer::SetIcon(const char *fullname, const char *iconname)
755 {
756  return SetItemField(fullname, "_icon", iconname);
757 }
758 
759 ////////////////////////////////////////////////////////////////////////////////
760 
761 Bool_t THttpServer::CreateItem(const char *fullname, const char *title)
762 {
763  return fSniffer->CreateItem(fullname, title);
764 }
765 
766 ////////////////////////////////////////////////////////////////////////////////
767 
768 Bool_t THttpServer::SetItemField(const char *fullname, const char *name, const char *value)
769 {
770  return fSniffer->SetItemField(fullname, name, value);
771 }
772 
773 ////////////////////////////////////////////////////////////////////////////////
774 
775 const char *THttpServer::GetItemField(const char *fullname, const char *name)
776 {
777  return fSniffer->GetItemField(fullname, name);
778 }
779 
780 ////////////////////////////////////////////////////////////////////////////////
781 /// Returns MIME type base on file extension
782 
783 const char *THttpServer::GetMimeType(const char *path)
784 {
785  static const struct {
786  const char *extension;
787  int ext_len;
788  const char *mime_type;
789  } builtin_mime_types[] = {
790  {".xml", 4, "text/xml"},
791  {".json", 5, "application/json"},
792  {".bin", 4, "application/x-binary"},
793  {".gif", 4, "image/gif"},
794  {".jpg", 4, "image/jpeg"},
795  {".png", 4, "image/png"},
796  {".html", 5, "text/html"},
797  {".htm", 4, "text/html"},
798  {".shtm", 5, "text/html"},
799  {".shtml", 6, "text/html"},
800  {".css", 4, "text/css"},
801  {".js", 3, "application/x-javascript"},
802  {".ico", 4, "image/x-icon"},
803  {".jpeg", 5, "image/jpeg"},
804  {".svg", 4, "image/svg+xml"},
805  {".txt", 4, "text/plain"},
806  {".torrent", 8, "application/x-bittorrent"},
807  {".wav", 4, "audio/x-wav"},
808  {".mp3", 4, "audio/x-mp3"},
809  {".mid", 4, "audio/mid"},
810  {".m3u", 4, "audio/x-mpegurl"},
811  {".ogg", 4, "application/ogg"},
812  {".ram", 4, "audio/x-pn-realaudio"},
813  {".xslt", 5, "application/xml"},
814  {".xsl", 4, "application/xml"},
815  {".ra", 3, "audio/x-pn-realaudio"},
816  {".doc", 4, "application/msword"},
817  {".exe", 4, "application/octet-stream"},
818  {".zip", 4, "application/x-zip-compressed"},
819  {".xls", 4, "application/excel"},
820  {".tgz", 4, "application/x-tar-gz"},
821  {".tar", 4, "application/x-tar"},
822  {".gz", 3, "application/x-gunzip"},
823  {".arj", 4, "application/x-arj-compressed"},
824  {".rar", 4, "application/x-arj-compressed"},
825  {".rtf", 4, "application/rtf"},
826  {".pdf", 4, "application/pdf"},
827  {".swf", 4, "application/x-shockwave-flash"},
828  {".mpg", 4, "video/mpeg"},
829  {".webm", 5, "video/webm"},
830  {".mpeg", 5, "video/mpeg"},
831  {".mov", 4, "video/quicktime"},
832  {".mp4", 4, "video/mp4"},
833  {".m4v", 4, "video/x-m4v"},
834  {".asf", 4, "video/x-ms-asf"},
835  {".avi", 4, "video/x-msvideo"},
836  {".bmp", 4, "image/bmp"},
837  {".ttf", 4, "application/x-font-ttf"},
838  {NULL, 0, NULL}
839  };
840 
841  int path_len = strlen(path);
842 
843  for (int i = 0; builtin_mime_types[i].extension != NULL; i++) {
844  if (path_len <= builtin_mime_types[i].ext_len) continue;
845  const char *ext = path + (path_len - builtin_mime_types[i].ext_len);
846  if (strcmp(ext, builtin_mime_types[i].extension) == 0) {
847  return builtin_mime_types[i].mime_type;
848  }
849  }
850 
851  return "text/plain";
852 }
853 
854 ////////////////////////////////////////////////////////////////////////////////
855 /// reads file content
856 
858 {
859  len = 0;
860 
861  std::ifstream is(filename);
862  if (!is) return 0;
863 
864  is.seekg(0, is.end);
865  len = is.tellg();
866  is.seekg(0, is.beg);
867 
868  char *buf = (char *) malloc(len);
869  is.read(buf, len);
870  if (!is) {
871  free(buf);
872  len = 0;
873  return 0;
874  }
875 
876  return buf;
877 }
void SetZipping(Int_t kind)
Definition: THttpCallArg.h:273
An array of TObjects.
Definition: TObjArray.h:39
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
const char * mime_type
Definition: civetweb.c:2469
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 IsReadOnly() const
returns read-only mode
static const char * filename()
#define gROOT
Definition: TROOT.h:352
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:582
TString fQuery
authenticated user name (if any)
Definition: THttpCallArg.h:32
Basic string class.
Definition: TString.h:137
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kFALSE
Definition: Rtypes.h:92
static const TString & GetRootSys()
Get the rootsys directory in the installation. Static utility function.
Definition: TROOT.cxx:2517
TObject * At(Int_t idx) const
Definition: TObjArray.h:167
void SetServer(THttpServer *serv)
Definition: THttpEngine.h:21
void SetContentType(const char *typ)
Definition: THttpCallArg.h:203
void ProcessRequests()
Process submitted requests, must be called from main thread.
Bool_t CreateItem(const char *fullname, const char *title)
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
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:33
virtual const char * Getenv(const char *env)
Get environment variable.
Definition: TSystem.cxx:1626
TString fPathName
request method like GET or POST
Definition: THttpCallArg.h:29
TString & Append(const char *cs)
Definition: TString.h:492
Bool_t EndsWith(const char *pat, ECaseCompare cmp=kExact) const
Return true if string ends with the specified string.
Definition: TString.cxx:2220
std::vector< std::vector< double > > Data
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...
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
Int_t GetLast() const
Return index of last object in array.
Definition: TObjArray.cxx:527
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
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
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:918
char * Form(const char *fmt,...)
Ssiz_t Length() const
Definition: TString.h:390
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
void SetSniffer(TRootSniffer *sniff)
Set TRootSniffer to the server Server takes ownership over sniffer.
Bool_t ExecuteHttp(THttpCallArg *arg)
Execute HTTP request.
const char * extension
Definition: civetweb.c:2467
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 ...
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition: TString.cxx:2240
Bool_t Hide(const char *fullname, Bool_t hide=kTRUE)
hides folder or element from web gui
#define ClassImp(name)
Definition: Rtypes.h:279
virtual void ProcessRequest(THttpCallArg *arg)
submitted arguments
static const TString & GetEtcDir()
Get the sysconfig directory in the installation. Static utility function.
Definition: TROOT.cxx:2601
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
Bool_t IsNull() const
Definition: TString.h:387
#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 const char * GetTitle() const
Returns title of object.
Definition: TObject.cxx:459
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.
const Ssiz_t kNPOS
Definition: Rtypes.h:115
static const struct @201 builtin_mime_types[]
Bool_t Is404() const
Definition: THttpCallArg.h:306
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
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:1242
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:415
const Bool_t kTRUE
Definition: Rtypes.h:91
virtual void SetTitle(const char *title="")
Change (i.e. set) the title of the TNamed.
Definition: TNamed.cxx:152
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)
Bool_t IsFileRequested(const char *uri, TString &res) const
Check if file is requested, thread safe.
void Restrict(const char *path, const char *options)
Restrict access to specified object.
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:904
void Resize(Ssiz_t n)
Resize the string. Truncate or add blanks as necessary.
Definition: TString.cxx:1058
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
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)
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4672
const char * Data() const
Definition: TString.h:349