Logo ROOT   6.18/05
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 "TROOT.h"
18#include "TUrl.h"
19#include "TEnv.h"
20#include "TError.h"
21#include "TClass.h"
22#include "RVersion.h"
23#include "RConfigure.h"
24#include "TRegexp.h"
25
26#include "THttpEngine.h"
27#include "THttpLongPollEngine.h"
28#include "THttpWSHandler.h"
29#include "TRootSniffer.h"
30#include "TRootSnifferStore.h"
31#include "TCivetweb.h"
32#include "TFastCgi.h"
33
34#include <string>
35#include <cstdlib>
36#include <stdlib.h>
37#include <string.h>
38#include <fstream>
39#include <chrono>
40
41////////////////////////////////////////////////////////////////////////////////
42
43//////////////////////////////////////////////////////////////////////////
44// //
45// THttpTimer //
46// //
47// Specialized timer for THttpServer //
48// Provides regular calls of THttpServer::ProcessRequests() method //
49// //
50//////////////////////////////////////////////////////////////////////////
51
52class THttpTimer : public TTimer {
53public:
54 THttpServer &fServer; ///!< server processing requests
55
56 /// constructor
57 THttpTimer(Long_t milliSec, Bool_t mode, THttpServer &serv) : TTimer(milliSec, mode), fServer(serv) {}
58
59 /// timeout handler
60 /// used to process http requests in main ROOT thread
61 virtual void Timeout() { fServer.ProcessRequests(); }
62};
63
64//////////////////////////////////////////////////////////////////////////////////////////////////
65
66//////////////////////////////////////////////////////////////////////////
67// //
68// THttpServer //
69// //
70// Online http server for arbitrary ROOT application //
71// //
72// Idea of THttpServer - provide remote http access to running //
73// ROOT application and enable HTML/JavaScript user interface. //
74// Any registered object can be requested and displayed in the browser. //
75// There are many benefits of such approach: //
76// * standard http interface to ROOT application //
77// * no any temporary ROOT files when access data //
78// * user interface running in all browsers //
79// //
80// Starting HTTP server //
81// //
82// To start http server, at any time create instance //
83// of the THttpServer class like: //
84// serv = new THttpServer("http:8080"); //
85// //
86// This will starts civetweb-based http server with http port 8080. //
87// Than one should be able to open address "http://localhost:8080" //
88// in any modern browser (IE, Firefox, Chrome) and browse objects, //
89// created in application. By default, server can access files, //
90// canvases and histograms via gROOT pointer. All such objects //
91// can be displayed with JSROOT graphics. //
92// //
93// At any time one could register other objects with the command: //
94// //
95// TGraph* gr = new TGraph(10); //
96// gr->SetName("gr1"); //
97// serv->Register("graphs/subfolder", gr); //
98// //
99// If objects content is changing in the application, one could //
100// enable monitoring flag in the browser - than objects view //
101// will be regularly updated. //
102// //
103// More information: https://root.cern/root/htmldoc/guides/HttpServer/HttpServer.html //
104// //
105//////////////////////////////////////////////////////////////////////////
106
108
109////////////////////////////////////////////////////////////////////////////////
110/// constructor
111///
112/// As argument, one specifies engine kind which should be
113/// created like "http:8080". One could specify several engines
114/// at once, separating them with semicolon (";"). Following engines are supported:
115///
116/// http - TCivetweb, civetweb-based implementation of http protocol
117/// fastcgi - TFastCgi, special protocol for communicating with web servers
118///
119/// For each created engine one should provide socket port number like "http:8080" or "fastcgi:9000".
120/// Additional engine-specific options can be supplied with URL syntax like "http:8080?thrds=10".
121/// Full list of supported options should be checked in engines docu.
122///
123/// One also can configure following options, separated by semicolon:
124///
125/// readonly, ro - set read-only mode (default)
126/// readwrite, rw - allows methods execution of registered objects
127/// global - scans global ROOT lists for existing objects (default)
128/// noglobal - disable scan of global lists
129/// cors - enable CORS header with origin="*"
130/// cors=domain - enable CORS header with origin="domain"
131/// basic_sniffer - use basic sniffer without support of hist, gpad, graph classes
132///
133/// For example, create http server, which allows cors headers and disable scan of global lists,
134/// one should provide "http:8080;cors;noglobal" as parameter
135///
136/// THttpServer uses JavaScript ROOT (https://root.cern/js) to implement web clients UI.
137/// Normally JSROOT sources are used from $ROOTSYS/js directory,
138/// but one could set JSROOTSYS shell variable to specify alternative location
139
140THttpServer::THttpServer(const char *engine) : TNamed("http", "ROOT http server")
141{
142 const char *jsrootsys = gSystem->Getenv("JSROOTSYS");
143 if (!jsrootsys)
144 jsrootsys = gEnv->GetValue("HttpServ.JSRootPath", jsrootsys);
145
146 if (jsrootsys && *jsrootsys) {
147 if ((strncmp(jsrootsys, "http://", 7)==0) || (strncmp(jsrootsys, "https://", 8)==0))
148 fJSROOT = jsrootsys;
149 else
150 fJSROOTSYS = jsrootsys;
151 }
152
153 if (fJSROOTSYS.Length() == 0) {
154 TString jsdir = TString::Format("%s/js", TROOT::GetDataDir().Data());
155 if (gSystem->ExpandPathName(jsdir)) {
156 ::Warning("THttpServer::THttpServer", "problems resolving '%s', set JSROOTSYS to proper JavaScript ROOT location",
157 jsdir.Data());
158 fJSROOTSYS = ".";
159 } else {
160 fJSROOTSYS = jsdir;
161 }
162 }
163
164 AddLocation("currentdir/", ".");
165 AddLocation("jsrootsys/", fJSROOTSYS.Data());
166 AddLocation("rootsys/", TROOT::GetRootSys());
167
168 fDefaultPage = fJSROOTSYS + "/files/online.htm";
169 fDrawPage = fJSROOTSYS + "/files/draw.htm";
170
171 TRootSniffer *sniff = nullptr;
172 if (strstr(engine, "basic_sniffer")) {
173 sniff = new TRootSniffer("sniff");
174 sniff->SetScanGlobalDir(kFALSE);
175 sniff->CreateOwnTopFolder(); // use dedicated folder
176 } else {
177 sniff = (TRootSniffer *)gROOT->ProcessLineSync("new TRootSnifferFull(\"sniff\");");
178 }
179
180 SetSniffer(sniff);
181
182 // start timer
183 SetTimer(20, kTRUE);
184
185 if (strchr(engine, ';') == 0) {
186 CreateEngine(engine);
187 } else {
188 TObjArray *lst = TString(engine).Tokenize(";");
189
190 for (Int_t n = 0; n <= lst->GetLast(); n++) {
191 const char *opt = lst->At(n)->GetName();
192 if ((strcmp(opt, "readonly") == 0) || (strcmp(opt, "ro") == 0)) {
194 } else if ((strcmp(opt, "readwrite") == 0) || (strcmp(opt, "rw") == 0)) {
196 } else if (strcmp(opt, "global") == 0) {
198 } else if (strcmp(opt, "noglobal") == 0) {
200 } else if (strncmp(opt, "cors=", 5) == 0) {
201 SetCors(opt + 5);
202 } else if (strcmp(opt, "cors") == 0) {
203 SetCors("*");
204 } else
205 CreateEngine(opt);
206 }
207
208 delete lst;
209 }
210}
211
212////////////////////////////////////////////////////////////////////////////////
213/// destructor
214/// delete all http engines and sniffer
215
217{
219
220 if (fTerminated) {
221 TIter iter(&fEngines);
222 while (auto engine = dynamic_cast<THttpEngine *>(iter()))
223 engine->Terminate();
224 }
225
227
228 SetSniffer(nullptr);
229
230 SetTimer(0);
231}
232
233////////////////////////////////////////////////////////////////////////////////
234/// Set TRootSniffer to the server
235/// Server takes ownership over sniffer
236
238{
239 if (fSniffer)
240 delete fSniffer;
241 fSniffer = sniff;
242}
243
244////////////////////////////////////////////////////////////////////////////////
245/// Set termination flag,
246/// No any further requests will be processed, server only can be destroyed afterwards
247
249{
251}
252
253////////////////////////////////////////////////////////////////////////////////
254/// returns read-only mode
255
257{
258 return fSniffer ? fSniffer->IsReadOnly() : kTRUE;
259}
260
261////////////////////////////////////////////////////////////////////////////////
262/// Set read-only mode for the server (default on)
263/// In read-only server is not allowed to change any ROOT object, registered to the server
264/// Server also cannot execute objects method via exe.json request
265
267{
268 if (fSniffer)
269 fSniffer->SetReadOnly(readonly);
270}
271
272////////////////////////////////////////////////////////////////////////////////
273/// add files location, which could be used in the server
274/// one could map some system folder to the server like AddLocation("mydir/","/home/user/specials");
275/// Than files from this directory could be addressed via server like
276/// http://localhost:8080/mydir/myfile.root
277
278void THttpServer::AddLocation(const char *prefix, const char *path)
279{
280 if (!prefix || (*prefix == 0))
281 return;
282
283 if (!path)
284 fLocations.erase(fLocations.find(prefix));
285 else
286 fLocations[prefix] = path;
287}
288
289////////////////////////////////////////////////////////////////////////////////
290/// Set location of JSROOT to use with the server
291/// One could specify address like:
292/// https://root.cern.ch/js/5.6.3/
293/// http://jsroot.gsi.de/5.6.3/
294/// This allows to get new JSROOT features with old server,
295/// reduce load on THttpServer instance, also startup time can be improved
296/// When empty string specified (default), local copy of JSROOT is used (distributed with ROOT)
297
298void THttpServer::SetJSROOT(const char *location)
299{
300 fJSROOT = location ? location : "";
301}
302
303////////////////////////////////////////////////////////////////////////////////
304/// Set file name of HTML page, delivered by the server when
305/// http address is opened in the browser.
306/// By default, $ROOTSYS/js/files/online.htm page is used
307/// When empty filename is specified, default page will be used
308
309void THttpServer::SetDefaultPage(const std::string &filename)
310{
311 if (!filename.empty())
312 fDefaultPage = filename;
313 else
314 fDefaultPage = fJSROOTSYS + "/files/online.htm";
315
316 // force to read page content next time again
317 fDefaultPageCont.clear();
318}
319
320////////////////////////////////////////////////////////////////////////////////
321/// Set file name of HTML page, delivered by the server when
322/// objects drawing page is requested from the browser
323/// By default, $ROOTSYS/js/files/draw.htm page is used
324/// When empty filename is specified, default page will be used
325
326void THttpServer::SetDrawPage(const std::string &filename)
327{
328 if (!filename.empty())
329 fDrawPage = filename;
330 else
331 fDrawPage = fJSROOTSYS + "/files/draw.htm";
332
333 // force to read page content next time again
334 fDrawPageCont.clear();
335}
336
337////////////////////////////////////////////////////////////////////////////////
338/// factory method to create different http engines
339/// At the moment two engine kinds are supported:
340/// civetweb (default) and fastcgi
341/// Examples:
342/// "http:8080" or "civetweb:8080" or ":8080" - creates civetweb web server with http port 8080
343/// "fastcgi:9000" - creates fastcgi server with port 9000
344/// One could apply additional parameters, using URL syntax:
345/// "http:8080?thrds=10"
346
348{
349 if (!engine)
350 return kFALSE;
351
352 const char *arg = strchr(engine, ':');
353 if (!arg)
354 return kFALSE;
355
356 TString clname;
357 if (arg != engine)
358 clname.Append(engine, arg - engine);
359
360 THttpEngine *eng = nullptr;
361
362 if ((clname.Length() == 0) || (clname == "http") || (clname == "civetweb")) {
363 eng = new TCivetweb(kFALSE);
364 } else if (clname == "https") {
365 eng = new TCivetweb(kTRUE);
366 } else if (clname == "fastcgi") {
367 eng = new TFastCgi();
368 }
369
370 if (!eng) {
371 // ensure that required engine class exists before we try to create it
372 TClass *engine_class = gROOT->LoadClass(clname.Data());
373 if (!engine_class)
374 return kFALSE;
375
376 eng = (THttpEngine *)engine_class->New();
377 if (!eng)
378 return kFALSE;
379 }
380
381 eng->SetServer(this);
382
383 if (!eng->Create(arg + 1)) {
384 delete eng;
385 return kFALSE;
386 }
387
388 fEngines.Add(eng);
389
390 return kTRUE;
391}
392
393////////////////////////////////////////////////////////////////////////////////
394/// create timer which will invoke ProcessRequests() function periodically
395/// Timer is required to perform all actions in main ROOT thread
396/// Method arguments are the same as for TTimer constructor
397/// By default, sync timer with 100 ms period is created
398///
399/// It is recommended to always use sync timer mode and only change period to
400/// adjust server reaction time. Use of async timer requires, that application regularly
401/// calls gSystem->ProcessEvents(). It happens automatically in ROOT interactive shell.
402/// If milliSec == 0, no timer will be created.
403/// In this case application should regularly call ProcessRequests() method.
404///
405/// Async timer allows to use THttpServer in applications, which does not have explicit
406/// gSystem->ProcessEvents() calls. But be aware, that such timer can interrupt any system call
407/// (like malloc) and can lead to dead locks, especially in multi-threaded applications.
408
410{
411 if (fTimer) {
412 fTimer->Stop();
413 delete fTimer;
414 fTimer = nullptr;
415 }
416 if (milliSec > 0) {
417 if (fOwnThread) {
418 Error("SetTimer", "Server runs already in special thread, therefore no any timer can be created");
419 } else {
420 fTimer = new THttpTimer(milliSec, mode, *this);
421 fTimer->TurnOn();
422 }
423 }
424}
425
426////////////////////////////////////////////////////////////////////////////////
427/// Creates special thread to process all requests, directed to http server
428///
429/// Should be used with care - only dedicated instance of TRootSniffer is allowed
430/// By default THttpServer allows to access global lists pointers gROOT or gFile.
431/// To be on the safe side, all kind of such access performed from the main thread.
432/// Therefore usage of specialized thread means that no any global pointers will
433/// be accessible by THttpServer
434
436{
437 if (fOwnThread)
438 return;
439
440 SetTimer(0);
441 fMainThrdId = 0;
442 fOwnThread = true;
443
444 std::thread thrd([this] {
445 int nempty = 0;
446 while (fOwnThread && !fTerminated) {
447 int nprocess = ProcessRequests();
448 if (nprocess > 0)
449 nempty = 0;
450 else
451 nempty++;
452 if (nempty > 1000) {
453 nempty = 0;
454 std::this_thread::sleep_for(std::chrono::milliseconds(1));
455 }
456 }
457 });
458
459 fThrd = std::move(thrd);
460}
461
462////////////////////////////////////////////////////////////////////////////////
463/// Stop server thread
464/// Normally called shortly before http server destructor
465
467{
468 if (!fOwnThread)
469 return;
470
471 fOwnThread = false;
472 fThrd.join();
473 fMainThrdId = 0;
474}
475
476////////////////////////////////////////////////////////////////////////////////
477/// Checked that filename does not contains relative path below current directory
478/// Used to prevent access to files below current directory
479
481{
482 if (!fname || (*fname == 0))
483 return kFALSE;
484
485 Int_t level = 0;
486
487 while (*fname != 0) {
488
489 // find next slash or backslash
490 const char *next = strpbrk(fname, "/\\");
491 if (next == 0)
492 return kTRUE;
493
494 // most important - change to parent dir
495 if ((next == fname + 2) && (*fname == '.') && (*(fname + 1) == '.')) {
496 fname += 3;
497 level--;
498 if (level < 0)
499 return kFALSE;
500 continue;
501 }
502
503 // ignore current directory
504 if ((next == fname + 1) && (*fname == '.')) {
505 fname += 2;
506 continue;
507 }
508
509 // ignore slash at the front
510 if (next == fname) {
511 fname++;
512 continue;
513 }
514
515 fname = next + 1;
516 level++;
517 }
518
519 return kTRUE;
520}
521
522////////////////////////////////////////////////////////////////////////////////
523/// Verifies that request is just file name
524/// File names typically contains prefix like "jsrootsys/"
525/// If true, method returns real name of the file,
526/// which should be delivered to the client
527/// Method is thread safe and can be called from any thread
528
529Bool_t THttpServer::IsFileRequested(const char *uri, TString &res) const
530{
531 if (!uri || (*uri == 0))
532 return kFALSE;
533
534 TString fname(uri);
535
536 for (auto &entry : fLocations) {
537 Ssiz_t pos = fname.Index(entry.first.c_str());
538 if (pos == kNPOS)
539 continue;
540 fname.Remove(0, pos + (entry.first.length() - 1));
541 if (!VerifyFilePath(fname.Data()))
542 return kFALSE;
543 res = entry.second.c_str();
544 if ((fname[0] == '/') && (res[res.Length() - 1] == '/'))
545 res.Resize(res.Length() - 1);
546 res.Append(fname);
547 return kTRUE;
548 }
549
550 return kFALSE;
551}
552
553////////////////////////////////////////////////////////////////////////////////
554/// Executes http request, specified in THttpCallArg structure
555/// Method can be called from any thread
556/// Actual execution will be done in main ROOT thread, where analysis code is running.
557
558Bool_t THttpServer::ExecuteHttp(std::shared_ptr<THttpCallArg> arg)
559{
560 if (fTerminated)
561 return kFALSE;
562
563 if ((fMainThrdId != 0) && (fMainThrdId == TThread::SelfId())) {
564 // should not happen, but one could process requests directly without any signaling
565
566 ProcessRequest(arg);
567
568 return kTRUE;
569 }
570
571 // add call arg to the list
572 std::unique_lock<std::mutex> lk(fMutex);
573 fArgs.push(arg);
574 // and now wait until request is processed
575 arg->fCond.wait(lk);
576
577 return kTRUE;
578}
579
580////////////////////////////////////////////////////////////////////////////////
581/// Submit http request, specified in THttpCallArg structure
582/// Contrary to ExecuteHttp, it will not block calling thread.
583/// User should reimplement THttpCallArg::HttpReplied() method
584/// to react when HTTP request is executed.
585/// Method can be called from any thread
586/// Actual execution will be done in main ROOT thread, where analysis code is running.
587/// When called from main thread and can_run_immediately==kTRUE, will be
588/// executed immediately.
589/// Returns kTRUE when was executed.
590
591Bool_t THttpServer::SubmitHttp(std::shared_ptr<THttpCallArg> arg, Bool_t can_run_immediately)
592{
593 if (fTerminated)
594 return kFALSE;
595
596 if (can_run_immediately && (fMainThrdId != 0) && (fMainThrdId == TThread::SelfId())) {
597 ProcessRequest(arg);
598 arg->NotifyCondition();
599 return kTRUE;
600 }
601
602 // add call arg to the list
603 std::unique_lock<std::mutex> lk(fMutex);
604 fArgs.push(arg);
605 return kFALSE;
606}
607
608////////////////////////////////////////////////////////////////////////////////
609/// Process requests, submitted for execution
610/// Returns number of processed requests
611///
612/// Normally invoked by THttpTimer, when somewhere in the code
613/// gSystem->ProcessEvents() is called.
614/// User can call serv->ProcessRequests() directly, but only from main thread.
615/// If special server thread is created, called from that thread
616
618{
619 if (fMainThrdId == 0)
621
622 if (fMainThrdId != TThread::SelfId()) {
623 Error("ProcessRequests", "Should be called only from main ROOT thread");
624 return 0;
625 }
626
627 Int_t cnt = 0;
628
629 std::unique_lock<std::mutex> lk(fMutex, std::defer_lock);
630
631 // first process requests in the queue
632 while (true) {
633 std::shared_ptr<THttpCallArg> arg;
634
635 lk.lock();
636 if (!fArgs.empty()) {
637 arg = fArgs.front();
638 fArgs.pop();
639 }
640 lk.unlock();
641
642 if (!arg)
643 break;
644
645 if (arg->fFileName == "root_batch_holder.js") {
647 continue;
648 }
649
650 fSniffer->SetCurrentCallArg(arg.get());
651
652 try {
653 cnt++;
654 ProcessRequest(arg);
655 fSniffer->SetCurrentCallArg(nullptr);
656 } catch (...) {
657 fSniffer->SetCurrentCallArg(nullptr);
658 }
659
660 arg->NotifyCondition();
661 }
662
663 // regularly call Process() method of engine to let perform actions in ROOT context
664 TIter iter(&fEngines);
665 THttpEngine *engine = nullptr;
666 while ((engine = (THttpEngine *)iter()) != nullptr) {
667 if (fTerminated)
668 engine->Terminate();
669 engine->Process();
670 }
671
672 return cnt;
673}
674
675////////////////////////////////////////////////////////////////////////////////
676/// Method called when THttpServer cannot process request
677/// By default such requests replied with 404 code
678/// One could overwrite with method in derived class to process all kinds of such non-standard requests
679
681{
682 arg->Set404();
683}
684
685////////////////////////////////////////////////////////////////////////////////
686/// Process special http request for root_batch_holder.js script
687/// This kind of requests used to hold web browser running in headless mode
688/// Intentionally requests does not replied immediately
689
690void THttpServer::ProcessBatchHolder(std::shared_ptr<THttpCallArg> &arg)
691{
692 auto wsptr = FindWS(arg->GetPathName());
693
694 if (!wsptr || !wsptr->ProcessBatchHolder(arg)) {
695 arg->Set404();
696 arg->NotifyCondition();
697 }
698}
699
700////////////////////////////////////////////////////////////////////////////////
701/// Process single http request
702/// Depending from requested path and filename different actions will be performed.
703/// In most cases information is provided by TRootSniffer class
704
705void THttpServer::ProcessRequest(std::shared_ptr<THttpCallArg> arg)
706{
707 if (fTerminated) {
708 arg->Set404();
709 } else if ((arg->fFileName == "root.websocket") || (arg->fFileName == "root.longpoll")) {
710 ExecuteWS(arg);
711 } else {
712 ProcessRequest(arg.get());
713 }
714}
715
716////////////////////////////////////////////////////////////////////////////////
717/// \deprecated One should use signature with std::shared_ptr
718/// Process single http request
719/// Depending from requested path and filename different actions will be performed.
720/// In most cases information is provided by TRootSniffer class
721
723{
724 if (fTerminated) {
725 arg->Set404();
726 return;
727 }
728
729 if (arg->fFileName.IsNull() || (arg->fFileName == "index.htm") || (arg->fFileName == "default.htm")) {
730
731 if (arg->fFileName == "default.htm") {
732
733 arg->fContent = ReadFileContent((fJSROOTSYS + "/files/online.htm").Data());
734
735 } else {
736 auto wsptr = FindWS(arg->GetPathName());
737
738 auto handler = wsptr.get();
739
740 if (!handler)
741 handler = dynamic_cast<THttpWSHandler *>(fSniffer->FindTObjectInHierarchy(arg->fPathName.Data()));
742
743 if (handler) {
744
745 arg->fContent = handler->GetDefaultPageContent().Data();
746
747 if (arg->fContent.find("file:") == 0) {
748 const char *fname = arg->fContent.c_str() + 5;
749 TString resolve;
750 if (!IsFileRequested(fname, resolve)) resolve = fname;
751 arg->fContent = ReadFileContent(resolve.Data());
752 arg->AddNoCacheHeader();
753 }
754
755 arg->CheckWSPageContent(handler);
756 }
757 }
758
759 if (arg->fContent.empty()) {
760
761 if (fDefaultPageCont.empty())
763
765 }
766
767 if (arg->fContent.empty()) {
768 arg->Set404();
769 } else {
770 // replace all references on JSROOT
771 if (fJSROOT.Length() > 0) {
772 std::string repl("=\"");
773 repl.append(fJSROOT.Data());
774 if (repl.back() != '/')
775 repl.append("/");
776 arg->ReplaceAllinContent("=\"jsrootsys/", repl);
777 }
778
779 const char *hjsontag = "\"$$$h.json$$$\"";
780
781 // add h.json caching
782 if (arg->fContent.find(hjsontag) != std::string::npos) {
783 TString h_json;
784 TRootSnifferStoreJson store(h_json, kTRUE);
785 const char *topname = fTopName.Data();
786 if (arg->fTopName.Length() > 0)
787 topname = arg->fTopName.Data();
788 fSniffer->ScanHierarchy(topname, arg->fPathName.Data(), &store);
789
790 arg->ReplaceAllinContent(hjsontag, h_json.Data());
791
792 arg->AddNoCacheHeader();
793
794 if (arg->fQuery.Index("nozip") == kNPOS)
795 arg->SetZipping();
796 }
797 arg->SetContentType("text/html");
798 }
799 return;
800 }
801
802 if (arg->fFileName == "draw.htm") {
803 if (fDrawPageCont.empty())
805
806 if (fDrawPageCont.empty()) {
807 arg->Set404();
808 } else {
809 const char *rootjsontag = "\"$$$root.json$$$\"";
810 const char *hjsontag = "\"$$$h.json$$$\"";
811
812 arg->fContent = fDrawPageCont;
813
814 // replace all references on JSROOT
815 if (fJSROOT.Length() > 0) {
816 std::string repl("=\"");
817 repl.append(fJSROOT.Data());
818 if (repl.back() != '/')
819 repl.append("/");
820 arg->ReplaceAllinContent("=\"jsrootsys/", repl);
821 }
822
823 if ((arg->fQuery.Index("no_h_json") == kNPOS) && (arg->fQuery.Index("webcanvas") == kNPOS) &&
824 (arg->fContent.find(hjsontag) != std::string::npos)) {
825 TString h_json;
826 TRootSnifferStoreJson store(h_json, kTRUE);
827 const char *topname = fTopName.Data();
828 if (arg->fTopName.Length() > 0)
829 topname = arg->fTopName.Data();
830 fSniffer->ScanHierarchy(topname, arg->fPathName.Data(), &store, kTRUE);
831
832 arg->ReplaceAllinContent(hjsontag, h_json.Data());
833 }
834
835 if ((arg->fQuery.Index("no_root_json") == kNPOS) && (arg->fQuery.Index("webcanvas") == kNPOS) &&
836 (arg->fContent.find(rootjsontag) != std::string::npos)) {
837 std::string str;
838 if (fSniffer->Produce(arg->fPathName.Data(), "root.json", "compact=23", str))
839 arg->ReplaceAllinContent(rootjsontag, str);
840 }
841 arg->AddNoCacheHeader();
842 if (arg->fQuery.Index("nozip") == kNPOS)
843 arg->SetZipping();
844 arg->SetContentType("text/html");
845 }
846 return;
847 }
848
849 if ((arg->fFileName == "favicon.ico") && arg->fPathName.IsNull()) {
850 arg->SetFile(fJSROOTSYS + "/img/RootIcon.ico");
851 return;
852 }
853
854 TString filename;
855 if (IsFileRequested(arg->fFileName.Data(), filename)) {
856 arg->SetFile(filename);
857 return;
858 }
859
860 // check if websocket handler may serve file request
861 if (!arg->fPathName.IsNull() && !arg->fFileName.IsNull()) {
862 TString wsname = arg->fPathName, fname;
863 auto pos = wsname.First('/');
864 if (pos == kNPOS) {
865 wsname = arg->fPathName;
866 } else {
867 wsname = arg->fPathName(0, pos);
868 fname = arg->fPathName(pos + 1, arg->fPathName.Length() - pos);
869 fname.Append("/");
870 }
871
872 fname.Append(arg->fFileName);
873
874 if (VerifyFilePath(fname.Data())) {
875
876 auto ws = FindWS(wsname.Data());
877
878 if (ws && ws->CanServeFiles()) {
879 TString fdir = ws->GetDefaultPageContent();
880 // only when file is specified, can take directory, append prefix and file name
881 if (fdir.Index("file:") == 0) {
882 fdir.Remove(0, 5);
883 auto separ = fdir.Last('/');
884 if (separ != kNPOS)
885 fdir.Resize(separ + 1);
886 else
887 fdir = "./";
888
889 fdir.Append(fname);
890 arg->SetFile(fdir);
891 return;
892 }
893 }
894 }
895 }
896
897 filename = arg->fFileName;
898
899 Bool_t iszip = kFALSE;
900 if (filename.EndsWith(".gz")) {
901 filename.Resize(filename.Length() - 3);
902 iszip = kTRUE;
903 }
904
905 if ((filename == "h.xml") || (filename == "get.xml")) {
906
907 Bool_t compact = arg->fQuery.Index("compact") != kNPOS;
908
909 TString res;
910
911 res.Form("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
912 if (!compact)
913 res.Append("\n");
914 res.Append("<root>");
915 if (!compact)
916 res.Append("\n");
917 {
918 TRootSnifferStoreXml store(res, compact);
919
920 const char *topname = fTopName.Data();
921 if (arg->fTopName.Length() > 0)
922 topname = arg->fTopName.Data();
923 fSniffer->ScanHierarchy(topname, arg->fPathName.Data(), &store, filename == "get.xml");
924 }
925
926 res.Append("</root>");
927 if (!compact)
928 res.Append("\n");
929
930 arg->SetContent(std::string(res.Data()));
931
932 arg->SetXml();
933 } else if (filename == "h.json") {
934 TString res;
935 TRootSnifferStoreJson store(res, arg->fQuery.Index("compact") != kNPOS);
936 const char *topname = fTopName.Data();
937 if (arg->fTopName.Length() > 0)
938 topname = arg->fTopName.Data();
939 fSniffer->ScanHierarchy(topname, arg->fPathName.Data(), &store);
940 arg->SetContent(std::string(res.Data()));
941 arg->SetJson();
942 } else if (fSniffer->Produce(arg->fPathName.Data(), filename.Data(), arg->fQuery.Data(), arg->fContent)) {
943 // define content type base on extension
944 arg->SetContentType(GetMimeType(filename.Data()));
945 } else {
946 // miss request, user may process
947 MissedRequest(arg);
948 }
949
950 if (arg->Is404())
951 return;
952
953 if (iszip)
955
956 if (filename == "root.bin") {
957 // only for binary data master version is important
958 // it allows to detect if streamer info was modified
959 const char *parname = fSniffer->IsStreamerInfoItem(arg->fPathName.Data()) ? "BVersion" : "MVersion";
960 arg->AddHeader(parname, Form("%u", (unsigned)fSniffer->GetStreamerInfoHash()));
961 }
962
963 // try to avoid caching on the browser
964 arg->AddNoCacheHeader();
965
966 // potentially add cors header
967 if (IsCors())
968 arg->AddHeader("Access-Control-Allow-Origin", GetCors());
969}
970
971////////////////////////////////////////////////////////////////////////////////
972/// Register object in folders hierarchy
973///
974/// See TRootSniffer::RegisterObject() for more details
975
976Bool_t THttpServer::Register(const char *subfolder, TObject *obj)
977{
978 return fSniffer->RegisterObject(subfolder, obj);
979}
980
981////////////////////////////////////////////////////////////////////////////////
982/// Unregister object in folders hierarchy
983///
984/// See TRootSniffer::UnregisterObject() for more details
985
987{
988 return fSniffer->UnregisterObject(obj);
989}
990
991////////////////////////////////////////////////////////////////////////////////
992/// Register WS handler to the THttpServer
993///
994/// Only such handler can be used in multi-threaded processing of websockets
995
996void THttpServer::RegisterWS(std::shared_ptr<THttpWSHandler> ws)
997{
998 std::lock_guard<std::mutex> grd(fWSMutex);
999 fWSHandlers.emplace_back(ws);
1000}
1001
1002////////////////////////////////////////////////////////////////////////////////
1003/// Unregister WS handler to the THttpServer
1004
1005void THttpServer::UnregisterWS(std::shared_ptr<THttpWSHandler> ws)
1006{
1007 std::lock_guard<std::mutex> grd(fWSMutex);
1008 for (int n = (int)fWSHandlers.size(); n > 0; --n)
1009 if ((fWSHandlers[n - 1] == ws) || fWSHandlers[n - 1]->IsDisabled())
1010 fWSHandlers.erase(fWSHandlers.begin() + n - 1);
1011}
1012
1013////////////////////////////////////////////////////////////////////////////////
1014/// Search WS handler with given name
1015///
1016/// Handler must be registered with RegisterWS() method
1017
1018std::shared_ptr<THttpWSHandler> THttpServer::FindWS(const char *name)
1019{
1020 std::lock_guard<std::mutex> grd(fWSMutex);
1021 for (auto &ws : fWSHandlers) {
1022 if (strcmp(name, ws->GetName()) == 0)
1023 return ws;
1024 }
1025
1026 return nullptr;
1027}
1028
1029////////////////////////////////////////////////////////////////////////////////
1030/// Execute WS related operation
1031
1032Bool_t THttpServer::ExecuteWS(std::shared_ptr<THttpCallArg> &arg, Bool_t external_thrd, Bool_t wait_process)
1033{
1034 if (fTerminated) {
1035 arg->Set404();
1036 return kFALSE;
1037 }
1038
1039 auto wsptr = FindWS(arg->GetPathName());
1040
1041 auto handler = wsptr.get();
1042
1043 if (!handler && !external_thrd)
1044 handler = dynamic_cast<THttpWSHandler *>(fSniffer->FindTObjectInHierarchy(arg->fPathName.Data()));
1045
1046 if (external_thrd && (!handler || !handler->AllowMTProcess())) {
1047 std::unique_lock<std::mutex> lk(fMutex);
1048 fArgs.push(arg);
1049 // and now wait until request is processed
1050 if (wait_process)
1051 arg->fCond.wait(lk);
1052
1053 return kTRUE;
1054 }
1055
1056 if (!handler)
1057 return kFALSE;
1058
1059 Bool_t process = kFALSE;
1060
1061 if (arg->fFileName == "root.websocket") {
1062 // handling of web socket
1063 process = handler->HandleWS(arg);
1064 } else if (arg->fFileName == "root.longpoll") {
1065 // ROOT emulation of websocket with polling requests
1066 if (arg->fQuery.BeginsWith("raw_connect") || arg->fQuery.BeginsWith("txt_connect")) {
1067 // try to emulate websocket connect
1068 // if accepted, reply with connection id, which must be used in the following communications
1069 arg->SetMethod("WS_CONNECT");
1070
1071 bool israw = arg->fQuery.BeginsWith("raw_connect");
1072
1073 // automatically assign engine to arg
1074 arg->CreateWSEngine<THttpLongPollEngine>(israw);
1075
1076 if (handler->HandleWS(arg)) {
1077 arg->SetMethod("WS_READY");
1078
1079 if (handler->HandleWS(arg))
1080 arg->SetTextContent(std::string(israw ? "txt:" : "") + std::to_string(arg->GetWSId()));
1081 } else {
1082 arg->TakeWSEngine(); // delete handle
1083 }
1084
1085 process = arg->IsText();
1086 } else {
1087 TUrl url;
1088 url.SetOptions(arg->fQuery);
1089 url.ParseOptions();
1090 Int_t connid = url.GetIntValueFromOptions("connection");
1091 arg->SetWSId((UInt_t)connid);
1092 if (url.HasOption("close")) {
1093 arg->SetMethod("WS_CLOSE");
1094 arg->SetTextContent("OK");
1095 } else {
1096 arg->SetMethod("WS_DATA");
1097 }
1098
1099 process = handler->HandleWS(arg);
1100 }
1101 }
1102
1103 if (!process)
1104 arg->Set404();
1105
1106 return process;
1107}
1108
1109////////////////////////////////////////////////////////////////////////////////
1110/// Restrict access to specified object
1111///
1112/// See TRootSniffer::Restrict() for more details
1113
1114void THttpServer::Restrict(const char *path, const char *options)
1115{
1116 fSniffer->Restrict(path, options);
1117}
1118
1119////////////////////////////////////////////////////////////////////////////////
1120/// Register command which can be executed from web interface
1121///
1122/// As method one typically specifies string, which is executed with
1123/// gROOT->ProcessLine() method. For instance
1124/// serv->RegisterCommand("Invoke","InvokeFunction()");
1125///
1126/// Or one could specify any method of the object which is already registered
1127/// to the server. For instance:
1128/// serv->Register("/", hpx);
1129/// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()");
1130/// Here symbols '/->' separates item name from method to be executed
1131///
1132/// One could specify additional arguments in the command with
1133/// syntax like %arg1%, %arg2% and so on. For example:
1134/// serv->RegisterCommand("/ResetHPX", "/hpx/->SetTitle(\"%arg1%\")");
1135/// serv->RegisterCommand("/RebinHPXPY", "/hpxpy/->Rebin2D(%arg1%,%arg2%)");
1136/// Such parameter(s) will be requested when command clicked in the browser.
1137///
1138/// Once command is registered, one could specify icon which will appear in the browser:
1139/// serv->SetIcon("/ResetHPX", "rootsys/icons/ed_execute.png");
1140///
1141/// One also can set extra property '_fastcmd', that command appear as
1142/// tool button on the top of the browser tree:
1143/// serv->SetItemField("/ResetHPX", "_fastcmd", "true");
1144/// Or it is equivalent to specifying extra argument when register command:
1145/// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()", "button;rootsys/icons/ed_delete.png");
1146
1147Bool_t THttpServer::RegisterCommand(const char *cmdname, const char *method, const char *icon)
1148{
1149 return fSniffer->RegisterCommand(cmdname, method, icon);
1150}
1151
1152////////////////////////////////////////////////////////////////////////////////
1153/// hides folder or element from web gui
1154
1155Bool_t THttpServer::Hide(const char *foldername, Bool_t hide)
1156{
1157 return SetItemField(foldername, "_hidden", hide ? "true" : (const char *)0);
1158}
1159
1160////////////////////////////////////////////////////////////////////////////////
1161/// set name of icon, used in browser together with the item
1162///
1163/// One could use images from $ROOTSYS directory like:
1164/// serv->SetIcon("/ResetHPX","/rootsys/icons/ed_execute.png");
1165
1166Bool_t THttpServer::SetIcon(const char *fullname, const char *iconname)
1167{
1168 return SetItemField(fullname, "_icon", iconname);
1169}
1170
1171////////////////////////////////////////////////////////////////////////////////
1172
1173Bool_t THttpServer::CreateItem(const char *fullname, const char *title)
1174{
1175 return fSniffer->CreateItem(fullname, title);
1176}
1177
1178////////////////////////////////////////////////////////////////////////////////
1179
1180Bool_t THttpServer::SetItemField(const char *fullname, const char *name, const char *value)
1181{
1182 return fSniffer->SetItemField(fullname, name, value);
1183}
1184
1185////////////////////////////////////////////////////////////////////////////////
1186
1187const char *THttpServer::GetItemField(const char *fullname, const char *name)
1188{
1189 return fSniffer->GetItemField(fullname, name);
1190}
1191
1192////////////////////////////////////////////////////////////////////////////////
1193/// Returns MIME type base on file extension
1194
1195const char *THttpServer::GetMimeType(const char *path)
1196{
1197 static const struct {
1198 const char *extension;
1199 int ext_len;
1200 const char *mime_type;
1201 } builtin_mime_types[] = {{".xml", 4, "text/xml"},
1202 {".json", 5, "application/json"},
1203 {".bin", 4, "application/x-binary"},
1204 {".gif", 4, "image/gif"},
1205 {".jpg", 4, "image/jpeg"},
1206 {".png", 4, "image/png"},
1207 {".html", 5, "text/html"},
1208 {".htm", 4, "text/html"},
1209 {".shtm", 5, "text/html"},
1210 {".shtml", 6, "text/html"},
1211 {".css", 4, "text/css"},
1212 {".js", 3, "application/x-javascript"},
1213 {".ico", 4, "image/x-icon"},
1214 {".jpeg", 5, "image/jpeg"},
1215 {".svg", 4, "image/svg+xml"},
1216 {".txt", 4, "text/plain"},
1217 {".torrent", 8, "application/x-bittorrent"},
1218 {".wav", 4, "audio/x-wav"},
1219 {".mp3", 4, "audio/x-mp3"},
1220 {".mid", 4, "audio/mid"},
1221 {".m3u", 4, "audio/x-mpegurl"},
1222 {".ogg", 4, "application/ogg"},
1223 {".ram", 4, "audio/x-pn-realaudio"},
1224 {".xslt", 5, "application/xml"},
1225 {".xsl", 4, "application/xml"},
1226 {".ra", 3, "audio/x-pn-realaudio"},
1227 {".doc", 4, "application/msword"},
1228 {".exe", 4, "application/octet-stream"},
1229 {".zip", 4, "application/x-zip-compressed"},
1230 {".xls", 4, "application/excel"},
1231 {".tgz", 4, "application/x-tar-gz"},
1232 {".tar", 4, "application/x-tar"},
1233 {".gz", 3, "application/x-gunzip"},
1234 {".arj", 4, "application/x-arj-compressed"},
1235 {".rar", 4, "application/x-arj-compressed"},
1236 {".rtf", 4, "application/rtf"},
1237 {".pdf", 4, "application/pdf"},
1238 {".swf", 4, "application/x-shockwave-flash"},
1239 {".mpg", 4, "video/mpeg"},
1240 {".webm", 5, "video/webm"},
1241 {".mpeg", 5, "video/mpeg"},
1242 {".mov", 4, "video/quicktime"},
1243 {".mp4", 4, "video/mp4"},
1244 {".m4v", 4, "video/x-m4v"},
1245 {".asf", 4, "video/x-ms-asf"},
1246 {".avi", 4, "video/x-msvideo"},
1247 {".bmp", 4, "image/bmp"},
1248 {".ttf", 4, "application/x-font-ttf"},
1249 {NULL, 0, NULL}};
1250
1251 int path_len = strlen(path);
1252
1253 for (int i = 0; builtin_mime_types[i].extension != NULL; i++) {
1254 if (path_len <= builtin_mime_types[i].ext_len)
1255 continue;
1256 const char *ext = path + (path_len - builtin_mime_types[i].ext_len);
1257 if (strcmp(ext, builtin_mime_types[i].extension) == 0) {
1258 return builtin_mime_types[i].mime_type;
1259 }
1260 }
1261
1262 return "text/plain";
1263}
1264
1265////////////////////////////////////////////////////////////////////////////////
1266/// \deprecated reads file content
1267
1268char *THttpServer::ReadFileContent(const char *filename, Int_t &len)
1269{
1270 len = 0;
1271
1272 std::ifstream is(filename, std::ios::in | std::ios::binary);
1273 if (!is)
1274 return nullptr;
1275
1276 is.seekg(0, is.end);
1277 len = is.tellg();
1278 is.seekg(0, is.beg);
1279
1280 char *buf = (char *)malloc(len);
1281 is.read(buf, len);
1282 if (!is) {
1283 free(buf);
1284 len = 0;
1285 return nullptr;
1286 }
1287
1288 return buf;
1289}
1290
1291////////////////////////////////////////////////////////////////////////////////
1292/// reads file content, using std::string as container
1293
1294std::string THttpServer::ReadFileContent(const std::string &filename)
1295{
1296 std::ifstream is(filename, std::ios::in | std::ios::binary);
1297 std::string res;
1298 if (is) {
1299 is.seekg(0, std::ios::end);
1300 res.resize(is.tellg());
1301 is.seekg(0, std::ios::beg);
1302 is.read((char *)res.data(), res.length());
1303 if (!is)
1304 res.clear();
1305 }
1306 return res;
1307}
const Ssiz_t kNPOS
Definition: RtypesCore.h:111
int Int_t
Definition: RtypesCore.h:41
int Ssiz_t
Definition: RtypesCore.h:63
unsigned int UInt_t
Definition: RtypesCore.h:42
const Bool_t kFALSE
Definition: RtypesCore.h:88
long Long_t
Definition: RtypesCore.h:50
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kTRUE
Definition: RtypesCore.h:87
#define ClassImp(name)
Definition: Rtypes.h:365
R__EXTERN TEnv * gEnv
Definition: TEnv.h:171
char name[80]
Definition: TGX11.cxx:109
#define gROOT
Definition: TROOT.h:414
char * Form(const char *fmt,...)
R__EXTERN TSystem * gSystem
Definition: TSystem.h:560
const char * mime_type
Definition: civetweb.c:7795
size_t ext_len
Definition: civetweb.c:7794
static const struct @139 builtin_mime_types[]
#define free
Definition: civetweb.c:1539
const char * extension
Definition: civetweb.c:7793
#define malloc
Definition: civetweb.c:1536
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:75
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4841
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
Definition: TEnv.cxx:491
void Set404()
mark reply as 404 error - page/request not exists or refused
Definition: THttpCallArg.h:162
void SetJson()
Set content type as "application/json".
void SetFile(const char *filename=nullptr)
indicate that http request should response with file content
Definition: THttpCallArg.h:168
TString fTopName
! top item name
Definition: THttpCallArg.h:42
void AddHeader(const char *name, const char *value)
Set name: value pair to reply header Content-Type field handled separately - one should use SetConten...
void ReplaceAllinContent(const std::string &from, const std::string &to, bool once=false)
Replace all occurrences of.
TString fPathName
! item path
Definition: THttpCallArg.h:44
Bool_t Is404() const
Definition: THttpCallArg.h:220
TString fQuery
! additional arguments
Definition: THttpCallArg.h:47
void AddNoCacheHeader()
Set CacheControl http header to disable browser caching.
void SetXml()
Set content type as "text/xml".
void SetContent(const char *cont)
Set content as text.
TString fFileName
! file name
Definition: THttpCallArg.h:45
std::string fContent
! content - text or binary
Definition: THttpCallArg.h:72
void SetContentType(const char *typ)
set content type like "text/xml" or "application/json"
Definition: THttpCallArg.h:159
virtual void CheckWSPageContent(THttpWSHandler *)
Method used to modify content of web page used by web socket handler.
Definition: THttpCallArg.h:67
const char * GetPathName() const
returns path name from request URL
Definition: THttpCallArg.h:145
void SetZipping(Int_t mode=kZipLarge)
Definition: THttpCallArg.h:207
void SetServer(THttpServer *serv)
Definition: THttpEngine.h:27
virtual Bool_t Create(const char *)
Method to create all components of engine.
Definition: THttpEngine.h:37
virtual void Process()
Method regularly called in main ROOT context.
Definition: THttpEngine.h:33
virtual void Terminate()
Method called when server want to be terminated.
Definition: THttpEngine.h:30
Bool_t IsReadOnly() const
returns read-only mode
TString fJSROOT
! location of external JSROOT files
Definition: THttpServer.h:44
virtual void ProcessRequest(std::shared_ptr< THttpCallArg > arg)
Process single http request Depending from requested path and filename different actions will be perf...
std::shared_ptr< THttpWSHandler > FindWS(const char *name)
Find web-socket handler with given name.
void SetTimer(Long_t milliSec=100, Bool_t mode=kTRUE)
create timer which will invoke ProcessRequests() function periodically Timer is required to perform a...
virtual void ProcessBatchHolder(std::shared_ptr< THttpCallArg > &arg)
Process special http request for root_batch_holder.js script This kind of requests used to hold web b...
std::vector< std::shared_ptr< THttpWSHandler > > fWSHandlers
! list of WS handlers
Definition: THttpServer.h:58
virtual ~THttpServer()
destructor delete all http engines and sniffer
void SetTerminate()
set termination flag, no any further requests will be processed
virtual void MissedRequest(THttpCallArg *arg)
Method called when THttpServer cannot process request By default such requests replied with 404 code ...
Bool_t fOwnThread
! true when specialized thread allocated for processing requests
Definition: THttpServer.h:39
void SetSniffer(TRootSniffer *sniff)
Set TRootSniffer to the server Server takes ownership over sniffer.
Bool_t IsFileRequested(const char *uri, TString &res) const
Check if file is requested, thread safe.
const char * GetItemField(const char *fullname, const char *name)
const char * GetCors() const
Returns specified CORS domain.
Definition: THttpServer.h:103
std::thread fThrd
! own thread
Definition: THttpServer.h:40
void StopServerThread()
Stop server thread Normally called shortly before http server destructor.
Int_t ProcessRequests()
Process submitted requests, must be called from appropriate thread.
Bool_t ExecuteWS(std::shared_ptr< THttpCallArg > &arg, Bool_t external_thrd=kFALSE, Bool_t wait_process=kFALSE)
Execute WS request.
void RegisterWS(std::shared_ptr< THttpWSHandler > ws)
Register WS handler.
TString fTopName
! name of top folder, default - "ROOT"
Definition: THttpServer.h:43
TRootSniffer * fSniffer
! sniffer provides access to ROOT objects hierarchy
Definition: THttpServer.h:36
void SetDrawPage(const std::string &filename="")
Set file name of HTML page, delivered by the server when objects drawing page is requested from the b...
Bool_t CreateItem(const char *fullname, const char *title)
Bool_t ExecuteHttp(std::shared_ptr< THttpCallArg > arg)
Execute HTTP request.
Bool_t Hide(const char *fullname, Bool_t hide=kTRUE)
hides folder or element from web gui
THttpServer(const char *engine="civetweb:8080")
constructor
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 ...
std::map< std::string, std::string > fLocations
! list of local directories, which could be accessed via server
Definition: THttpServer.h:46
Bool_t SubmitHttp(std::shared_ptr< THttpCallArg > arg, Bool_t can_run_immediately=kFALSE)
Submit HTTP request.
Long_t fMainThrdId
! id of the thread for processing requests
Definition: THttpServer.h:38
TString fJSROOTSYS
! location of local JSROOT files
Definition: THttpServer.h:42
Bool_t Register(const char *subfolder, TObject *obj)
Register object in subfolder.
TList fEngines
! engines which runs http server
Definition: THttpServer.h:34
void SetCors(const std::string &domain="*")
Enable CORS header to ProcessRequests() responses Specified location (typically "*") add as "Access-C...
Definition: THttpServer.h:97
Bool_t IsCors() const
Returns kTRUE if CORS was configured.
Definition: THttpServer.h:100
std::queue< std::shared_ptr< THttpCallArg > > fArgs
! submitted arguments
Definition: THttpServer.h:55
void SetDefaultPage(const std::string &filename="")
Set file name of HTML page, delivered by the server when http address is opened in the browser.
static char * ReadFileContent(const char *filename, Int_t &len)
Reads content of file from the disk.
void CreateServerThread()
Creates special thread to process all requests, directed to http server.
std::string fDrawPageCont
! content of draw html page
Definition: THttpServer.h:51
Bool_t Unregister(TObject *obj)
Unregister object.
THttpTimer * fTimer
! timer used to access main thread
Definition: THttpServer.h:35
std::mutex fWSMutex
! mutex to protect WS handler lists
Definition: THttpServer.h:57
Bool_t CreateEngine(const char *engine)
factory method to create different http engines At the moment two engine kinds are supported: civetwe...
Bool_t SetIcon(const char *fullname, const char *iconname)
set name of icon, used in browser together with the item
std::string fDrawPage
! file name for drawing of single element
Definition: THttpServer.h:50
std::string fDefaultPageCont
! content of default html page
Definition: THttpServer.h:49
static Bool_t VerifyFilePath(const char *fname)
Checked that filename does not contains relative path below current directory Used to prevent access ...
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 ...
Bool_t SetItemField(const char *fullname, const char *name, const char *value)
void SetJSROOT(const char *location)
Set location of JSROOT to use with the server One could specify address like: https://root....
std::mutex fMutex
! mutex to protect list with arguments
Definition: THttpServer.h:54
std::string fDefaultPage
! file name for default page name
Definition: THttpServer.h:48
void UnregisterWS(std::shared_ptr< THttpWSHandler > ws)
Unregister WS handler.
static const char * GetMimeType(const char *path)
Guess mime type base on file extension.
TRootSniffer * GetSniffer() const
returns pointer on objects sniffer
Definition: THttpServer.h:81
Bool_t RegisterCommand(const char *cmdname, const char *method, const char *icon=0)
Register command which can be executed from web interface.
Bool_t fTerminated
! termination flag, disables all requests processing
Definition: THttpServer.h:37
void Restrict(const char *path, const char *options)
Restrict access to specified object.
virtual void Add(TObject *obj)
Definition: TList.h:87
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
Definition: TList.cxx:467
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:29
An array of TObjects.
Definition: TObjArray.h:37
Int_t GetLast() const
Return index of last object in array.
Definition: TObjArray.cxx:576
TObject * At(Int_t idx) const
Definition: TObjArray.h:166
Mother of all ROOT objects.
Definition: TObject.h:37
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:357
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:866
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
static const TString & GetRootSys()
Get the rootsys directory in the installation. Static utility function.
Definition: TROOT.cxx:2944
static const TString & GetDataDir()
Get the data directory in the installation. Static utility function.
Definition: TROOT.cxx:3049
Storage of hierarchy scan in TRootSniffer in JSON format.
Storage of hierarchy scan in TRootSniffer in XML format.
void ScanHierarchy(const char *topname, const char *path, TRootSnifferStore *store, Bool_t only_fields=kFALSE)
Method scans normal objects, registered in ROOT.
void SetCurrentCallArg(THttpCallArg *arg)
set current http arguments, which then used in different process methods For instance,...
Bool_t RegisterObject(const char *subfolder, TObject *obj)
Register object in subfolder structure subfolder parameter can have many levels like:
Bool_t IsReadOnly() const
Returns readonly mode.
Definition: TRootSniffer.h:188
Bool_t UnregisterObject(TObject *obj)
unregister (remove) object from folders structures folder itself will remain even when it will be emp...
Bool_t CreateItem(const char *fullname, const char *title)
create item element
virtual Bool_t IsStreamerInfoItem(const char *)
Definition: TRootSniffer.h:236
Bool_t Produce(const std::string &path, const std::string &file, const std::string &options, std::string &res)
Method produce different kind of data out of object Parameter 'path' specifies object or object membe...
void CreateOwnTopFolder()
Create own TFolder structures independent from gROOT This allows to have many independent TRootSniffe...
void Restrict(const char *path, const char *options)
Restrict access to the specified location.
void SetReadOnly(Bool_t on=kTRUE)
When readonly on (default), sniffer is not allowed to change ROOT structures For instance,...
Definition: TRootSniffer.h:185
void SetScanGlobalDir(Bool_t on=kTRUE)
When enabled (default), sniffer scans gROOT for files, canvases, histograms.
Definition: TRootSniffer.h:201
TObject * FindTObjectInHierarchy(const char *path)
Search element in hierarchy, derived from TObject.
const char * GetItemField(TFolder *parent, TObject *item, const char *name)
return field for specified item
virtual ULong_t GetStreamerInfoHash()
Definition: TRootSniffer.h:238
Bool_t SetItemField(const char *fullname, const char *name, const char *value)
set field for specified item
Bool_t RegisterCommand(const char *cmdname, const char *method, const char *icon)
Register command which can be executed from web interface.
Basic string class.
Definition: TString.h:131
Ssiz_t Length() const
Definition: TString.h:405
Bool_t EndsWith(const char *pat, ECaseCompare cmp=kExact) const
Return true if string ends with the specified string.
Definition: TString.cxx:2177
Ssiz_t First(char c) const
Find first occurrence of a character c.
Definition: TString.cxx:499
const char * Data() const
Definition: TString.h:364
void Resize(Ssiz_t n)
Resize the string. Truncate or add blanks as necessary.
Definition: TString.cxx:1095
Ssiz_t Last(char c) const
Find last occurrence of a character c.
Definition: TString.cxx:892
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition: TString.cxx:2197
Bool_t IsNull() const
Definition: TString.h:402
TString & Remove(Ssiz_t pos)
Definition: TString.h:668
TString & Append(const char *cs)
Definition: TString.h:559
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:2311
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2289
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:634
virtual Bool_t ExpandPathName(TString &path)
Expand a pathname getting rid of special shell characters like ~.
Definition: TSystem.cxx:1264
virtual const char * Getenv(const char *env)
Get environment variable.
Definition: TSystem.cxx:1652
static Long_t SelfId()
Static method returning the id for the current thread.
Definition: TThread.cxx:547
Handles synchronous and a-synchronous timer events.
Definition: TTimer.h:51
virtual void Timeout()
Definition: TTimer.h:96
This class represents a WWW compatible URL.
Definition: TUrl.h:35
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:658
void SetOptions(const char *opt)
Definition: TUrl.h:90
void ParseOptions() const
Parse URL options into a key/value map.
Definition: TUrl.cxx:615
Bool_t HasOption(const char *key) const
Returns true if the given key appears in the URL options list.
Definition: TUrl.cxx:669
const Int_t n
Definition: legend1.C:16
const char * cnt
Definition: TXMLSetup.cxx:74
void ws()
Definition: ws.C:66