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