50 const char *undef =
"<undefined>";
51 const char *value =
gEnv->GetValue(
name.c_str(), undef);
52 if (!value)
return dflt;
53 std::string svalue = value;
54 if (svalue == undef)
return dflt;
56 if (svalue ==
"yes")
return 1;
57 if (svalue ==
"no")
return 0;
81 static std::shared_ptr<RWebWindowsManager> sInstance = std::make_shared<RWebWindowsManager>();
135 printf(
"\nWARNING!\n");
136 printf(
"Disabling loopback mode may leads to security problem.\n");
137 printf(
"See https://root.cern/about/security/ for more information.\n\n");
141 printf(
"Enforce session key to safely work on public network.\n");
142 printf(
"One may call RWebWindowsManager::SetUseSessionKey(false); to disable it.\n");
175 gEnv->SetValue(
"WebGui.OnetimeKey", on ?
"yes" :
"no");
187 gEnv->SetValue(
"WebGui.SingleConnMode", on ?
"yes" :
"no");
197 if (server_prefix.empty() || files_path.empty())
200 std::string prefix = server_prefix;
201 if (prefix.back() !=
'/')
203 loc[prefix] = files_path;
207 for (
auto &entry : loc) {
210 cfg.
Append(entry.first.c_str());
212 cfg.
Append(entry.second.c_str());
215 gEnv->SetValue(
"WebGui.ServerLocations", cfg);
217 auto serv =
Instance()->GetServer();
219 serv->AddLocation(prefix.c_str(), files_path.c_str());
228 std::map<std::string, std::string> res;
230 TString cfg =
gEnv->GetValue(
"WebGui.ServerLocations",
"");
234 while(
auto obj = next()) {
237 auto p = arg.
First(
":");
238 if (p ==
kNPOS)
continue;
258 gEnv->SetValue(
"WebGui.ServerLocations",
"");
269 std::vector<unsigned char> buf(keylen, 0);
270 auto res =
gSystem->GetCryptoRandom(buf.data(), keylen);
272 R__ASSERT(res == keylen &&
"Error in gSystem->GetCryptoRandom");
275 for (
int n = 0;
n < keylen;
n++) {
276 if ((
n > 0) && (
n % 4 == 0))
281 key.append(t.Data());
324 const char *fname =
gSystem->Getenv(
"ROOT_LISTENER_SOCKET");
325 if (!fname || !*fname)
330 R__LOG_ERROR(
WebGUILog()) <<
"Problem with open listener socket " << fname <<
", check ROOT_LISTENER_SOCKET environment variable";
334 int res = s.
SendRaw(msg.c_str(), msg.length());
447 if (
gROOT->GetWebDisplay() ==
"off")
451 std::lock_guard<std::recursive_mutex> grd(
fMutex);
455 fServer = std::make_unique<THttpServer>(
"basic_sniffer");
466 if (send_thrds != -1)
481 ui5dir =
gEnv->GetValue(
"WebGui.RootUi5Path",
"");
486 if (
gSystem->ExpandPathName(ui5dir)) {
487 R__LOG_ERROR(
WebGUILog()) <<
"Path to ROOT ui5 sources " << ui5dir <<
" not found, set ROOTUI5SYS correctly";
491 fServer->AddLocation(
"rootui5sys/", ui5dir.
Data());
494 for (
auto &entry : loc)
495 fServer->AddLocation(entry.first.c_str(), entry.second.c_str());
498 if (!with_http ||
fServer->IsAnyEngine())
501 int http_port =
gEnv->GetValue(
"WebGui.HttpPort", 0);
502 int http_min =
gEnv->GetValue(
"WebGui.HttpPortMin", 8800);
503 int http_max =
gEnv->GetValue(
"WebGui.HttpPortMax", 9800);
504 int http_timer =
gEnv->GetValue(
"WebGui.HttpTimer", 10);
505 int http_thrds =
gEnv->GetValue(
"WebGui.HttpThreads", 10);
506 int http_wstmout =
gEnv->GetValue(
"WebGui.HttpWSTmout", 10000);
507 int http_maxage =
gEnv->GetValue(
"WebGui.HttpMaxAge", -1);
508 const char *extra_args =
gEnv->GetValue(
"WebGui.HttpExtraArgs",
"");
509 int fcgi_port =
gEnv->GetValue(
"WebGui.FastCgiPort", 0);
510 int fcgi_thrds =
gEnv->GetValue(
"WebGui.FastCgiThreads", 10);
511 const char *fcgi_serv =
gEnv->GetValue(
"WebGui.FastCgiServer",
"");
515 const char *http_bind =
gEnv->GetValue(
"WebGui.HttpBind",
"");
517 const char *ssl_cert =
gEnv->GetValue(
"WebGui.ServerCert",
"rootserver.pem");
519 const char *unix_socket =
gSystem->Getenv(
"ROOT_WEBGUI_SOCKET");
520 if (!unix_socket || !*unix_socket)
521 unix_socket =
gEnv->GetValue(
"WebGui.UnixSocket",
"");
522 const char *unix_socket_mode =
gEnv->GetValue(
"WebGui.UnixSocketMode",
"0700");
523 bool use_unix_socket = unix_socket && *unix_socket;
526 fcgi_port = http_port = -1;
533 if ((http_port < 0) && (fcgi_port <= 0) && !use_unix_socket) {
548 if (http_max - http_min < ntry)
549 ntry = http_max - http_min;
558 while (ntry-- >= 0) {
559 if ((http_port == 0) && (fcgi_port <= 0) && !use_unix_socket) {
560 if ((http_min <= 0) || (http_max <= http_min)) {
561 R__LOG_ERROR(
WebGUILog()) <<
"Wrong HTTP range configuration, check WebGui.HttpPortMin/Max variables";
565 http_port = (
int)(http_min + (http_max - http_min) * rnd.
Rndm(1));
570 engine.
Form(
"fastcgi:%d?thrds=%d", fcgi_port, fcgi_thrds);
571 if (!
fServer->CreateEngine(engine))
573 if (fcgi_serv && (strlen(fcgi_serv) > 0))
579 if (use_unix_socket) {
580 engine.
Form(
"socket:%s?socket_mode=%s&", unix_socket, unix_socket_mode);
582 url = use_secure ?
"https://" :
"http://";
583 engine.
Form(
"%s:%d?", (use_secure ?
"https" :
"http"), http_port);
584 if (assign_loopback) {
585 engine.
Append(
"loopback&");
587 }
else if (http_bind && (strlen(http_bind) > 0)) {
595 engine.
Append(
TString::Format(
"webgui&top=remote&thrds=%d&websocket_timeout=%d", http_thrds, http_wstmout));
597 if (http_maxage >= 0)
600 if (use_secure && !strchr(ssl_cert,
'&')) {
601 engine.
Append(
"&ssl_cert=");
605 if (!use_unix_socket && !assign_loopback && extra_args && strlen(extra_args) > 0) {
607 engine.
Append(extra_args);
610 if (
fServer->CreateEngine(engine)) {
611 if (use_unix_socket) {
613 fAddr.append(unix_socket);
615 }
else if (http_port > 0) {
618 fAddr.append(std::to_string(http_port));
623 use_unix_socket =
false;
638 std::lock_guard<std::recursive_mutex> grd(
fMutex);
645 std::shared_ptr<RWebWindow> win = std::make_shared<RWebWindow>();
652 double dflt_tmout =
gEnv->GetValue(
"WebGui.OperationTmout", 50.);
654 auto wshandler = win->CreateWSHandler(
Instance(), ++
fIdCnt, dflt_tmout);
657 std::string fname, prefix;
659 prefix = std::string(
"f") + std::to_string(
fIdCnt) +
"_";
660 fname = std::string(
"protcol") + std::to_string(
fIdCnt) +
".json";
662 fname =
"protocol.json";
664 win->RecordData(fname, prefix);
667 int queuelen =
gEnv->GetValue(
"WebGui.QueueLength", 10);
669 win->SetMaxQueueLength(queuelen);
675 win->fUseProcessEvents =
true;
679 win->UseServerThreads();
681 const char *token =
gEnv->GetValue(
"WebGui.ConnToken",
"");
683 win->SetConnToken(token);
685 fServer->RegisterWS(wshandler);
713 std::string addr =
"/";
724 addr.append(
"?key=");
727 std::unique_ptr<ROOT::RWebDisplayHandle> dummy;
732 if (!token.empty()) {
733 addr.append(qmark ?
"&" :
"?");
734 addr.append(
"token=");
825 auto handle = std::make_unique<RWebDisplayHandle>(
"");
848 std::string url =
GetUrl(win, normal_http, &key);
854 std::lock_guard<std::recursive_mutex> grd(
fMutex);
871 auto winurl = args.
GetUrl();
872 winurl.erase(0,
fAddr.length());
879 server->AddLocation(
"currentdir/",
".");
882 std::cout <<
"New web window: " << args.
GetUrl() << std::endl;
886 if (
fAddr.compare(0,9,
"socket://") == 0)
889#if !defined(R__MACOSX) && !defined(R__WIN32)
891 const char *varname =
"WebGui.CheckRemoteDisplay";
893 const char *displ =
gSystem->Getenv(
"DISPLAY");
894 if (displ && *displ && (*displ !=
':')) {
895 gEnv->SetValue(varname,
"no");
897 "ROOT web-based widget started in the session where DISPLAY set to " << displ <<
"\n" <<
898 "Means web browser will be displayed on remote X11 server which is usually very inefficient\n"
899 "One can start ROOT session in server mode like \"root -b --web=server:8877\" and forward http port to display node\n"
900 "Or one can use rootssh script to configure port forwarding and display web widgets automatically\n"
901 "Find more info on https://root.cern/for_developers/root7/#rbrowser\n"
902 "This message can be disabled by setting \"" << varname <<
": no\" in .rootrc file\n";
935 int res = 0, cnt = 0;
938 auto start = std::chrono::high_resolution_clock::now();
944 while ((res = check(spent)) == 0) {
953 std::this_thread::sleep_for(std::chrono::milliseconds(cnt > 5000 ? 10 : 1));
955 std::chrono::duration<double, std::milli> elapsed = std::chrono::high_resolution_clock::now() -
start;
957 spent = elapsed.count() * 1
e-3;
959 if (timed && (spent > timelimit))
#define R__LOG_ERROR(...)
static bool gWebWinMainThrdSet
static std::thread::id gWebWinMainThrd
This thread id used to identify main application thread, where ROOT event processing runs To inject c...
static bool gWebWinLoopbackMode
static bool gWebWinUseSessionKey
constexpr Ssiz_t kNPOS
The equivalent of std::string::npos for the ROOT class TString.
externTApplication * gApplication
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Holds different arguments for starting browser with RWebDisplayHandle::Display() method.
std::string GetBrowserName() const
Returns configured browser name.
EBrowserKind GetBrowserKind() const
returns configured browser kind, see EBrowserKind for supported values
RWebDisplayArgs & SetX(int x=-1)
set preferable web window x position, negative is default
bool IsSupportHeadless() const
returns true if browser supports headless mode
RWebDisplayArgs & SetUrl(const std::string &url)
set window url
int GetWidth() const
returns preferable web window width
const std::string & GetUrl() const
returns window url
void AppendUrlOpt(const std::string &opt)
append extra url options, add "&" as separator if required
int GetY() const
set preferable web window y position
int GetHeight() const
returns preferable web window height
void SetHttpServer(THttpServer *serv)
set http server instance, used for window display
RWebDisplayArgs & SetWidth(int w=0)
set preferable web window width
bool IsInteractiveBrowser() const
returns true if interactive browser window supposed to be started
RWebDisplayArgs & SetY(int y=-1)
set preferable web window y position, negative is default
bool IsHeadless() const
returns headless mode
RWebDisplayArgs & SetHeight(int h=0)
set preferable web window height
@ kServer
indicates that ROOT runs as server and just printouts window URL, browser should be started by the us...
@ kOff
disable web display, do not start any browser
@ kEmbedded
window will be embedded into other, no extra browser need to be started
int GetX() const
set preferable web window x position
static bool NeedHttpServer(const RWebDisplayArgs &args)
Check if http server required for display.
static std::unique_ptr< RWebDisplayHandle > Display(const RWebDisplayArgs &args)
Create web display.
static int GetBoolEnv(const std::string &name, int dfl=-1)
Parse boolean gEnv variable which should be "yes" or "no".
void RemoveKey(const std::string &key)
Removes all connections with the key.
void Sync()
Special method to process all internal activity when window runs in separate thread.
unsigned AddDisplayHandle(bool headless_mode, const std::string &key, std::unique_ptr< RWebDisplayHandle > &handle)
Add display handle and associated key Key is large random string generated when starting new window W...
int GetX() const
returns configured window X position (-1 - default)
unsigned GetHeight() const
returns configured window height (0 - default)
std::shared_ptr< RWebWindowWSHandler > fWSHandler
! specialize websocket handler for all incoming connections
std::string GetConnToken() const
Returns configured connection token.
bool IsRequireAuthKey() const
returns true if authentication string is required
int GetY() const
returns configured window Y position (-1 - default)
unsigned GetWidth() const
returns configured window width (0 - default) actual window width can be different
bool IsUseCurrentDir() const
returns true if window can access local files via currentdir/ path of http server
std::string GenerateKey() const
Generate new unique key for the window.
static void AddServerLocation(const std::string &server_prefix, const std::string &files_path)
Configure server location which can be used for loading of custom scripts or files When THttpServer i...
static std::string GenerateKey(int keylen=32)
Static method to generate cryptographic key Parameter keylen defines length of cryptographic key in b...
bool fUseSessionKey
! is session key has to be used for data signing
bool CreateServer(bool with_http=false)
Creates http server, if required - with real http engine (civetweb) One could configure concrete HTTP...
static void SetUseConnectionKey(bool on=true)
Enable or disable usage of connection key (default on) If enabled, each connection (and reconnection)...
bool fExternalProcessEvents
! indicate that there are external process events engine
std::recursive_mutex fMutex
! main mutex, used for window creations
RWebWindowsManager()
window manager constructor Required here for correct usage of unique_ptr<THttpServer>
int WaitFor(RWebWindow &win, WebWindowWaitFunc_t check, bool timed=false, double tm=-1)
Waits until provided check function or lambdas returns non-zero value Regularly calls WebWindow::Sync...
static void ClearServerLocations()
Clear all server locations Does not change configuration of already running HTTP server.
WebWindowShowCallback_t fShowCallback
! function called for each RWebWindow::Show call
WebWindowDeleteCallback_t fDeleteCallback
! function called when RWebWindow is destroyed
unsigned ShowWindow(RWebWindow &win, const RWebDisplayArgs &args)
Show window in specified location, see Show() method for more details.
std::string fAddr
! HTTP address of the server
void Terminate()
Terminate http server and ROOT application.
unsigned fIdCnt
! counter for identifiers
~RWebWindowsManager()
window manager destructor Required here for correct usage of unique_ptr<THttpServer>
THttpServer * GetServer() const
Returns THttpServer instance.
std::string fSessionKey
! secret session key used on client to code connections keys
bool fUseHttpThrd
! use special thread for THttpServer
static void AssignMainThrd()
Re-assigns main thread id Normally main thread id recognized at the moment when library is loaded It ...
static void SetUseSessionKey(bool on=true)
Enable or disable usage of session key (default on) If enabled, secrete session key used to calculate...
static void SetSingleConnMode(bool on=true)
Enable or disable single connection mode (default on) If enabled, one connection only with any web wi...
float fReconnectTmout
! timeout in seconds to reconnect connection, default 15s
bool IsUseHttpThread() const
Returns true if http server use special thread for requests processing (default off).
bool fUseSenderThreads
! use extra threads for sending data from RWebWindow to clients
std::unique_ptr< THttpServer > fServer
! central communication with the all used displays
static void SetLoopbackMode(bool on=true)
Set loopback mode for THttpServer used for web widgets By default is on.
static bool IsMainThrd()
Returns true when called from main process Main process recognized at the moment when library is load...
static std::shared_ptr< RWebWindowsManager > & Instance()
Returns default window manager Used to display all standard ROOT elements like TCanvas or TFitPanel.
bool InformListener(const std::string &msg)
If ROOT_LISTENER_SOCKET variable is configured, message will be sent to that unix socket.
float fLaunchTmout
! timeout in seconds to start browser process, default 30s
static std::map< std::string, std::string > GetServerLocations()
Returns server locations as <std::string, std::string> Key is location name (with slash at the end) a...
std::string GetUrl(RWebWindow &win, bool remote=false, std::string *produced_key=nullptr)
Provide URL address to access specified window from inside or from remote.
void Unregister(RWebWindow &win)
Release all references to specified window Called from RWebWindow destructor.
static bool IsLoopbackMode()
Returns true if loopback mode used by THttpServer for web widgets.
std::shared_ptr< RWebWindow > CreateWindow()
Creates new window To show window, RWebWindow::Show() have to be called.
static const TString & GetDataDir()
Get the data directory in the installation. Static utility function.
Random number generator class based on M.
Double_t Rndm() override
Machine independent random number generator.
void SetSeed(ULong_t seed=0) override
Set the random generator sequence.
This class implements client sockets.
virtual void Close(Option_t *opt="")
Close the socket.
virtual Int_t SendRaw(const void *buffer, Int_t length, ESendRecvOptions opt=kDefault)
Send a raw buffer of specified length.
virtual Bool_t IsValid() const
Bool_t EndsWith(const char *pat, ECaseCompare cmp=kExact) const
Return true if string ends with the specified string.
Ssiz_t First(char c) const
Find first occurrence of a character c.
const char * Data() const
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
TString & Append(const char *cs)
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
static TString Itoa(Int_t value, Int_t base)
Converts an Int_t to a TString with respect to the base specified (2-36).
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
static void SingleShot(Int_t milliSec, const char *receiver_class, void *receiver, const char *method)
This static function calls a slot after a given time interval.
std::function< int(double)> WebWindowWaitFunc_t
function signature for waiting call-backs Such callback used when calling thread need to waits for so...
ROOT::RLogChannel & WebGUILog()
Log channel for WebGUI diagnostics.