Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
gui_handler.cxx
Go to the documentation of this file.
1/// \file gui_handler.cxx
2// Author: Sergey Linev <S.Linev@gsi.de>
3// Date: 2017-06-29
4// Warning: This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome!
5
6/*************************************************************************
7 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
8 * All rights reserved. *
9 * *
10 * For the licensing terms see $ROOTSYS/LICENSE. *
11 * For the list of contributors see $ROOTSYS/README/CREDITS. *
12 *************************************************************************/
13
14#if !defined(_MSC_VER)
15#pragma GCC diagnostic ignored "-Wunused-parameter"
16#pragma GCC diagnostic ignored "-Wshadow"
17#endif
18
19#include "gui_handler.h"
20#include "simple_app.h"
21
22#include <sstream>
23#include <fstream>
24#include <iostream>
25#include <string>
26
27#include "include/base/cef_bind.h"
28#include "include/cef_app.h"
29#include "include/cef_version.h"
30#include "include/views/cef_browser_view.h"
31#include "include/views/cef_window.h"
32#include "include/wrapper/cef_closure_task.h"
33#include "include/wrapper/cef_helpers.h"
34#include "include/cef_parser.h"
35#include "include/wrapper/cef_stream_resource_handler.h"
36
37#include "TEnv.h"
38#include "TUrl.h"
39#include "THttpServer.h"
40#include "THttpCallArg.h"
41#include "TSystem.h"
42#include "TBase64.h"
43#include <ROOT/RLogger.hxx>
44
46{
47 static ROOT::RLogChannel sChannel("ROOT.CefWebDisplay");
48 return sChannel;
49}
50
51
52GuiHandler::GuiHandler(bool use_views) : fUseViews(use_views), is_closing_(false)
53{
54 fConsole = gEnv->GetValue("WebGui.Console", (int)0);
55
56 // see https://bitbucket.org/chromiumembedded/cef-project/src/master/examples/resource_manager/?at=master for demo
57 // one probably can avoid to use scheme handler and just redirect requests
59}
60
62{
64
65 if (fUseViews) {
66 // Set the title of the window using the Views framework.
67 CefRefPtr<CefBrowserView> browser_view = CefBrowserView::GetForBrowser(browser);
68 if (browser_view) {
69 CefRefPtr<CefWindow> window = browser_view->GetWindow();
70 if (window) window->SetTitle(title);
71 }
72 } else {
73 // Set the title of the window using platform APIs.
75 }
76}
77
79{
81
82 // Add to the list of existing browsers.
83 fBrowserList.emplace_back(browser);
84}
85
87{
89
90 // Closing the main window requires special handling. See the DoClose()
91 // documentation in the CEF header for a detailed description of this
92 // process.
93 if (fBrowserList.size() == 1) {
94 // Set a flag to indicate that the window close should be allowed.
95 is_closing_ = true;
96 }
97
98 // Allow the close. For windowed browsers this will result in the OS close
99 // event being sent.
100 return false;
101}
102
104{
106
107 // Remove from the list of existing browsers.
108 auto bit = fBrowserList.begin();
109 for (; bit != fBrowserList.end(); ++bit) {
110 if ((*bit)->IsSame(browser)) {
111 fBrowserList.erase(bit);
112 break;
113 }
114 }
115
116 if (fBrowserList.empty()) {
117
118 // All browser windows have closed. Quit the application message loop.
119
121 }
122}
123
124// Returns a data: URI with the specified contents.
125std::string GuiHandler::GetDataURI(const std::string& data, const std::string& mime_type)
126{
127 return std::string("data:") + mime_type + ";base64," +
128 CefURIEncode(CefBase64Encode(data.data(), data.size()), false).ToString();
129}
130
131
133 const CefString &errorText, const CefString &failedUrl)
134{
136
137 // Don't display an error for downloaded files.
138 if (errorCode == ERR_ABORTED)
139 return;
140
141 // Display a load error message.
142 /*
143 std::stringstream ss;
144 ss << "<html><body bgcolor=\"white\">"
145 "<h2>Failed to load URL "
146 << failedUrl.ToString().substr(0,100) << " with error " << errorText.ToString() << " (" << errorCode
147 << ").</h2></body></html>";
148 frame->LoadURL(GetDataURI(ss.str(), "text/html"));
149 */
150
151 printf("Fail to load URL %s\n", failedUrl.ToString().substr(0,100).c_str());
152}
153
155{
156 if (!CefCurrentlyOn(TID_UI)) {
157 // Execute on the UI thread.
159 return;
160 }
161
162 if (fBrowserList.empty())
163 return;
164
165 for (auto &br : fBrowserList)
166 br->GetHost()->CloseBrowser(force_close);
167}
168
170 cef_log_severity_t level,
171 const CefString &message, const CefString &source,
172 int line)
173{
174 std::string src = source.ToString().substr(0,100);
175
176 switch (level) {
178 if (fConsole > -1)
179 std::cout << TString::Format("CEF: %s:%d: %s", src.c_str(), line, message.ToString().c_str()) << std::endl;
180 break;
182 if (fConsole > -2)
183 std::cerr << TString::Format("CEF: %s:%d: %s", src.c_str(), line, message.ToString().c_str()) << std::endl;
184 break;
185 default:
186 if (fConsole > 0)
187 std::cout << TString::Format("CEF: %s:%d: %s", src.c_str(), line, message.ToString().c_str()) << std::endl;
188 break;
189 }
190
191 return true;
192}
193
194
198 CefRefPtr<CefRequest> request,
199 CefRefPtr<CefCallback> callback) {
201
202 return fResourceManager->OnBeforeResourceLoad(browser, frame, request,
203 callback);
204}
205
206
208protected:
209
211
212public:
213 explicit TCefHttpCallArg() = default;
214
215 /** provide WS kind */
216 const char *GetWSKind() const override { return "longpoll"; }
217
218 /** provide WS platform */
219 const char *GetWSPlatform() const override { return "cef3"; }
220
222
223 // this is callback from HTTP server
224 void HttpReplied() override
225 {
226 if (IsFile()) {
227 // send file
228 std::string file_content = THttpServer::ReadFileContent((const char *)GetContent());
229 SetContent(std::move(file_content));
230 }
231
232 fCallBack->Continue(); // we have result and can continue with processing
233 }
234};
235
236
238public:
239 // QWebEngineUrlRequestJob *fRequest;
240
242 std::shared_ptr<TCefHttpCallArg> fArg;
243
245
246 explicit TGuiResourceHandler(THttpServer *serv, bool dummy = false)
247 {
248 fServer = serv;
249
250 if (!dummy)
251 fArg = std::make_shared<TCefHttpCallArg>();
252 }
253
255
256 void Cancel() override { CEF_REQUIRE_IO_THREAD(); }
257
259 {
261
262 if (fArg) {
263 fArg->AssignCallback(callback);
265 } else {
266 callback->Continue();
267 }
268
269 return true;
270 }
271#if CEF_VERSION_MAJOR > 114
273#else
275#endif
276 {
278
279 if (!fArg || fArg->Is404()) {
280 response->SetMimeType("text/html");
281 response->SetStatus(404);
282 response_length = 0;
283 } else {
284 response->SetMimeType(fArg->GetContentType());
285 response->SetStatus(200);
286 response_length = fArg->GetContentLength();
287
288 if (fArg->NumHeader() > 0) {
289 CefResponse::HeaderMap headers;
290 for (Int_t n = 0; n < fArg->NumHeader(); ++n) {
291 TString name = fArg->GetHeaderName(n);
292 TString value = fArg->GetHeader(name.Data());
293 headers.emplace(CefString(name.Data()), CefString(value.Data()));
294 }
295 response->SetHeaderMap(headers);
296 }
297 }
298 // DCHECK(!fArg->Is404());
299 }
300
301 bool ReadResponse(void *data_out, int bytes_to_read, int &bytes_read, CefRefPtr<CefCallback> callback) override
302 {
304
305 if (!fArg) return false;
306
307 bytes_read = 0;
308
309 if (fTransferOffset < fArg->GetContentLength()) {
310 char *data_ = (char *)fArg->GetContent();
311 // Copy the next block of data into the buffer.
312 int transfer_size = fArg->GetContentLength() - fTransferOffset;
317
319 }
320
321 // if content fully copied - can release reference, object will be cleaned up
322 if (fTransferOffset >= fArg->GetContentLength())
323 fArg.reset();
324
325 return bytes_read > 0;
326 }
327
330};
331
332
336 CefRefPtr<CefRequest> request) {
338
339 std::string addr = request->GetURL().ToString();
340 std::string prefix = "http://rootserver.local";
341
342 if (addr.compare(0, prefix.length(), prefix) != 0)
343 return fResourceManager->GetResourceHandler(browser, frame, request);
344
345 int indx = std::stoi(addr.substr(prefix.length(), addr.find("/", prefix.length()) - prefix.length()));
346
347 if ((indx < 0) || (indx >= (int) fServers.size()) || !fServers[indx]) {
348 R__LOG_ERROR(CefWebDisplayLog()) << "No THttpServer with index " << indx;
349 return nullptr;
350 }
351
353 if (serv->IsZombie()) {
354 fServers[indx] = nullptr;
355 R__LOG_ERROR(CefWebDisplayLog()) << "THttpServer with index " << indx << " is zombie now";
356 return nullptr;
357 }
358
359 TUrl url(addr.c_str());
360
361 const char *inp_path = url.GetFile();
362
363 TString inp_query = url.GetOptions();
364
366
367 if (serv->IsFileRequested(inp_path, fname)) {
368 // process file - no need for special requests handling
369
370 std::ifstream ifs(fname.Data());
371 // when file not exists - return default handler otherwise CEF terminates
372 if (!ifs)
373 return new TGuiResourceHandler(serv, true);
374
375 const char *mime = THttpServer::GetMimeType(fname.Data());
376
377 CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForFile(fname.Data());
378
379 // Constructor for HTTP status code 200 and no custom response headers.
380 // There’s also a version of the constructor for custom status code and response headers.
381 return new CefStreamResourceHandler(mime, stream);
382 }
383
384 std::string inp_method = request->GetMethod().ToString();
385
387 handler->fArg->SetMethod(inp_method.c_str());
388 handler->fArg->SetPathAndFileName(inp_path);
389 handler->fArg->SetTopName("webgui");
390
391 if (inp_method == "POST") {
392
393 CefRefPtr< CefPostData > post_data = request->GetPostData();
394
395 if (!post_data) {
396 R__LOG_ERROR(CefWebDisplayLog()) << "FATAL - NO POST DATA in CEF HANDLER!!!";
397 exit(1);
398 } else {
399 CefPostData::ElementVector elements;
400 post_data->GetElements(elements);
401 size_t sz = 0, off = 0;
402 for (unsigned n = 0; n < elements.size(); ++n)
403 sz += elements[n]->GetBytesCount();
404 std::string data;
405 data.resize(sz);
406
407 for (unsigned n = 0; n < elements.size(); ++n) {
408 sz = elements[n]->GetBytes(elements[n]->GetBytesCount(), (char *)data.data() + off);
409 off += sz;
410 }
411 handler->fArg->SetPostData(std::move(data));
412 }
413 } else if (inp_query.Index("&post=") != kNPOS) {
414 Int_t pos = inp_query.Index("&post=");
415 TString buf = TBase64::Decode(inp_query.Data() + pos + 6);
416 handler->fArg->SetPostData(std::string(buf.Data()));
417 inp_query.Resize(pos);
418 }
419
420 handler->fArg->SetQuery(inp_query.Data());
421
422 // just return handler
423 return handler;
424}
425
426///////////////////////////////////////////////////////////////////////////////////////////////////
427/// Generate URL for batch page
428/// Uses file:/// prefix to let access JSROOT scripts placed on file system
429/// Register provider for that page in resource manager
430
431std::string GuiHandler::AddBatchPage(const std::string &cont)
432{
433 std::string url = "file:///batch_page";
434 url.append(std::to_string(fBatchPageCount++));
435 url.append(".html");
436
437 fResourceManager->AddContentProvider(url, cont, "text/html", 0, std::string());
438 return url;
439}
440
441///////////////////////////////////////////////////////////////////////////////////////////////////
442/// Generate URL for RWebWindow page
443/// Register server instance and assign it with the index
444/// Produced URL only works inside CEF and does not represent real HTTP address
445
446std::string GuiHandler::MakePageUrl(THttpServer *serv, const std::string &addr)
447{
448 unsigned indx = 0;
449 while ((indx < fServers.size()) && (fServers[indx] != serv)) indx++;
450 if (indx >= fServers.size()) {
451 fServers.emplace_back(serv);
452 indx = fServers.size() - 1;
453 }
454
455 return std::string("http://rootserver.local") + std::to_string(indx) + addr;
456}
457
#define R__LOG_ERROR(...)
Definition RLogger.hxx:356
constexpr Ssiz_t kNPOS
The equivalent of std::string::npos for the ROOT class TString.
Definition RtypesCore.h:131
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
R__EXTERN TEnv * gEnv
Definition TEnv.h:126
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t src
char name[80]
Definition TGX11.cxx:148
const char * mime_type
Definition civetweb.c:8517
CefRefPtr< CefResourceManager > fResourceManager
bool is_closing_
Definition gui_handler.h:50
int fConsole
! console parameter, assigned via WebGui.Console rootrc parameter
Definition gui_handler.h:44
GuiHandler(bool use_views=false)
std::vector< THttpServer * > fServers
Definition gui_handler.h:48
void OnBeforeClose(CefRefPtr< CefBrowser > browser) override
CefRefPtr< CefResourceHandler > GetResourceHandler(CefRefPtr< CefBrowser > browser, CefRefPtr< CefFrame > frame, CefRefPtr< CefRequest > request) override
bool DoClose(CefRefPtr< CefBrowser > browser) override
BrowserList fBrowserList
Definition gui_handler.h:46
void CloseAllBrowsers(bool force_close)
int fBatchPageCount
void PlatformTitleChange(CefRefPtr< CefBrowser > browser, const CefString &title)
cef_return_value_t OnBeforeResourceLoad(CefRefPtr< CefBrowser > browser, CefRefPtr< CefFrame > frame, CefRefPtr< CefRequest > request, CefRefPtr< CefCallback > callback) override
void OnLoadError(CefRefPtr< CefBrowser > browser, CefRefPtr< CefFrame > frame, ErrorCode errorCode, const CefString &errorText, const CefString &failedUrl) override
static std::string GetDataURI(const std::string &data, const std::string &mime_type)
bool fUseViews
! if view framework is used, required for true headless mode
Definition gui_handler.h:43
std::string AddBatchPage(const std::string &cont)
Generate URL for batch page Uses file:/// prefix to let access JSROOT scripts placed on file system R...
std::string MakePageUrl(THttpServer *serv, const std::string &addr)
Generate URL for RWebWindow page Register server instance and assign it with the index Produced URL o...
bool OnConsoleMessage(CefRefPtr< CefBrowser > browser, cef_log_severity_t level, const CefString &message, const CefString &source, int line) override
void OnTitleChange(CefRefPtr< CefBrowser > browser, const CefString &title) override
void OnAfterCreated(CefRefPtr< CefBrowser > browser) override
A log configuration for a channel, e.g.
Definition RLogger.hxx:97
static TString Decode(const char *data)
Decode a base64 string date into a generic TString.
Definition TBase64.cxx:130
void AssignCallback(CefRefPtr< CefCallback > cb)
void HttpReplied() override
virtual method to inform object that http request is processed
const char * GetWSPlatform() const override
provide WS platform
CefRefPtr< CefCallback > fCallBack
const char * GetWSKind() const override
provide WS kind
TCefHttpCallArg()=default
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
Definition TEnv.cxx:511
~TGuiResourceHandler() override
bool ProcessRequest(CefRefPtr< CefRequest > request, CefRefPtr< CefCallback > callback) override
DISALLOW_COPY_AND_ASSIGN(TGuiResourceHandler)
std::shared_ptr< TCefHttpCallArg > fArg
IMPLEMENT_REFCOUNTING(TGuiResourceHandler)
bool ReadResponse(void *data_out, int bytes_to_read, int &bytes_read, CefRefPtr< CefCallback > callback) override
TGuiResourceHandler(THttpServer *serv, bool dummy=false)
THttpServer * fServer
void GetResponseHeaders(CefRefPtr< CefResponse > response, int64 &response_length, CefString &redirectUrl) override
void Cancel() override
Contains arguments for single HTTP call.
const void * GetContent() const
void SetContent(const char *cont)
Set content as text.
Bool_t IsFile() const
Online http server for arbitrary ROOT application.
Definition THttpServer.h:31
Bool_t SubmitHttp(std::shared_ptr< THttpCallArg > arg, Bool_t can_run_immediately=kFALSE)
Submit HTTP request.
static char * ReadFileContent(const char *filename, Int_t &len)
Reads content of file from the disk.
static const char * GetMimeType(const char *path)
Guess mime type base on file extension.
Basic string class.
Definition TString.h:138
const char * Data() const
Definition TString.h:384
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:2385
This class represents a WWW compatible URL.
Definition TUrl.h:33
TLine * line
ROOT::RLogChannel & CefWebDisplayLog()
ROOT::RLogChannel & CefWebDisplayLog()
const Int_t n
Definition legend1.C:16