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 */
89 const char *GetWSPlatform() const override
90 {
91 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
92 return "qt6";
93 #else
94 return "qt5";
95 #endif
96 }
97
98 void SendFile(const char *fname)
99 {
100 const char *mime = THttpServer::GetMimeType(fname);
101
102 QBuffer *buffer = new QBuffer;
103
104 QFile file(fname);
105 buffer->open(QIODevice::WriteOnly);
106 if (file.open(QIODevice::ReadOnly)) {
107 auto arr = file.readAll();
108 buffer->write(arr);
109 }
110 file.close();
111 buffer->close();
112
113 QWebEngineUrlRequestJob *req = fRequest.req();
114
115 if (req) {
116 buffer->connect(req, &QObject::destroyed, buffer, &QObject::deleteLater);
117 req->reply(mime, buffer);
118 fRequest.reset();
119 } else {
120 delete buffer;
121 }
122 }
123
124 void HttpReplied() override
125 {
126 QWebEngineUrlRequestJob *req = fRequest.req();
127
128 if (!req) {
129 R__LOG_ERROR(QtWebDisplayLog()) << "Qt " << QT_VERSION_STR << " request already processed path " << GetPathName() << " file " << GetFileName();
130 return;
131 }
132
133 if (Is404()) {
134 R__LOG_ERROR(QtWebDisplayLog()) << "Qt " << QT_VERSION_STR << " request FAIL path " << GetPathName() << " file " << GetFileName();
135
136 req->fail(QWebEngineUrlRequestJob::UrlNotFound);
137 // abort request
138 } else if (IsFile()) {
139 // send file
140 SendFile((const char *)GetContent());
141 } else {
142
143 QBuffer *buffer = new QBuffer;
144
145 buffer->open(QIODevice::WriteOnly);
146
147 buffer->write((const char *)GetContent(), GetContentLength());
148
149 buffer->close();
150
151 buffer->connect(req, &QObject::destroyed, buffer, &QObject::deleteLater);
152
153 req->reply(GetContentType(), buffer);
154 }
155
156 fRequest.reset();
157 }
158};
159
160
161/////////////////////////////////////////////////////////////////
162/// Returns fully qualified URL, required to open in QWindow
163
164QString RootUrlSchemeHandler::MakeFullUrl(THttpServer *serv, const QString &url)
165{
166 // TODO: provide support for many servers
167 fServer = serv;
168
169 QString res = "rootscheme://root.server1";
170 res.append(url);
171 return res;
172}
173
174
175///////////////////////////////////////////////////////////////////////////////////////////////////
176/// Start processing of emulated HTTP request in WebEngine scheme handler
177/// Either one reads file or redirect request to THttpServer
178
179void RootUrlSchemeHandler::requestStarted(QWebEngineUrlRequestJob *request)
180{
181 QUrl url = request->requestUrl();
182
183 if (!fServer) {
184 R__LOG_ERROR(QtWebDisplayLog()) << "Server not specified when request is started";
185 request->fail(QWebEngineUrlRequestJob::UrlNotFound);
186 return;
187 }
188
189 QString inp_path = url.path();
190 QString inp_query = url.query();
191 QString inp_method = request->requestMethod();
192
193 // printf("REQUEST PATH:%s QUERY:%s\n", inp_path.toLatin1().data(), inp_query.toLatin1().data());
194
195 auto arg = std::make_shared<TWebGuiCallArg>(request);
196
197 TString fname;
198
199 // process file
200 if (fServer->IsFileRequested(inp_path.toLatin1().data(), fname)) {
201 arg->SendFile(fname.Data());
202 return;
203 }
204
205 // Analyze and cut post data as soon as possible
206 TString query = inp_query.toLatin1().data();
207 Int_t pos = query.Index("&post=");
208 if (pos != kNPOS) {
209 TString buf = TBase64::Decode(query.Data() + pos + 6);
210 arg->SetPostData(std::string(buf.Data()));
211 query.Resize(pos);
212 }
213
214 arg->SetPathAndFileName(inp_path.toLatin1().data());
215 arg->SetQuery(query.Data());
216 arg->SetMethod(inp_method.toLatin1().data());
217 arg->SetTopName("webgui");
218
219 // can process immediately - function called in main thread
220 fServer->SubmitHttp(arg, kTRUE);
221}
#define R__LOG_ERROR(...)
Definition RLogger.hxx:362
constexpr Ssiz_t kNPOS
Definition RtypesCore.h:117
constexpr Bool_t kTRUE
Definition RtypesCore.h:93
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
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()