cutelyst  4.9.0
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
useragent.cpp
1 /*
2  * SPDX-FileCopyrightText: (C) 2019-2022 Daniel Nicoletti <dantti12@gmail.com>
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 #include "useragent.h"
6 
7 #include <Cutelyst/Context>
8 #include <Cutelyst/Engine>
9 #include <Cutelyst/Request>
10 #include <Cutelyst/Response>
11 
12 #include <QBuffer>
13 #include <QHostAddress>
14 #include <QHttpMultiPart>
15 #include <QJsonDocument>
16 #include <QLoggingCategory>
17 #include <QNetworkAccessManager>
18 
19 using namespace Cutelyst;
20 
21 Q_LOGGING_CATEGORY(C_USERAGENT, "cutelyst.useragent", QtWarningMsg)
22 
23 QNetworkAccessManager *Cutelyst::UA::networkAccessManager()
24 {
25  static thread_local QNetworkAccessManager m_instance;
26  m_instance.setAutoDeleteReplies(true);
27  return &m_instance;
28 }
29 
31 {
32  return networkAccessManager()->head(request);
33 }
34 
36 {
37  return networkAccessManager()->get(request);
38 }
39 
41 {
42  return networkAccessManager()->post(request, data);
43 }
44 
45 QNetworkReply *UA::post(const QNetworkRequest &request, const QByteArray &data)
46 {
47  return networkAccessManager()->post(request, data);
48 }
49 
51 {
52  return networkAccessManager()->put(request, data);
53 }
54 
55 QNetworkReply *UA::put(const QNetworkRequest &request, const QByteArray &data)
56 {
57  return networkAccessManager()->put(request, data);
58 }
59 
61 {
62  return networkAccessManager()->deleteResource(request);
63 }
64 
66  UA::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QIODevice *data)
67 {
68  return networkAccessManager()->sendCustomRequest(request, verb, data);
69 }
70 
72  const QByteArray &verb,
73  const QByteArray &data)
74 {
75  return networkAccessManager()->sendCustomRequest(request, verb, data);
76 }
77 
79 {
80  return networkAccessManager()->post(request, multiPart);
81 }
82 
84 {
85  return networkAccessManager()->post(request, multiPart);
86 }
87 
89  const QByteArray &verb,
90  QHttpMultiPart *multiPart)
91 {
92  return networkAccessManager()->sendCustomRequest(request, verb, multiPart);
93 }
94 
96 {
97  QNetworkRequest jsonRequest(request);
99  QByteArrayLiteral("application/json"));
100  return networkAccessManager()->post(jsonRequest, doc.toJson(QJsonDocument::Compact));
101 }
102 
104 {
105  QNetworkRequest jsonRequest(request);
107  QByteArrayLiteral("application/json"));
108  return networkAccessManager()->put(jsonRequest, doc.toJson(QJsonDocument::Compact));
109 }
110 
112  const QByteArray &verb,
113  const QJsonDocument &doc)
114 {
115  QNetworkRequest jsonRequest(request);
117  QByteArrayLiteral("application/json"));
118  return UA::sendCustomRequest(jsonRequest, verb, doc.toJson(QJsonDocument::Compact));
119 }
120 
122 {
123  QNetworkRequest jsonRequest(request);
125  QByteArrayLiteral("application/json"));
126  return networkAccessManager()->post(jsonRequest,
127  QJsonDocument(object).toJson(QJsonDocument::Compact));
128 }
129 
131 {
132  QNetworkRequest jsonRequest(request);
134  QByteArrayLiteral("application/json"));
135  return networkAccessManager()->put(jsonRequest,
136  QJsonDocument(object).toJson(QJsonDocument::Compact));
137 }
138 
140  const QByteArray &verb,
141  const QJsonObject &object)
142 {
143  QNetworkRequest jsonRequest(request);
145  QByteArrayLiteral("application/json"));
146  return UA::sendCustomRequest(
147  jsonRequest, verb, QJsonDocument(object).toJson(QJsonDocument::Compact));
148 }
149 
151 {
152  QNetworkRequest jsonRequest(request);
154  QByteArrayLiteral("application/json"));
155  return networkAccessManager()->post(jsonRequest,
156  QJsonDocument(array).toJson(QJsonDocument::Compact));
157 }
158 
160 {
161  QNetworkRequest jsonRequest(request);
163  QByteArrayLiteral("application/json"));
164  return networkAccessManager()->put(jsonRequest,
165  QJsonDocument(array).toJson(QJsonDocument::Compact));
166 }
167 
169  const QByteArray &verb,
170  const QJsonArray &array)
171 {
172  QNetworkRequest jsonRequest(request);
174  QByteArrayLiteral("application/json"));
175  return UA::sendCustomRequest(
176  jsonRequest, verb, QJsonDocument(array).toJson(QJsonDocument::Compact));
177 }
178 
179 QNetworkReply *UA::forwardRequest(Request *request, const QUrl &destination)
180 {
181  QUrl dest(request->uri());
182  dest.setHost(destination.host());
183  dest.setPort(destination.port());
184  dest.setScheme(destination.scheme());
185 
186  QNetworkRequest proxyReq(dest);
187 
188  const Headers reqHeaders = request->headers();
189  const auto headersData = reqHeaders.data();
190  auto it = headersData.begin();
191  while (it != headersData.end()) {
192  proxyReq.setRawHeader(it->key, it->value);
193  ++it;
194  }
195 
196  return networkAccessManager()->sendCustomRequest(proxyReq, request->method(), request->body());
197 }
198 
200 {
201  QNetworkReply *reply = forwardRequest(c->request(), destination);
202  QObject::connect(reply, &QNetworkReply::finished, c, [=] {
203  Headers &responseHeaders = c->response()->headers();
204  const QList<QNetworkReply::RawHeaderPair> &headers = reply->rawHeaderPairs();
205  for (const QNetworkReply::RawHeaderPair &pair : headers) {
206  responseHeaders.pushHeader(pair.first, pair.second);
207  }
208  c->response()->setStatus(
210  c->response()->setBody(reply->readAll());
211  });
212  return reply;
213 }
214 
215 void UA::forwardAsync(Context *c, const QUrl &destination)
216 {
217  ASync a;
218  QNetworkReply *reply = forwardRequest(c->request(), destination);
219  QObject::connect(reply, &QNetworkReply::finished, c, [reply, a, c] {
220  Headers &responseHeaders = c->response()->headers();
221  const QList<QNetworkReply::RawHeaderPair> &headers = reply->rawHeaderPairs();
222  for (const QNetworkReply::RawHeaderPair &pair : headers) {
223  responseHeaders.pushHeader(pair.first, pair.second);
224  }
225  c->response()->setStatus(
227  c->response()->setBody(reply);
228  });
229 }
QNetworkReply * post(const QNetworkRequest &request, QHttpMultiPart *multiPart)
const QList< RawHeaderPair > & rawHeaderPairs() const const
Request request
Definition: context.h:72
QByteArray toJson(JsonFormat format) const const
Headers & headers() noexcept
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
CUTELYST_PLUGIN_USERAGENT_EXPORT QNetworkReply * putJsonObject(const QNetworkRequest &request, const QJsonObject &object)
Definition: useragent.cpp:130
CUTELYST_PLUGIN_USERAGENT_EXPORT QNetworkReply * forwardRequest(Request *request, const QUrl &destination)
Definition: useragent.cpp:179
QString host(ComponentFormattingOptions options) const const
Container for HTTP headers.
Definition: headers.h:23
Helper class for asynchronous processing.
Definition: async.h:15
int port(int defaultPort) const const
CUTELYST_PLUGIN_USERAGENT_EXPORT QNetworkReply * head(const QNetworkRequest &request)
Definition: useragent.cpp:30
QNetworkReply * sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QHttpMultiPart *multiPart)
QIODevice * body() const noexcept
Definition: request.cpp:180
QNetworkReply * put(const QNetworkRequest &request, QHttpMultiPart *multiPart)
CUTELYST_PLUGIN_USERAGENT_EXPORT QNetworkReply * post(const QNetworkRequest &request, QIODevice *data)
Definition: useragent.cpp:40
The Cutelyst Context.
Definition: context.h:42
CUTELYST_PLUGIN_USERAGENT_EXPORT QNetworkReply * deleteResource(const QNetworkRequest &request)
Definition: useragent.cpp:60
CUTELYST_PLUGIN_USERAGENT_EXPORT QNetworkReply * sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QIODevice *data=nullptr)
Definition: useragent.cpp:66
uint toUInt(bool *ok) const const
QNetworkReply * deleteResource(const QNetworkRequest &request)
Headers headers() const noexcept
Definition: request.cpp:313
CUTELYST_PLUGIN_USERAGENT_EXPORT QNetworkReply * putJsonArray(const QNetworkRequest &request, const QJsonArray &array)
Definition: useragent.cpp:159
CUTELYST_PLUGIN_USERAGENT_EXPORT QNetworkReply * sendCustomRequestJson(const QNetworkRequest &request, const QByteArray &verb, const QJsonDocument &doc)
Definition: useragent.cpp:111
CUTELYST_PLUGIN_USERAGENT_EXPORT QNetworkAccessManager * networkAccessManager()
Definition: useragent.cpp:23
QByteArray readAll()
typedef RawHeaderPair
The Cutelyst namespace holds all public Cutelyst API.
CUTELYST_PLUGIN_USERAGENT_EXPORT QNetworkReply * postJsonArray(const QNetworkRequest &request, const QJsonArray &array)
Definition: useragent.cpp:150
QVector< HeaderKeyValue > data() const
Definition: headers.h:419
QString scheme() const const
void setAutoDeleteReplies(bool shouldAutoDelete)
void setHeader(KnownHeaders header, const QVariant &value)
void pushHeader(const QByteArray &key, const QByteArray &value)
Definition: headers.cpp:461
QNetworkReply * head(const QNetworkRequest &request)
CUTELYST_PLUGIN_USERAGENT_EXPORT void forwardAsync(Context *c, const QUrl &destination)
Definition: useragent.cpp:215
CUTELYST_PLUGIN_USERAGENT_EXPORT QNetworkReply * sendCustomRequestJsonArray(const QNetworkRequest &request, const QByteArray &verb, const QJsonArray &array)
Definition: useragent.cpp:168
CUTELYST_PLUGIN_USERAGENT_EXPORT QNetworkReply * forwardRequestResponse(Context *c, const QUrl &destination)
Definition: useragent.cpp:199
CUTELYST_PLUGIN_USERAGENT_EXPORT QNetworkReply * put(const QNetworkRequest &request, QIODevice *data)
Definition: useragent.cpp:50
CUTELYST_PLUGIN_USERAGENT_EXPORT QNetworkReply * putJson(const QNetworkRequest &request, const QJsonDocument &doc)
Definition: useragent.cpp:103
void setRawHeader(const QByteArray &headerName, const QByteArray &headerValue)
QVariant attribute(QNetworkRequest::Attribute code) const const
CUTELYST_PLUGIN_USERAGENT_EXPORT QNetworkReply * get(const QNetworkRequest &request)
Definition: useragent.cpp:35
CUTELYST_PLUGIN_USERAGENT_EXPORT QNetworkReply * postJsonObject(const QNetworkRequest &request, const QJsonObject &object)
Definition: useragent.cpp:121
CUTELYST_PLUGIN_USERAGENT_EXPORT QNetworkReply * sendCustomRequestJsonObject(const QNetworkRequest &request, const QByteArray &verb, const QJsonObject &object)
Definition: useragent.cpp:139
CUTELYST_PLUGIN_USERAGENT_EXPORT QNetworkReply * postJson(const QNetworkRequest &request, const QJsonDocument &doc)
Definition: useragent.cpp:95
void setHost(const QString &host, ParsingMode mode)
QNetworkReply * get(const QNetworkRequest &request)
A request.
Definition: request.h:41
void setBody(QIODevice *body)
Definition: response.cpp:104
Response * response() const noexcept
Definition: context.cpp:98
void setStatus(quint16 status) noexcept
Definition: response.cpp:73