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