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