Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
rooturlschemehandler.cpp
Go to the documentation of this file.
1// Author: Sergey Linev <S.Linev@gsi.de>
2// Date: 2017-06-29
3// Warning: This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome!
4
5/*************************************************************************
6 * Copyright (C) 1995-2023, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13
15
16#include "rootwebpage.h" // only because of logger channel
17#include <cstring>
18
19#include <QBuffer>
20#include <QByteArray>
21#include <QFile>
22#include <QWebEngineUrlRequestJob>
23
24#include <ROOT/RLogger.hxx>
25
26#include "THttpServer.h"
27#include "THttpCallArg.h"
28#include "TBase64.h"
29
30/** \class UrlRequestJobHolder
31\ingroup qt5webdisplay
32
33Class UrlRequestJobHolder
34Required to monitor state of QWebEngineUrlRequestJob
35Qt can delete object at any time, therefore one connects destroy signal
36from the request to clear pointer
37
38*/
39
40/////////////////////////////////////////////////////////////////
41/// Constructor
42
43UrlRequestJobHolder::UrlRequestJobHolder(QWebEngineUrlRequestJob *req) : QObject(), fRequest(req)
44{
45 if (fRequest)
46 connect(fRequest, &QObject::destroyed, this, &UrlRequestJobHolder::onRequestDeleted);
47}
48
49/////////////////////////////////////////////////////////////////
50/// destroyed signal handler
51
53{
54 if (fRequest == obj)
55 fRequest = nullptr;
56}
57
58/////////////////////////////////////////////////////////////////
59/// Reset holder
60
62{
63 if (fRequest)
64 disconnect(fRequest, &QObject::destroyed, this, &UrlRequestJobHolder::onRequestDeleted);
65 fRequest = nullptr;
66}
67
68// ===================================================================
69
70/////////////////////////////////////////////////////////////////////////////////////
71/// Class TWebGuiCallArg
72/// Specialized handler of requests in THttpServer with QWebEngine
73////////////////////////////////////////////////////////////////////////////////////
74
76
77protected:
79
80public:
81 explicit TWebGuiCallArg(QWebEngineUrlRequestJob *req = nullptr) : THttpCallArg(), fRequest(req) {}
82
83 virtual ~TWebGuiCallArg() {}
84
85 /** provide WS kind */
86 const char *GetWSKind() const override { return "rawlongpoll"; }
87
88 /** provide WS platform, intentionally keep qt5 here while it only used on client side */
89 const char *GetWSPlatform() const override { return "qt5"; }
90
91 void SendFile(const char *fname)
92 {
93 const char *mime = THttpServer::GetMimeType(fname);
94
95 QBuffer *buffer = new QBuffer;
96
97 QFile file(fname);
98 buffer->open(QIODevice::WriteOnly);
99 if (file.open(QIODevice::ReadOnly)) {
100 auto arr = file.readAll();
101 buffer->write(arr);
102 }
103 file.close();
104 buffer->close();
105
106 QWebEngineUrlRequestJob *req = fRequest.req();
107
108 if (req) {
109 buffer->connect(req, &QObject::destroyed, buffer, &QObject::deleteLater);
110 req->reply(mime, buffer);
111 fRequest.reset();
112 } else {
113 delete buffer;
114 }
115 }
116
117 void HttpReplied() override
118 {
119 QWebEngineUrlRequestJob *req = fRequest.req();
120
121 if (!req) {
122 R__LOG_ERROR(QtWebDisplayLog()) << "Qt " << QT_VERSION_STR << " request already processed path " << GetPathName() << " file " << GetFileName();
123 return;
124 }
125
126 if (Is404()) {
127 R__LOG_ERROR(QtWebDisplayLog()) << "Qt " << QT_VERSION_STR << " request FAIL path " << GetPathName() << " file " << GetFileName();
128
129 req->fail(QWebEngineUrlRequestJob::UrlNotFound);
130 // abort request
131 } else if (IsFile()) {
132 // send file
133 SendFile((const char *)GetContent());
134 } else {
135
136 QBuffer *buffer = new QBuffer;
137
138 buffer->open(QIODevice::WriteOnly);
139
140 buffer->write((const char *)GetContent(), GetContentLength());
141
142 buffer->close();
143
144 buffer->connect(req, &QObject::destroyed, buffer, &QObject::deleteLater);
145
146 req->reply(GetContentType(), buffer);
147 }
148
149 fRequest.reset();
150 }
151};
152
153
154/////////////////////////////////////////////////////////////////
155/// Returns fully qualified URL, required to open in QWindow
156
157QString RootUrlSchemeHandler::MakeFullUrl(THttpServer *serv, const QString &url)
158{
159 // TODO: provide support for many servers
160 fServer = serv;
161
162 QString res = "rootscheme://root.server1";
163 res.append(url);
164 return res;
165}
166
167
168///////////////////////////////////////////////////////////////////////////////////////////////////
169/// Start processing of emulated HTTP request in WebEngine scheme handler
170/// Either one reads file or redirect request to THttpServer
171
172void RootUrlSchemeHandler::requestStarted(QWebEngineUrlRequestJob *request)
173{
174 QUrl url = request->requestUrl();
175
176 if (!fServer) {
177 R__LOG_ERROR(QtWebDisplayLog()) << "Server not specified when request is started";
178 request->fail(QWebEngineUrlRequestJob::UrlNotFound);
179 return;
180 }
181
182 QString inp_path = url.path();
183 QString inp_query = url.query();
184 QString inp_method = request->requestMethod();
185
186 // printf("REQUEST PATH:%s QUERY:%s\n", inp_path.toLatin1().data(), inp_query.toLatin1().data());
187
188 auto arg = std::make_shared<TWebGuiCallArg>(request);
189
190 TString fname;
191
192 // process file
193 if (fServer->IsFileRequested(inp_path.toLatin1().data(), fname)) {
194 arg->SendFile(fname.Data());
195 return;
196 }
197
198 // Analyze and cut post data as soon as possible
199 TString query = inp_query.toLatin1().data();
200 Int_t pos = query.Index("&post=");
201 if (pos != kNPOS) {
202 TString buf = TBase64::Decode(query.Data() + pos + 6);
203 arg->SetPostData(std::string(buf.Data()));
204 query.Resize(pos);
205 }
206
207 arg->SetPathAndFileName(inp_path.toLatin1().data());
208 arg->SetQuery(query.Data());
209 arg->SetMethod(inp_method.toLatin1().data());
210 arg->SetTopName("webgui");
211
212 // can process immediately - function called in main thread
213 fServer->SubmitHttp(arg, kTRUE);
214}
#define R__LOG_ERROR(...)
Definition RLogger.hxx:362
constexpr Ssiz_t kNPOS
Definition RtypesCore.h:124
constexpr Bool_t kTRUE
Definition RtypesCore.h:100
THttpServer * fServer
server instance which should handle requests
QString MakeFullUrl(THttpServer *serv, const QString &url)
Returns fully qualified URL, required to open in QWindow.
void requestStarted(QWebEngineUrlRequestJob *request) override
Start processing of emulated HTTP request in WebEngine scheme handler Either one reads file or redire...
static TString Decode(const char *data)
Decode a base64 string date into a generic TString.
Definition TBase64.cxx:131
Contains arguments for single HTTP call.
Long_t GetContentLength() const
Bool_t Is404() const
const void * GetContent() const
const char * GetPathName() const
returns path name from request URL
const char * GetContentType() const
const char * GetFileName() const
returns file name from request URL
Bool_t IsFile() const
Online http server for arbitrary ROOT application.
Definition THttpServer.h:31
Bool_t IsFileRequested(const char *uri, TString &res) const
Check if file is requested, thread safe.
Bool_t SubmitHttp(std::shared_ptr< THttpCallArg > arg, Bool_t can_run_immediately=kFALSE)
Submit HTTP request.
static const char * GetMimeType(const char *path)
Guess mime type base on file extension.
Basic string class.
Definition TString.h:139
const char * Data() const
Definition TString.h:376
void Resize(Ssiz_t n)
Resize the string. Truncate or add blanks as necessary.
Definition TString.cxx:1152
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:651
Class TWebGuiCallArg Specialized handler of requests in THttpServer with QWebEngine.
UrlRequestJobHolder fRequest
TWebGuiCallArg(QWebEngineUrlRequestJob *req=nullptr)
void SendFile(const char *fname)
void HttpReplied() override
virtual method to inform object that http request is processed
const char * GetWSKind() const override
provide WS kind
const char * GetWSPlatform() const override
provide WS platform, intentionally keep qt5 here while it only used on client side
Class UrlRequestJobHolder Required to monitor state of QWebEngineUrlRequestJob Qt can delete object a...
QWebEngineUrlRequestJob * req() const
void onRequestDeleted(QObject *obj)
destroyed signal handler
void reset()
Reset holder.
UrlRequestJobHolder(QWebEngineUrlRequestJob *req)
Constructor.
QWebEngineUrlRequestJob * fRequest
ROOT::Experimental::RLogChannel & QtWebDisplayLog()