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