cutelyst  3.9.1
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", QtInfoMsg)
22 
23 static thread_local QNetworkAccessManager m_instance;
24 
25 QNetworkAccessManager *Cutelyst::UA::networkAccessManager()
26 {
27  return &m_instance;
28 }
29 
30 QNetworkReply *UA::head(const QNetworkRequest &request)
31 {
32  return m_instance.head(request);
33 }
34 
35 QNetworkReply *UA::get(const QNetworkRequest &request)
36 {
37  return m_instance.get(request);
38 }
39 
40 QNetworkReply *UA::post(const QNetworkRequest &request, QIODevice *data)
41 {
42  return m_instance.post(request, data);
43 }
44 
45 QNetworkReply *UA::post(const QNetworkRequest &request, const QByteArray &data)
46 {
47  return m_instance.post(request, data);
48 }
49 
50 QNetworkReply *UA::put(const QNetworkRequest &request, QIODevice *data)
51 {
52  return m_instance.put(request, data);
53 }
54 
55 QNetworkReply *UA::put(const QNetworkRequest &request, const QByteArray &data)
56 {
57  return m_instance.put(request, data);
58 }
59 
60 QNetworkReply *UA::deleteResource(const QNetworkRequest &request)
61 {
62  return m_instance.deleteResource(request);
63 }
64 
66  UA::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QIODevice *data)
67 {
68  return m_instance.sendCustomRequest(request, verb, data);
69 }
70 
71 QNetworkReply *UA::sendCustomRequest(const QNetworkRequest &request,
72  const QByteArray &verb,
73  const QByteArray &data)
74 {
75  return m_instance.sendCustomRequest(request, verb, data);
76 }
77 
78 QNetworkReply *UA::post(const QNetworkRequest &request, QHttpMultiPart *multiPart)
79 {
80  return m_instance.post(request, multiPart);
81 }
82 
83 QNetworkReply *UA::put(const QNetworkRequest &request, QHttpMultiPart *multiPart)
84 {
85  return m_instance.post(request, multiPart);
86 }
87 
88 QNetworkReply *UA::sendCustomRequest(const QNetworkRequest &request,
89  const QByteArray &verb,
90  QHttpMultiPart *multiPart)
91 {
92  return m_instance.sendCustomRequest(request, verb, multiPart);
93 }
94 
95 QNetworkReply *UA::postJson(const QNetworkRequest &request, const QJsonDocument &doc)
96 {
97  QNetworkRequest jsonRequest(request);
98  jsonRequest.setHeader(QNetworkRequest::ContentTypeHeader,
99  QByteArrayLiteral("application/json"));
100  return m_instance.post(jsonRequest, doc.toJson(QJsonDocument::Compact));
101 }
102 
103 QNetworkReply *UA::putJson(const QNetworkRequest &request, const QJsonDocument &doc)
104 {
105  QNetworkRequest jsonRequest(request);
106  jsonRequest.setHeader(QNetworkRequest::ContentTypeHeader,
107  QByteArrayLiteral("application/json"));
108  return m_instance.put(jsonRequest, doc.toJson(QJsonDocument::Compact));
109 }
110 
111 QNetworkReply *UA::sendCustomRequestJson(const QNetworkRequest &request,
112  const QByteArray &verb,
113  const QJsonDocument &doc)
114 {
115  QNetworkRequest jsonRequest(request);
116  jsonRequest.setHeader(QNetworkRequest::ContentTypeHeader,
117  QByteArrayLiteral("application/json"));
118  return UA::sendCustomRequest(jsonRequest, verb, doc.toJson(QJsonDocument::Compact));
119 }
120 
121 QNetworkReply *UA::postJsonObject(const QNetworkRequest &request, const QJsonObject &obj)
122 {
123  QNetworkRequest jsonRequest(request);
124  jsonRequest.setHeader(QNetworkRequest::ContentTypeHeader,
125  QByteArrayLiteral("application/json"));
126  return m_instance.post(jsonRequest, QJsonDocument(obj).toJson(QJsonDocument::Compact));
127 }
128 
129 QNetworkReply *UA::putJsonObject(const QNetworkRequest &request, const QJsonObject &obj)
130 {
131  QNetworkRequest jsonRequest(request);
132  jsonRequest.setHeader(QNetworkRequest::ContentTypeHeader,
133  QByteArrayLiteral("application/json"));
134  return m_instance.put(jsonRequest, QJsonDocument(obj).toJson(QJsonDocument::Compact));
135 }
136 
137 QNetworkReply *UA::sendCustomRequestJsonObject(const QNetworkRequest &request,
138  const QByteArray &verb,
139  const QJsonObject &obj)
140 {
141  QNetworkRequest jsonRequest(request);
142  jsonRequest.setHeader(QNetworkRequest::ContentTypeHeader,
143  QByteArrayLiteral("application/json"));
144  return UA::sendCustomRequest(
145  jsonRequest, verb, QJsonDocument(obj).toJson(QJsonDocument::Compact));
146 }
147 
148 QNetworkReply *UA::postJsonArray(const QNetworkRequest &request, const QJsonArray &array)
149 {
150  QNetworkRequest jsonRequest(request);
151  jsonRequest.setHeader(QNetworkRequest::ContentTypeHeader,
152  QByteArrayLiteral("application/json"));
153  return m_instance.post(jsonRequest, QJsonDocument(array).toJson(QJsonDocument::Compact));
154 }
155 
156 QNetworkReply *UA::putJsonArray(const QNetworkRequest &request, const QJsonArray &array)
157 {
158  QNetworkRequest jsonRequest(request);
159  jsonRequest.setHeader(QNetworkRequest::ContentTypeHeader,
160  QByteArrayLiteral("application/json"));
161  return m_instance.put(jsonRequest, QJsonDocument(array).toJson(QJsonDocument::Compact));
162 }
163 
164 QNetworkReply *UA::sendCustomRequestJsonArray(const QNetworkRequest &request,
165  const QByteArray &verb,
166  const QJsonArray &array)
167 {
168  QNetworkRequest jsonRequest(request);
169  jsonRequest.setHeader(QNetworkRequest::ContentTypeHeader,
170  QByteArrayLiteral("application/json"));
171  return UA::sendCustomRequest(
172  jsonRequest, verb, QJsonDocument(array).toJson(QJsonDocument::Compact));
173 }
174 
175 QNetworkReply *UA::forwardRequest(Request *request, const QUrl &destination)
176 {
177  QUrl dest(request->uri());
178  dest.setHost(destination.host());
179  dest.setPort(destination.port());
180  dest.setScheme(destination.scheme());
181 
182  QNetworkRequest proxyReq(dest);
183 
184  const Headers reqHeaders = request->headers();
185  const auto headersData = reqHeaders.data();
186  auto it = headersData.constBegin();
187  while (it != headersData.constEnd()) {
188  proxyReq.setRawHeader(Cutelyst::Engine::camelCaseHeader(it.key()).toLatin1(),
189  it.value().toLatin1());
190  ++it;
191  }
192 
193  return m_instance.sendCustomRequest(proxyReq, request->method().toLatin1(), request->body());
194 }
195 
196 QNetworkReply *UA::forwardRequestResponse(Context *c, const QUrl &destination)
197 {
198  QNetworkReply *reply = forwardRequest(c->request(), destination);
199  QObject::connect(reply, &QNetworkReply::finished, c, [=] {
200  Headers &responseHeaders = c->response()->headers();
201  const QList<QNetworkReply::RawHeaderPair> &headers = reply->rawHeaderPairs();
202  for (const QNetworkReply::RawHeaderPair &pair : headers) {
203  responseHeaders.setHeader(QString::fromLatin1(pair.first),
204  QString::fromLatin1(pair.second));
205  }
206  c->response()->setStatus(
208  c->response()->setBody(reply);
209  });
210  return reply;
211 }
212 
213 void UA::forwardAsync(Context *c, const QUrl &destination)
214 {
215  QNetworkReply *reply = forwardRequest(c->request(), destination);
216  QObject::connect(reply, &QNetworkReply::finished, c, [=] {
217  Headers &responseHeaders = c->response()->headers();
218  const QList<QNetworkReply::RawHeaderPair> &headers = reply->rawHeaderPairs();
219  for (const QNetworkReply::RawHeaderPair &pair : headers) {
220  responseHeaders.setHeader(QString::fromLatin1(pair.first),
221  QString::fromLatin1(pair.second));
222  }
223  c->response()->setStatus(
225  c->response()->setBody(reply);
226  c->attachAsync();
227  });
228  c->detachAsync();
229 }
QNetworkReply * post(const QNetworkRequest &request, QHttpMultiPart *multiPart)
const QList< RawHeaderPair > & rawHeaderPairs() const const
const_iterator constBegin() const const
QIODevice * body() const
Definition: request.cpp:181
QByteArray toJson(JsonFormat format) const const
Headers & headers() noexcept
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
static QString camelCaseHeader(const QString &headerKey)
Definition: engine.h:103
QString host(ComponentFormattingOptions options) const const
int port(int defaultPort) const const
QNetworkReply * sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QHttpMultiPart *multiPart)
QNetworkReply * put(const QNetworkRequest &request, QHttpMultiPart *multiPart)
The Cutelyst Context.
Definition: context.h:38
uint toUInt(bool *ok) const const
QNetworkReply * deleteResource(const QNetworkRequest &request)
Headers headers() const noexcept
Definition: request.cpp:310
typedef RawHeaderPair
void setHeader(const QString &field, const QString &value)
Definition: headers.cpp:396
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:7
void detachAsync() noexcept
Definition: context.cpp:355
QString scheme() const const
QMultiHash< QString, QString > data() const
Definition: headers.h:382
QNetworkReply * head(const QNetworkRequest &request)
QString fromLatin1(QByteArrayView str)
QByteArray toLatin1() const const
QVariant attribute(QNetworkRequest::Attribute code) const const
void setHost(const QString &host, ParsingMode mode)
QNetworkReply * get(const QNetworkRequest &request)
void setBody(QIODevice *body)
Definition: response.cpp:100
Response * response() const noexcept
Definition: context.cpp:96
void setStatus(quint16 status) noexcept
Definition: response.cpp:70
void attachAsync()
attachAsync
Definition: context.cpp:361