Logo ROOT   6.12/07
Reference Guide
THttpServer.cxx
Go to the documentation of this file.
1 // $Id$
2 // Author: Sergey Linev 21/12/2013
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2013, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "THttpServer.h"
13 
14 #include "TThread.h"
15 #include "TTimer.h"
16 #include "TSystem.h"
17 #include "TImage.h"
18 #include "TROOT.h"
19 #include "TUrl.h"
20 #include "TClass.h"
21 #include "TCanvas.h"
22 #include "TFolder.h"
23 #include "RVersion.h"
24 #include "RConfigure.h"
25 #include "TRegexp.h"
26 
27 #include "THttpEngine.h"
28 #include "THttpWSEngine.h"
29 #include "THttpWSHandler.h"
30 #include "TRootSniffer.h"
31 #include "TRootSnifferStore.h"
32 
33 #include <string>
34 #include <cstdlib>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <fstream>
38 
39 ////////////////////////////////////////////////////////////////////////////////
40 
41 //////////////////////////////////////////////////////////////////////////
42 // //
43 // THttpTimer //
44 // //
45 // Specialized timer for THttpServer //
46 // Provides regular calls of THttpServer::ProcessRequests() method //
47 // //
48 //////////////////////////////////////////////////////////////////////////
49 
50 class THttpTimer : public TTimer {
51 public:
52  THttpServer *fServer; //!
53 
54  THttpTimer(Long_t milliSec, Bool_t mode, THttpServer *serv) : TTimer(milliSec, mode), fServer(serv)
55  {
56  // construtor
57  }
58 
59  virtual ~THttpTimer()
60  {
61  // destructor
62  }
63 
64  virtual void Timeout()
65  {
66  // timeout handler
67  // used to process http requests in main ROOT thread
68 
69  if (fServer)
70  fServer->ProcessRequests();
71  }
72 };
73 
74 //////////////////////////////////////////////////////////////////////////////////////////////////
75 
76 //////////////////////////////////////////////////////////////////////////
77 // //
78 // TLongPollEngine //
79 // //
80 // Emulation of websocket with long poll requests //
81 // Allows to send data from server to client without explicit request //
82 // //
83 //////////////////////////////////////////////////////////////////////////
84 
85 class TLongPollEngine : public THttpWSEngine {
86 protected:
87  THttpCallArg *fPoll; ///< polling request, which can be used for the next sending
88  TString fBuf; ///< single entry to keep data which is not yet send to the client
89 
90 public:
91  TLongPollEngine(const char *name, const char *title) : THttpWSEngine(name, title), fPoll(0), fBuf() {}
92 
93  virtual ~TLongPollEngine() {}
94 
95  virtual UInt_t GetId() const
96  {
97  const void *ptr = (const void *)this;
98  return TString::Hash((void *)&ptr, sizeof(void *));
99  }
100 
101  virtual void ClearHandle()
102  {
103  if (fPoll) {
104  fPoll->Set404();
105  fPoll->NotifyCondition();
106  fPoll = 0;
107  }
108  }
109 
110  virtual void Send(const void * /*buf*/, int /*len*/)
111  {
112  Error("TLongPollEngine::Send", "Should never be called, only text is supported");
113  }
114 
115  virtual void SendCharStar(const char *buf)
116  {
117  if (fPoll) {
118  fPoll->SetContentType("text/plain");
119  fPoll->SetContent(buf);
120  fPoll->NotifyCondition();
121  fPoll = 0;
122  } else if (fBuf.Length() == 0) {
123  fBuf = buf;
124  } else {
125  Error("TLongPollEngine::SendCharStar", "Too many send operations, use TList object instead");
126  }
127  }
128 
129  virtual Bool_t PreviewData(THttpCallArg *arg)
130  {
131  // function called in the user code before processing correspondent websocket data
132  // returns kTRUE when user should ignore such http request - it is for internal use
133 
134  // this is normal request, deliver and process it as any other
135  if (!strstr(arg->GetQuery(), "&dummy"))
136  return kFALSE;
137 
138  if (arg == fPoll) {
139  Error("PreviewData", "NEVER SHOULD HAPPEN");
140  exit(12);
141  }
142 
143  if (fPoll) {
144  Info("PreviewData", "Get dummy request when previous not completed");
145  // if there are pending request, reply it immediately
146  fPoll->SetContentType("text/plain");
147  fPoll->SetContent("<<nope>>"); // normally should never happen
148  fPoll->NotifyCondition();
149  fPoll = 0;
150  }
151 
152  if (fBuf.Length() > 0) {
153  arg->SetContentType("text/plain");
154  arg->SetContent(fBuf.Data());
155  fBuf = "";
156  } else {
157  arg->SetPostponed();
158  fPoll = arg;
159  }
160 
161  // if arguments has "&dummy" string, user should not process it
162  return kTRUE;
163  }
164 };
165 
166 // =======================================================
167 
168 //////////////////////////////////////////////////////////////////////////
169 // //
170 // THttpServer //
171 // //
172 // Online http server for arbitrary ROOT application //
173 // //
174 // Idea of THttpServer - provide remote http access to running //
175 // ROOT application and enable HTML/JavaScript user interface. //
176 // Any registered object can be requested and displayed in the browser. //
177 // There are many benefits of such approach: //
178 // * standard http interface to ROOT application //
179 // * no any temporary ROOT files when access data //
180 // * user interface running in all browsers //
181 // //
182 // Starting HTTP server //
183 // //
184 // To start http server, at any time create instance //
185 // of the THttpServer class like: //
186 // serv = new THttpServer("http:8080"); //
187 // //
188 // This will starts civetweb-based http server with http port 8080. //
189 // Than one should be able to open address "http://localhost:8080" //
190 // in any modern browser (IE, Firefox, Chrome) and browse objects, //
191 // created in application. By default, server can access files, //
192 // canvases and histograms via gROOT pointer. All such objects //
193 // can be displayed with JSROOT graphics. //
194 // //
195 // At any time one could register other objects with the command: //
196 // //
197 // TGraph* gr = new TGraph(10); //
198 // gr->SetName("gr1"); //
199 // serv->Register("graphs/subfolder", gr); //
200 // //
201 // If objects content is changing in the application, one could //
202 // enable monitoring flag in the browser - than objects view //
203 // will be regularly updated. //
204 // //
205 // More information: https://root.cern/root/htmldoc/guides/HttpServer/HttpServer.html //
206 // //
207 //////////////////////////////////////////////////////////////////////////
208 
210 
211 ////////////////////////////////////////////////////////////////////////////////
212 /// constructor
213 ///
214 /// As argument, one specifies engine kind which should be
215 /// created like "http:8080". One could specify several engines
216 /// at once, separating them with semicolon (";"). Following engines are supported:
217 ///
218 /// http - TCivetweb, civetweb-based implementation of http protocol
219 /// fastcgi - TFastCgi, special protocol for communicating with web servers
220 ///
221 /// For each created engine one should provide socket port number like "http:8080" or "fastcgi:9000".
222 /// Additional engine-specific options can be supplied with URL syntax like "http:8080?thrds=10".
223 /// Full list of supported options should be checked in engines docu.
224 ///
225 /// One also can configure following options, separated by semicolon:
226 ///
227 /// readonly, ro - set read-only mode (default)
228 /// readwrite, rw - allows methods execution of registered objects
229 /// global - scans global ROOT lists for existing objects (default)
230 /// noglobal - disable scan of global lists
231 /// cors - enable CORS header with origin="*"
232 /// cors=domain - enable CORS header with origin="domain"
233 ///
234 /// For example, create http server, which allows cors headers and disable scan of global lists,
235 /// one should provide "http:8080;cors;noglobal" as parameter
236 ///
237 /// THttpServer uses JavaScript ROOT (https://root.cern/js) to implement web clients UI.
238 /// Normally JSROOT sources are used from $ROOTSYS/etc/http directory,
239 /// but one could set JSROOTSYS shell variable to specify alternative location
240 
241 THttpServer::THttpServer(const char *engine)
242  : TNamed("http", "ROOT http server"), fEngines(), fTimer(0), fSniffer(0), fMainThrdId(0), fJSROOTSYS(),
243  fTopName("ROOT"), fJSROOT(), fLocations(), fDefaultPage(), fDefaultPageCont(), fDrawPage(), fDrawPageCont(),
244  fCallArgs()
245 {
247 
248 #ifdef COMPILED_WITH_DABC
249  const char *dabcsys = gSystem->Getenv("DABCSYS");
250  if (dabcsys != 0)
251  fJSROOTSYS = TString::Format("%s/plugins/root/js", dabcsys);
252 #endif
253 
254  const char *jsrootsys = gSystem->Getenv("JSROOTSYS");
255  if (jsrootsys != 0)
256  fJSROOTSYS = jsrootsys;
257 
258  if (fJSROOTSYS.Length() == 0) {
259  TString jsdir = TString::Format("%s/http", TROOT::GetEtcDir().Data());
260  if (gSystem->ExpandPathName(jsdir)) {
261  Warning("THttpServer", "problems resolving '%s', use JSROOTSYS to specify $ROOTSYS/etc/http location",
262  jsdir.Data());
263  fJSROOTSYS = ".";
264  } else {
265  fJSROOTSYS = jsdir;
266  }
267  }
268 
269  AddLocation("currentdir/", ".");
270  AddLocation("jsrootsys/", fJSROOTSYS);
271  AddLocation("rootsys/", TROOT::GetRootSys());
272 
273  fDefaultPage = fJSROOTSYS + "/files/online.htm";
274  fDrawPage = fJSROOTSYS + "/files/draw.htm";
275 
276  SetSniffer(new TRootSniffer("sniff"));
277 
278  // start timer
279  SetTimer(20, kTRUE);
280 
281  if (strchr(engine, ';') == 0) {
282  CreateEngine(engine);
283  } else {
284  TObjArray *lst = TString(engine).Tokenize(";");
285 
286  for (Int_t n = 0; n <= lst->GetLast(); n++) {
287  const char *opt = lst->At(n)->GetName();
288  if ((strcmp(opt, "readonly") == 0) || (strcmp(opt, "ro") == 0)) {
290  } else if ((strcmp(opt, "readwrite") == 0) || (strcmp(opt, "rw") == 0)) {
292  } else if (strcmp(opt, "global") == 0) {
294  } else if (strcmp(opt, "noglobal") == 0) {
296  } else if (strncmp(opt, "cors=", 5) == 0) {
297  SetCors(opt + 5);
298  } else if (strcmp(opt, "cors") == 0) {
299  SetCors("*");
300  } else
301  CreateEngine(opt);
302  }
303 
304  delete lst;
305  }
306 }
307 
308 ////////////////////////////////////////////////////////////////////////////////
309 /// destructor
310 /// delete all http engines and sniffer
311 
313 {
314  fEngines.Delete();
315 
316  SetSniffer(0);
317 
318  SetTimer(0);
319 }
320 
321 ////////////////////////////////////////////////////////////////////////////////
322 /// Set TRootSniffer to the server
323 /// Server takes ownership over sniffer
324 
326 {
327  if (fSniffer)
328  delete fSniffer;
329  fSniffer = sniff;
330 }
331 
332 ////////////////////////////////////////////////////////////////////////////////
333 /// returns read-only mode
334 
336 {
337  return fSniffer ? fSniffer->IsReadOnly() : kTRUE;
338 }
339 
340 ////////////////////////////////////////////////////////////////////////////////
341 /// Set read-only mode for the server (default on)
342 /// In read-only server is not allowed to change any ROOT object, registered to the server
343 /// Server also cannot execute objects method via exe.json request
344 
346 {
347  if (fSniffer)
348  fSniffer->SetReadOnly(readonly);
349 }
350 
351 ////////////////////////////////////////////////////////////////////////////////
352 /// add files location, which could be used in the server
353 /// one could map some system folder to the server like AddLocation("mydir/","/home/user/specials");
354 /// Than files from this directory could be addressed via server like
355 /// http://localhost:8080/mydir/myfile.root
356 
357 void THttpServer::AddLocation(const char *prefix, const char *path)
358 {
359  if ((prefix == 0) || (*prefix == 0))
360  return;
361 
362  TNamed *obj = dynamic_cast<TNamed *>(fLocations.FindObject(prefix));
363  if (obj != 0) {
364  obj->SetTitle(path);
365  } else {
366  fLocations.Add(new TNamed(prefix, path));
367  }
368 }
369 
370 ////////////////////////////////////////////////////////////////////////////////
371 /// Set location of JSROOT to use with the server
372 /// One could specify address like:
373 /// https://root.cern.ch/js/3.3/
374 /// http://web-docs.gsi.de/~linev/js/3.3/
375 /// This allows to get new JSROOT features with old server,
376 /// reduce load on THttpServer instance, also startup time can be improved
377 /// When empty string specified (default), local copy of JSROOT is used (distributed with ROOT)
378 
379 void THttpServer::SetJSROOT(const char *location)
380 {
381  fJSROOT = location ? location : "";
382 }
383 
384 ////////////////////////////////////////////////////////////////////////////////
385 /// Set file name of HTML page, delivered by the server when
386 /// http address is opened in the browser.
387 /// By default, $ROOTSYS/etc/http/files/online.htm page is used
388 /// When empty filename is specified, default page will be used
389 
390 void THttpServer::SetDefaultPage(const char *filename)
391 {
392  if ((filename != 0) && (*filename != 0))
393  fDefaultPage = filename;
394  else
395  fDefaultPage = fJSROOTSYS + "/files/online.htm";
396 
397  // force to read page content next time again
399 }
400 
401 ////////////////////////////////////////////////////////////////////////////////
402 /// Set file name of HTML page, delivered by the server when
403 /// objects drawing page is requested from the browser
404 /// By default, $ROOTSYS/etc/http/files/draw.htm page is used
405 /// When empty filename is specified, default page will be used
406 
407 void THttpServer::SetDrawPage(const char *filename)
408 {
409  if ((filename != 0) && (*filename != 0))
410  fDrawPage = filename;
411  else
412  fDrawPage = fJSROOTSYS + "/files/draw.htm";
413 
414  // force to read page content next time again
416 }
417 
418 ////////////////////////////////////////////////////////////////////////////////
419 /// factory method to create different http engines
420 /// At the moment two engine kinds are supported:
421 /// civetweb (default) and fastcgi
422 /// Examples:
423 /// "http:8080" or "civetweb:8080" or ":8080" - creates civetweb web server with http port 8080
424 /// "fastcgi:9000" - creates fastcgi server with port 9000
425 /// One could apply additional parameters, using URL syntax:
426 /// "http:8080?thrds=10"
427 
429 {
430  if (engine == 0)
431  return kFALSE;
432 
433  const char *arg = strchr(engine, ':');
434  if (arg == 0)
435  return kFALSE;
436 
437  TString clname;
438  if (arg != engine)
439  clname.Append(engine, arg - engine);
440 
441  if ((clname.Length() == 0) || (clname == "http") || (clname == "civetweb"))
442  clname = "TCivetweb";
443  else if (clname == "fastcgi")
444  clname = "TFastCgi";
445  else if (clname == "dabc")
446  clname = "TDabcEngine";
447 
448  // ensure that required engine class exists before we try to create it
449  TClass *engine_class = gROOT->LoadClass(clname.Data());
450  if (engine_class == 0)
451  return kFALSE;
452 
453  THttpEngine *eng = (THttpEngine *)engine_class->New();
454  if (eng == 0)
455  return kFALSE;
456 
457  eng->SetServer(this);
458 
459  if (!eng->Create(arg + 1)) {
460  delete eng;
461  return kFALSE;
462  }
463 
464  fEngines.Add(eng);
465 
466  return kTRUE;
467 }
468 
469 ////////////////////////////////////////////////////////////////////////////////
470 /// create timer which will invoke ProcessRequests() function periodically
471 /// Timer is required to perform all actions in main ROOT thread
472 /// Method arguments are the same as for TTimer constructor
473 /// By default, sync timer with 100 ms period is created
474 ///
475 /// It is recommended to always use sync timer mode and only change period to
476 /// adjust server reaction time. Use of async timer requires, that application regularly
477 /// calls gSystem->ProcessEvents(). It happens automatically in ROOT interactive shell.
478 /// If milliSec == 0, no timer will be created.
479 /// In this case application should regularly call ProcessRequests() method.
480 ///
481 /// Async timer allows to use THttpServer in applications, which does not have explicit
482 /// gSystem->ProcessEvents() calls. But be aware, that such timer can interrupt any system call
483 /// (lise malloc) and can lead to dead locks, especially in multi-threaded applications.
484 
485 void THttpServer::SetTimer(Long_t milliSec, Bool_t mode)
486 {
487  if (fTimer) {
488  fTimer->Stop();
489  delete fTimer;
490  fTimer = 0;
491  }
492  if (milliSec > 0) {
493  fTimer = new THttpTimer(milliSec, mode, this);
494  fTimer->TurnOn();
495  }
496 }
497 
498 ////////////////////////////////////////////////////////////////////////////////
499 /// Checked that filename does not contains relative path below current directory
500 /// Used to prevent access to files below current directory
501 
503 {
504  if ((fname == 0) || (*fname == 0))
505  return kFALSE;
506 
507  Int_t level = 0;
508 
509  while (*fname != 0) {
510 
511  // find next slash or backslash
512  const char *next = strpbrk(fname, "/\\");
513  if (next == 0)
514  return kTRUE;
515 
516  // most important - change to parent dir
517  if ((next == fname + 2) && (*fname == '.') && (*(fname + 1) == '.')) {
518  fname += 3;
519  level--;
520  if (level < 0)
521  return kFALSE;
522  continue;
523  }
524 
525  // ignore current directory
526  if ((next == fname + 1) && (*fname == '.')) {
527  fname += 2;
528  continue;
529  }
530 
531  // ignore slash at the front
532  if (next == fname) {
533  fname++;
534  continue;
535  }
536 
537  fname = next + 1;
538  level++;
539  }
540 
541  return kTRUE;
542 }
543 
544 ////////////////////////////////////////////////////////////////////////////////
545 /// Verifies that request is just file name
546 /// File names typically contains prefix like "jsrootsys/"
547 /// If true, method returns real name of the file,
548 /// which should be delivered to the client
549 /// Method is thread safe and can be called from any thread
550 
551 Bool_t THttpServer::IsFileRequested(const char *uri, TString &res) const
552 {
553  if ((uri == 0) || (strlen(uri) == 0))
554  return kFALSE;
555 
556  TString fname(uri);
557  TIter iter(&fLocations);
558  TObject *obj(0);
559  while ((obj = iter()) != 0) {
560  Ssiz_t pos = fname.Index(obj->GetName());
561  if (pos == kNPOS)
562  continue;
563  fname.Remove(0, pos + (strlen(obj->GetName()) - 1));
564  if (!VerifyFilePath(fname.Data()))
565  return kFALSE;
566  res = obj->GetTitle();
567  if ((fname[0] == '/') && (res[res.Length() - 1] == '/'))
568  res.Resize(res.Length() - 1);
569  res.Append(fname);
570  return kTRUE;
571  }
572 
573  return kFALSE;
574 }
575 
576 ////////////////////////////////////////////////////////////////////////////////
577 /// Executes http request, specified in THttpCallArg structure
578 /// Method can be called from any thread
579 /// Actual execution will be done in main ROOT thread, where analysis code is running.
580 
582 {
583  if ((fMainThrdId != 0) && (fMainThrdId == TThread::SelfId())) {
584  // should not happen, but one could process requests directly without any signaling
585 
586  ProcessRequest(arg);
587 
588  return kTRUE;
589  }
590 
591  // add call arg to the list
592  std::unique_lock<std::mutex> lk(fMutex);
593  fCallArgs.Add(arg);
594  // and now wait until request is processed
595  arg->fCond.wait(lk);
596 
597  return kTRUE;
598 }
599 
600 ////////////////////////////////////////////////////////////////////////////////
601 /// Submit http request, specified in THttpCallArg structure
602 /// Contrary to ExecuteHttp, it will not block calling thread.
603 /// User should reimplement THttpCallArg::HttpReplied() method
604 /// to react when HTTP request is executed.
605 /// Method can be called from any thread
606 /// Actual execution will be done in main ROOT thread, where analysis code is running.
607 /// When called from main thread and can_run_immediately==kTRUE, will be
608 /// executed immediately. Returns kTRUE when was executed.
609 
611 {
612  if (can_run_immediately && (fMainThrdId != 0) && (fMainThrdId == TThread::SelfId())) {
613  ProcessRequest(arg);
614  return kTRUE;
615  }
616 
617  // add call arg to the list
618  std::unique_lock<std::mutex> lk(fMutex);
619  fCallArgs.Add(arg);
620  return kFALSE;
621 }
622 
623 ////////////////////////////////////////////////////////////////////////////////
624 /// Process requests, submitted for execution
625 /// Regularly invoked by THttpTimer, when somewhere in the code
626 /// gSystem->ProcessEvents() is called.
627 /// User can call serv->ProcessRequests() directly, but only from main analysis thread.
628 
630 {
631  if (fMainThrdId == 0)
633 
634  if (fMainThrdId != TThread::SelfId()) {
635  Error("ProcessRequests", "Should be called only from main ROOT thread");
636  return;
637  }
638 
639  std::unique_lock<std::mutex> lk(fMutex, std::defer_lock);
640  while (true) {
641  THttpCallArg *arg = 0;
642 
643  lk.lock();
644  if (fCallArgs.GetSize() > 0) {
645  arg = (THttpCallArg *)fCallArgs.First();
647  }
648  lk.unlock();
649 
650  if (arg == 0)
651  break;
652 
654 
655  try {
656  ProcessRequest(arg);
658  } catch (...) {
660  }
661 
662  // workaround for longpoll handle, it sometime notifies condition before server
663  if (!arg->fNotifyFlag)
664  arg->NotifyCondition();
665  }
666 
667  // regularly call Process() method of engine to let perform actions in ROOT context
668  TIter iter(&fEngines);
669  THttpEngine *engine = 0;
670  while ((engine = (THttpEngine *)iter()) != 0)
671  engine->Process();
672 }
673 
674 ////////////////////////////////////////////////////////////////////////////////
675 /// Process single http request
676 /// Depending from requested path and filename different actions will be performed.
677 /// In most cases information is provided by TRootSniffer class
678 
680 {
681 
682  if (arg->fFileName.IsNull() || (arg->fFileName == "index.htm")) {
683 
684  THttpWSHandler *handler(0);
685 
686  if (arg->fFileName.IsNull())
687  handler = dynamic_cast<THttpWSHandler *>(fSniffer->FindTObjectInHierarchy(arg->fPathName.Data()));
688 
689  if (handler) {
690 
691  arg->fContent = handler->GetDefaultPageContent();
692 
693  if (arg->fContent.Index("file:")==0) {
694  TString fname = arg->fContent.Data() + 5;
695  arg->fContent.Clear();
696  fname.ReplaceAll("$jsrootsys", fJSROOTSYS);
697 
698  Int_t len(0);
699  char *buf = ReadFileContent(fname.Data(), len);
700  if (len > 0)
701  arg->fContent.Append(buf, len);
702  free(buf);
703  }
704  }
705 
706  if (arg->fContent.Length() == 0) {
707 
708  if (fDefaultPageCont.Length() == 0) {
709  Int_t len = 0;
710  char *buf = ReadFileContent(fDefaultPage.Data(), len);
711  if (len > 0)
712  fDefaultPageCont.Append(buf, len);
713  free(buf);
714  }
715 
716  arg->fContent = fDefaultPageCont;
717  }
718 
719  if (arg->fContent.Length() == 0) {
720  arg->Set404();
721  } else {
722  // replace all references on JSROOT
723  if (fJSROOT.Length() > 0) {
724  TString repl = TString("=\"") + fJSROOT;
725  if (!repl.EndsWith("/"))
726  repl += "/";
727  arg->fContent.ReplaceAll("=\"jsrootsys/", repl);
728  }
729 
730  const char *hjsontag = "\"$$$h.json$$$\"";
731 
732  // add h.json caching
733  if (arg->fContent.Index(hjsontag) != kNPOS) {
734  TString h_json;
735  TRootSnifferStoreJson store(h_json, kTRUE);
736  const char *topname = fTopName.Data();
737  if (arg->fTopName.Length() > 0)
738  topname = arg->fTopName.Data();
739  fSniffer->ScanHierarchy(topname, arg->fPathName.Data(), &store);
740 
741  arg->fContent.ReplaceAll(hjsontag, h_json);
742 
743  arg->AddHeader("Cache-Control",
744  "private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0");
745  if (arg->fQuery.Index("nozip") == kNPOS)
746  arg->SetZipping(2);
747  }
748  arg->SetContentType("text/html");
749  }
750  return;
751  }
752 
753  if (arg->fFileName == "draw.htm") {
754  if (fDrawPageCont.Length() == 0) {
755  Int_t len = 0;
756  char *buf = ReadFileContent(fDrawPage.Data(), len);
757  if (len > 0)
758  fDrawPageCont.Append(buf, len);
759  free(buf);
760  }
761 
762  if (fDrawPageCont.Length() == 0) {
763  arg->Set404();
764  } else {
765  const char *rootjsontag = "\"$$$root.json$$$\"";
766  const char *hjsontag = "\"$$$h.json$$$\"";
767 
768  arg->fContent = fDrawPageCont;
769 
770  // replace all references on JSROOT
771  if (fJSROOT.Length() > 0) {
772  TString repl = TString("=\"") + fJSROOT;
773  if (!repl.EndsWith("/"))
774  repl += "/";
775  arg->fContent.ReplaceAll("=\"jsrootsys/", repl);
776  }
777 
778  if ((arg->fQuery.Index("no_h_json") == kNPOS) && (arg->fQuery.Index("webcanvas") == kNPOS) &&
779  (arg->fContent.Index(hjsontag) != kNPOS)) {
780  TString h_json;
781  TRootSnifferStoreJson store(h_json, kTRUE);
782  const char *topname = fTopName.Data();
783  if (arg->fTopName.Length() > 0)
784  topname = arg->fTopName.Data();
785  fSniffer->ScanHierarchy(topname, arg->fPathName.Data(), &store, kTRUE);
786 
787  arg->fContent.ReplaceAll(hjsontag, h_json);
788  }
789 
790  if ((arg->fQuery.Index("no_root_json") == kNPOS) && (arg->fQuery.Index("webcanvas") == kNPOS) &&
791  (arg->fContent.Index(rootjsontag) != kNPOS)) {
792  TString str;
793  void *bindata = 0;
794  Long_t bindatalen = 0;
795  if (fSniffer->Produce(arg->fPathName.Data(), "root.json", "compact=3", bindata, bindatalen, str)) {
796  arg->fContent.ReplaceAll(rootjsontag, str);
797  }
798  }
799  arg->AddHeader("Cache-Control",
800  "private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0");
801  if (arg->fQuery.Index("nozip") == kNPOS)
802  arg->SetZipping(2);
803  arg->SetContentType("text/html");
804  }
805  return;
806  }
807 
808  if ((arg->fFileName == "favicon.ico") && arg->fPathName.IsNull()) {
809  arg->SetFile(fJSROOTSYS + "/img/RootIcon.ico");
810  return;
811  }
812 
813  TString filename;
814  if (IsFileRequested(arg->fFileName.Data(), filename)) {
815  arg->SetFile(filename);
816  return;
817  }
818 
819  filename = arg->fFileName;
820  Bool_t iszip = kFALSE;
821  if (filename.EndsWith(".gz")) {
822  filename.Resize(filename.Length() - 3);
823  iszip = kTRUE;
824  }
825 
826  void *bindata(0);
827  Long_t bindatalen(0);
828 
829  if ((filename == "h.xml") || (filename == "get.xml")) {
830 
831  Bool_t compact = arg->fQuery.Index("compact") != kNPOS;
832 
833  arg->fContent.Form("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
834  if (!compact)
835  arg->fContent.Append("\n");
836  arg->fContent.Append("<root>");
837  if (!compact)
838  arg->fContent.Append("\n");
839  {
840  TRootSnifferStoreXml store(arg->fContent, compact);
841 
842  const char *topname = fTopName.Data();
843  if (arg->fTopName.Length() > 0)
844  topname = arg->fTopName.Data();
845  fSniffer->ScanHierarchy(topname, arg->fPathName.Data(), &store, filename == "get.xml");
846  }
847 
848  arg->fContent.Append("</root>");
849  if (!compact)
850  arg->fContent.Append("\n");
851 
852  arg->SetXml();
853  } else if (filename == "h.json") {
854  TRootSnifferStoreJson store(arg->fContent, arg->fQuery.Index("compact") != kNPOS);
855  const char *topname = fTopName.Data();
856  if (arg->fTopName.Length() > 0)
857  topname = arg->fTopName.Data();
858  fSniffer->ScanHierarchy(topname, arg->fPathName.Data(), &store);
859  arg->SetJson();
860  } else if (filename == "root.websocket") {
861  // handling of web socket
862 
863  THttpWSHandler *handler = dynamic_cast<THttpWSHandler *>(fSniffer->FindTObjectInHierarchy(arg->fPathName.Data()));
864 
865  if (!handler || !handler->HandleWS(arg))
866  arg->Set404();
867 
868  return;
869  } else if (filename == "root.longpoll") {
870  // ROOT emulation of websocket with polling requests
871  THttpWSHandler *handler = dynamic_cast<THttpWSHandler *>(fSniffer->FindTObjectInHierarchy(arg->fPathName.Data()));
872 
873  if (!handler) {
874  // for the moment only TCanvas is used for web sockets
875  arg->Set404();
876  } else if (arg->fQuery == "connect") {
877  // try to emulate websocket connect
878  // if accepted, reply with connection id, which must be used in the following communications
879  arg->SetMethod("WS_CONNECT");
880 
881  if (handler && handler->HandleWS(arg)) {
882  arg->SetMethod("WS_READY");
883 
884  TLongPollEngine *handle = new TLongPollEngine("longpoll", arg->fPathName.Data());
885 
886  arg->SetWSId(handle->GetId());
887  arg->SetWSHandle(handle);
888 
889  if (handler->HandleWS(arg)) {
890  arg->SetContent(TString::Format("%u", arg->GetWSId()));
891  arg->SetContentType("text/plain");
892  }
893  }
894  if (!arg->IsContentType("text/plain"))
895  arg->Set404();
896  } else {
897  TUrl url;
898  url.SetOptions(arg->fQuery);
899  url.ParseOptions();
900  Int_t connid = url.GetIntValueFromOptions("connection");
901  arg->SetWSId((UInt_t)connid);
902  if (url.HasOption("close")) {
903  arg->SetMethod("WS_CLOSE");
904  arg->SetContent("OK");
905  arg->SetContentType("text/plain");
906  } else {
907  arg->SetMethod("WS_DATA");
908  const char *post = url.GetValueFromOptions("post");
909  if (post) {
910  // posted data transferred as URL parameter
911  // done due to limitation of webengine in qt
912  Int_t len = strlen(post);
913  void *buf = malloc(len / 2 + 1);
914  char *sbuf = (char *)buf;
915  for (int n = 0; n < len; n += 2)
916  sbuf[n / 2] = TString::BaseConvert(TString(post + n, 2), 16, 10).Atoi();
917  sbuf[len / 2] = 0; // just in case of zero-terminated string
918  arg->SetPostData(buf, len / 2);
919  }
920  }
921  if (handler && !handler->HandleWS(arg))
922  arg->Set404();
923  }
924  return;
925 
926  } else if (filename == "root.ws_emulation") {
927  // ROOT emulation of websocket
928  THttpWSHandler *handler = dynamic_cast<THttpWSHandler *>(fSniffer->FindTObjectInHierarchy(arg->fPathName.Data()));
929 
930  if (!handler || !handler->HandleWS(arg))
931  arg->Set404();
932  if (!arg->Is404() && (arg->fMethod == "WS_CONNECT") && arg->fWSHandle) {
933  arg->SetMethod("WS_READY");
934  if (handler->HandleWS(arg)) {
935  arg->SetContent(TString::Format("%u", arg->GetWSId()));
936  arg->SetContentType("text/plain");
937  } else {
938  arg->Set404();
939  }
940  }
941 
942  return;
943 
944  } else if (fSniffer->Produce(arg->fPathName.Data(), filename.Data(), arg->fQuery.Data(), bindata, bindatalen,
945  arg->fContent)) {
946  if (bindata != 0)
947  arg->SetBinData(bindata, bindatalen);
948 
949  // define content type base on extension
950  arg->SetContentType(GetMimeType(filename.Data()));
951  } else {
952  // request is not processed
953  arg->Set404();
954  }
955 
956  if (arg->Is404())
957  return;
958 
959  if (iszip)
960  arg->SetZipping(3);
961 
962  if (filename == "root.bin") {
963  // only for binary data master version is important
964  // it allows to detect if streamer info was modified
965  const char *parname = fSniffer->IsStreamerInfoItem(arg->fPathName.Data()) ? "BVersion" : "MVersion";
966  arg->AddHeader(parname, Form("%u", (unsigned)fSniffer->GetStreamerInfoHash()));
967  }
968 
969  // try to avoid caching on the browser
970  arg->AddHeader("Cache-Control",
971  "private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0");
972 
973  // potentially add cors header
974  if (IsCors())
975  arg->AddHeader("Access-Control-Allow-Origin", GetCors());
976 }
977 
978 ////////////////////////////////////////////////////////////////////////////////
979 /// Register object in folders hierarchy
980 ///
981 /// See TRootSniffer::RegisterObject() for more details
982 
983 Bool_t THttpServer::Register(const char *subfolder, TObject *obj)
984 {
985  return fSniffer->RegisterObject(subfolder, obj);
986 }
987 
988 ////////////////////////////////////////////////////////////////////////////////
989 /// Unregister object in folders hierarchy
990 ///
991 /// See TRootSniffer::UnregisterObject() for more details
992 
994 {
995  return fSniffer->UnregisterObject(obj);
996 }
997 
998 ////////////////////////////////////////////////////////////////////////////////
999 /// Restrict access to specified object
1000 ///
1001 /// See TRootSniffer::Restrict() for more details
1002 
1003 void THttpServer::Restrict(const char *path, const char *options)
1004 {
1005  fSniffer->Restrict(path, options);
1006 }
1007 
1008 ////////////////////////////////////////////////////////////////////////////////
1009 /// Register command which can be executed from web interface
1010 ///
1011 /// As method one typically specifies string, which is executed with
1012 /// gROOT->ProcessLine() method. For instance
1013 /// serv->RegisterCommand("Invoke","InvokeFunction()");
1014 ///
1015 /// Or one could specify any method of the object which is already registered
1016 /// to the server. For instance:
1017 /// serv->Register("/", hpx);
1018 /// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()");
1019 /// Here symbols '/->' separates item name from method to be executed
1020 ///
1021 /// One could specify additional arguments in the command with
1022 /// syntax like %arg1%, %arg2% and so on. For example:
1023 /// serv->RegisterCommand("/ResetHPX", "/hpx/->SetTitle(\"%arg1%\")");
1024 /// serv->RegisterCommand("/RebinHPXPY", "/hpxpy/->Rebin2D(%arg1%,%arg2%)");
1025 /// Such parameter(s) will be requested when command clicked in the browser.
1026 ///
1027 /// Once command is registered, one could specify icon which will appear in the browser:
1028 /// serv->SetIcon("/ResetHPX", "rootsys/icons/ed_execute.png");
1029 ///
1030 /// One also can set extra property '_fastcmd', that command appear as
1031 /// tool button on the top of the browser tree:
1032 /// serv->SetItemField("/ResetHPX", "_fastcmd", "true");
1033 /// Or it is equivalent to specifying extra argument when register command:
1034 /// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()", "button;rootsys/icons/ed_delete.png");
1035 
1036 Bool_t THttpServer::RegisterCommand(const char *cmdname, const char *method, const char *icon)
1037 {
1038  return fSniffer->RegisterCommand(cmdname, method, icon);
1039 }
1040 
1041 ////////////////////////////////////////////////////////////////////////////////
1042 /// hides folder or element from web gui
1043 
1044 Bool_t THttpServer::Hide(const char *foldername, Bool_t hide)
1045 {
1046  return SetItemField(foldername, "_hidden", hide ? "true" : (const char *)0);
1047 }
1048 
1049 ////////////////////////////////////////////////////////////////////////////////
1050 /// set name of icon, used in browser together with the item
1051 ///
1052 /// One could use images from $ROOTSYS directory like:
1053 /// serv->SetIcon("/ResetHPX","/rootsys/icons/ed_execute.png");
1054 
1055 Bool_t THttpServer::SetIcon(const char *fullname, const char *iconname)
1056 {
1057  return SetItemField(fullname, "_icon", iconname);
1058 }
1059 
1060 ////////////////////////////////////////////////////////////////////////////////
1061 
1062 Bool_t THttpServer::CreateItem(const char *fullname, const char *title)
1063 {
1064  return fSniffer->CreateItem(fullname, title);
1065 }
1066 
1067 ////////////////////////////////////////////////////////////////////////////////
1068 
1069 Bool_t THttpServer::SetItemField(const char *fullname, const char *name, const char *value)
1070 {
1071  return fSniffer->SetItemField(fullname, name, value);
1072 }
1073 
1074 ////////////////////////////////////////////////////////////////////////////////
1075 
1076 const char *THttpServer::GetItemField(const char *fullname, const char *name)
1077 {
1078  return fSniffer->GetItemField(fullname, name);
1079 }
1080 
1081 ////////////////////////////////////////////////////////////////////////////////
1082 /// Returns MIME type base on file extension
1083 
1084 const char *THttpServer::GetMimeType(const char *path)
1085 {
1086  static const struct {
1087  const char *extension;
1088  int ext_len;
1089  const char *mime_type;
1090  } builtin_mime_types[] = {{".xml", 4, "text/xml"},
1091  {".json", 5, "application/json"},
1092  {".bin", 4, "application/x-binary"},
1093  {".gif", 4, "image/gif"},
1094  {".jpg", 4, "image/jpeg"},
1095  {".png", 4, "image/png"},
1096  {".html", 5, "text/html"},
1097  {".htm", 4, "text/html"},
1098  {".shtm", 5, "text/html"},
1099  {".shtml", 6, "text/html"},
1100  {".css", 4, "text/css"},
1101  {".js", 3, "application/x-javascript"},
1102  {".ico", 4, "image/x-icon"},
1103  {".jpeg", 5, "image/jpeg"},
1104  {".svg", 4, "image/svg+xml"},
1105  {".txt", 4, "text/plain"},
1106  {".torrent", 8, "application/x-bittorrent"},
1107  {".wav", 4, "audio/x-wav"},
1108  {".mp3", 4, "audio/x-mp3"},
1109  {".mid", 4, "audio/mid"},
1110  {".m3u", 4, "audio/x-mpegurl"},
1111  {".ogg", 4, "application/ogg"},
1112  {".ram", 4, "audio/x-pn-realaudio"},
1113  {".xslt", 5, "application/xml"},
1114  {".xsl", 4, "application/xml"},
1115  {".ra", 3, "audio/x-pn-realaudio"},
1116  {".doc", 4, "application/msword"},
1117  {".exe", 4, "application/octet-stream"},
1118  {".zip", 4, "application/x-zip-compressed"},
1119  {".xls", 4, "application/excel"},
1120  {".tgz", 4, "application/x-tar-gz"},
1121  {".tar", 4, "application/x-tar"},
1122  {".gz", 3, "application/x-gunzip"},
1123  {".arj", 4, "application/x-arj-compressed"},
1124  {".rar", 4, "application/x-arj-compressed"},
1125  {".rtf", 4, "application/rtf"},
1126  {".pdf", 4, "application/pdf"},
1127  {".swf", 4, "application/x-shockwave-flash"},
1128  {".mpg", 4, "video/mpeg"},
1129  {".webm", 5, "video/webm"},
1130  {".mpeg", 5, "video/mpeg"},
1131  {".mov", 4, "video/quicktime"},
1132  {".mp4", 4, "video/mp4"},
1133  {".m4v", 4, "video/x-m4v"},
1134  {".asf", 4, "video/x-ms-asf"},
1135  {".avi", 4, "video/x-msvideo"},
1136  {".bmp", 4, "image/bmp"},
1137  {".ttf", 4, "application/x-font-ttf"},
1138  {NULL, 0, NULL}};
1139 
1140  int path_len = strlen(path);
1141 
1142  for (int i = 0; builtin_mime_types[i].extension != NULL; i++) {
1143  if (path_len <= builtin_mime_types[i].ext_len)
1144  continue;
1145  const char *ext = path + (path_len - builtin_mime_types[i].ext_len);
1146  if (strcmp(ext, builtin_mime_types[i].extension) == 0) {
1147  return builtin_mime_types[i].mime_type;
1148  }
1149  }
1150 
1151  return "text/plain";
1152 }
1153 
1154 ////////////////////////////////////////////////////////////////////////////////
1155 /// reads file content
1156 
1157 char *THttpServer::ReadFileContent(const char *filename, Int_t &len)
1158 {
1159  len = 0;
1160 
1161  std::ifstream is(filename);
1162  if (!is)
1163  return 0;
1164 
1165  is.seekg(0, is.end);
1166  len = is.tellg();
1167  is.seekg(0, is.beg);
1168 
1169  char *buf = (char *)malloc(len);
1170  is.read(buf, len);
1171  if (!is) {
1172  free(buf);
1173  len = 0;
1174  return 0;
1175  }
1176 
1177  return buf;
1178 }
void SetZipping(Int_t kind)
Set kind of content zipping 0 - none 1 - only when supported in request header 2 - if supported and c...
Definition: THttpCallArg.h:192
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:37
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
Definition: TList.cxx:467
void SetCors(const char *domain="*")
Enable CORS header to ProcessRequests() responses Specified location (typically "*") add as "Access-C...
Definition: THttpServer.h:77
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 &#39;path&#39; 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:30
Bool_t IsReadOnly() const
Returns readonly mode.
Definition: TRootSniffer.h:170
UInt_t GetWSId() const
get web-socket id
Definition: THttpCallArg.h:97
void SetWSHandle(TNamed *handle)
assign websocket handle with HTTP call
const char * mime_type
Definition: civetweb.c:5007
Storage of hierarchy scan in TRootSniffer in JSON format.
const Ssiz_t kNPOS
Definition: RtypesCore.h:111
This class represents a WWW compatible URL.
Definition: TUrl.h:35
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition: TString.h:638
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
const char * GetItemField(const char *fullname, const char *name)
Bool_t IsReadOnly() const
returns read-only mode
#define gROOT
Definition: TROOT.h:402
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:585
Bool_t IsCors() const
Returns kTRUE if CORS was configured.
Definition: THttpServer.h:80
TString fQuery
! additional arguments
Definition: THttpCallArg.h:34
Basic string class.
Definition: TString.h:125
TString fTopName
! name of top folder, default - "ROOT"
Definition: THttpServer.h:39
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
static const TString & GetRootSys()
Get the rootsys directory in the installation. Static utility function.
Definition: TROOT.cxx:2821
void Restrict(const char *path, const char *options)
Restrict access to the specified location.
static const struct @128 builtin_mime_types[]
Bool_t UnregisterObject(TObject *obj)
unregister (remove) object from folders structures folder itself will remain even when it will be emp...
TList fEngines
! engines which runs http server
Definition: THttpServer.h:32
TObject * At(Int_t idx) const
Definition: TObjArray.h:165
void SetServer(THttpServer *serv)
Definition: THttpEngine.h:27
#define malloc
Definition: civetweb.c:818
const char * GetQuery() const
returns request query (string after ? in request URL)
Definition: THttpCallArg.h:142
void SetContentType(const char *typ)
set content type like "text/xml" or "application/json"
Definition: THttpCallArg.h:147
Bool_t CreateItem(const char *fullname, const char *title)
create item element
void SetPostponed()
mark reply as postponed - submitting thread will not be inform
Definition: THttpCallArg.h:153
void ProcessRequests()
Process submitted requests, must be called from main thread.
UInt_t Hash(ECaseCompare cmp=kExact) const
Return hash value.
Definition: TString.cxx:616
virtual TObject * FindObject(const char *name) const
Delete a TObjLink object.
Definition: TList.cxx:574
Bool_t CreateItem(const char *fullname, const char *title)
void SetContent(const char *c)
Set content directly.
Definition: THttpCallArg.h:183
void SetPostData(void *data, Long_t length, Bool_t make_copy=kFALSE)
set data, posted with the request buffer should be allocated with malloc(length+1) call...
TRootSniffer * fSniffer
! sniffer provides access to ROOT objects hierarchy
Definition: THttpServer.h:34
THttpServer(const char *engine="civetweb:8080")
constructor
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:2365
Bool_t SetItemField(const char *fullname, const char *name, const char *value)
set field for specified item
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:29
void Clear()
Clear string without changing its capacity.
Definition: TString.cxx:1150
THttpTimer * fTimer
! timer used to access main thread
Definition: THttpServer.h:33
virtual const char * Getenv(const char *env)
Get environment variable.
Definition: TSystem.cxx:1638
TString fPathName
! item path
Definition: THttpCallArg.h:31
void Set404()
mark reply as 404 error - page/request not exists or refused
Definition: THttpCallArg.h:150
void Info(const char *location, const char *msgfmt,...)
TString & Append(const char *cs)
Definition: TString.h:495
Bool_t EndsWith(const char *pat, ECaseCompare cmp=kExact) const
Return true if string ends with the specified string.
Definition: TString.cxx:2231
static Long_t SelfId()
Static method returning the id for the current thread.
Definition: TThread.cxx:547
TNamed * fWSHandle
! web-socket handle, derived from TNamed class
Definition: THttpCallArg.h:39
void SetTimer(Long_t milliSec=100, Bool_t mode=kTRUE)
create timer which will invoke ProcessRequests() function periodically Timer is required to perform a...
const char * GetValueFromOptions(const char *key) const
Return a value for a given key from the URL options.
Definition: TUrl.cxx:649
TList fLocations
! list of local directories, which could be accessed via server
Definition: THttpServer.h:41
TString fJSROOTSYS
! location of local JSROOT files
Definition: THttpServer.h:38
void Error(const char *location, const char *msgfmt,...)
Storage of hierarchy scan in TRootSniffer in XML format.
Bool_t SubmitHttp(THttpCallArg *arg, Bool_t can_run_immediately=kFALSE)
Submit HTTP request.
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
! top item name
Definition: THttpCallArg.h:29
Int_t GetLast() const
Return index of last object in array.
Definition: TObjArray.cxx:561
void SetBinData(void *data, Long_t length)
set binary data, which will be returned as reply body
void SetJson()
set content type as JSON
Definition: THttpCallArg.h:167
Bool_t CreateEngine(const char *engine)
factory method to create different http engines At the moment two engine kinds are supported: civetwe...
Bool_t fNotifyFlag
! indicate that notification called
Definition: THttpCallArg.h:53
virtual TObject * First() const
Return the first object in the list. Returns 0 when list is empty.
Definition: TList.cxx:655
size_t ext_len
Definition: civetweb.c:5006
Bool_t HandleWS(THttpCallArg *arg)
R__EXTERN TSystem * gSystem
Definition: TSystem.h:540
virtual TString GetDefaultPageContent()
Provides content of default web page for registered web-socket handler Can be content of HTML page or...
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2343
unsigned int UInt_t
Definition: RtypesCore.h:42
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.
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
char * Form(const char *fmt,...)
Ssiz_t Length() const
Definition: TString.h:386
TString fDefaultPage
! file name for default page name
Definition: THttpServer.h:43
virtual Bool_t Create(const char *)
Method to create all components of engine.
Definition: THttpEngine.h:36
Handles synchronous and a-synchronous timer events.
Definition: TTimer.h:51
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:75
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.
Bool_t ExecuteHttp(THttpCallArg *arg)
Execute HTTP request.
const Bool_t kFALSE
Definition: RtypesCore.h:88
const char * extension
Definition: civetweb.c:5005
TString fDrawPage
! file name for drawing of single element
Definition: THttpServer.h:45
TString & Remove(Ssiz_t pos)
Definition: TString.h:619
long Long_t
Definition: RtypesCore.h:50
int Ssiz_t
Definition: RtypesCore.h:63
std::condition_variable fCond
! condition used to wait for processing
Definition: THttpCallArg.h:42
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:2251
Bool_t Hide(const char *fullname, Bool_t hide=kTRUE)
hides folder or element from web gui
#define ClassImp(name)
Definition: Rtypes.h:359
std::mutex fMutex
! mutex to protect list with arguments
Definition: THttpServer.h:50
void SetWSId(UInt_t id)
set web-socket id
Definition: THttpCallArg.h:94
virtual void ProcessRequest(THttpCallArg *arg)
Function called for every processed request.
TString fDrawPageCont
! content of draw page
Definition: THttpServer.h:46
void SetMethod(const char *method)
set request method kind like GET or POST
Definition: THttpCallArg.h:68
void SetXml()
set content type as XML
Definition: THttpCallArg.h:164
TNamed()
Definition: TNamed.h:36
#define free
Definition: civetweb.c:821
static const TString & GetEtcDir()
Get the sysconfig directory in the installation. Static utility function.
Definition: TROOT.cxx:2905
static TString BaseConvert(const TString &s_in, Int_t base_in, Int_t base_out)
Converts string from base base_in to base base_out.
Definition: TString.cxx:2181
void NotifyCondition()
method used to notify condition which waiting when operation will complete Condition notified only if...
TString fDefaultPageCont
! content of the file content
Definition: THttpServer.h:44
void ParseOptions() const
Parse URL options into a key/value map.
Definition: TUrl.cxx:618
Bool_t RegisterCommand(const char *cmdname, const char *method, const char *icon=0)
Register command which can be executed from web interface.
Bool_t IsNull() const
Definition: TString.h:383
Mother of all ROOT objects.
Definition: TObject.h:37
static const char * GetMimeType(const char *path)
Guess mime type base on file extension.
Bool_t Unregister(TObject *obj)
Unregister object.
TString fContent
! text content (if any)
Definition: THttpCallArg.h:47
virtual const char * GetTitle() const
Returns title of object.
Definition: TObject.cxx:401
Long_t fMainThrdId
! id of the main ROOT process
Definition: THttpServer.h:36
void AddHeader(const char *name, const char *value)
Set name: value pair to reply header Content-Type field handled separately - one should use SetConten...
TString fMethod
! request method like GET or POST
Definition: THttpCallArg.h:30
static char * ReadFileContent(const char *filename, Int_t &len)
Reads content of file from the disk.
void SetReadOnly(Bool_t on=kTRUE)
When readonly on (default), sniffer is not allowed to change ROOT structures For instance, it is not allowed to read new objects from files.
Definition: TRootSniffer.h:167
const char * GetCors() const
Returns specified CORS domain.
Definition: THttpServer.h:83
virtual void Add(TObject *obj)
Definition: TList.h:87
Bool_t Is404() const
Definition: THttpCallArg.h:206
void SetFile(const char *filename=0)
indicate that http request should response with file content
Definition: THttpCallArg.h:156
Bool_t SetIcon(const char *fullname, const char *iconname)
set name of icon, used in browser together with the item
void SetOptions(const char *opt)
Definition: TUrl.h:90
virtual void Timeout()
Definition: TTimer.h:96
Bool_t IsContentType(const char *typ) const
Definition: THttpCallArg.h:205
TList fCallArgs
! submitted 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:1254
Int_t GetIntValueFromOptions(const char *key) const
Return a value for a given key from the URL options as an Int_t, a missing key returns -1...
Definition: TUrl.cxx:661
TString fJSROOT
! location of external JSROOT files
Definition: THttpServer.h:40
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:357
virtual Int_t GetSize() const
Definition: TCollection.h:180
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 void SetTitle(const char *title="")
Set the title of the TNamed.
Definition: TNamed.cxx:164
const Bool_t kTRUE
Definition: RtypesCore.h:87
void SetDrawPage(const char *filename)
Set file name of HTML page, delivered by the server when objects drawing page is requested from the b...
void SetScanGlobalDir(Bool_t on=kTRUE)
When enabled (default), sniffer scans gROOT for files, canvases, histograms.
Definition: TRootSniffer.h:179
Bool_t HasOption(const char *key) const
Returns true if the given key appears in the URL options list.
Definition: TUrl.cxx:672
TRootSniffer * GetSniffer() const
returns pointer on objects sniffer
Definition: THttpServer.h:67
const Int_t n
Definition: legend1.C:16
TString fFileName
! file name
Definition: THttpCallArg.h:32
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
Bool_t IsFileRequested(const char *uri, TString &res) const
Check if file is requested, thread safe.
char name[80]
Definition: TGX11.cxx:109
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:866
void Resize(Ssiz_t n)
Resize the string. Truncate or add blanks as necessary.
Definition: TString.cxx:1069
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...
TObject * FindTObjectInHierarchy(const char *path)
Search element in hierarchy, derived from TObject.
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)
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4792
const char * Data() const
Definition: TString.h:345