Cutelyst  2.14.2
useragent.cpp
1 /*
2  * Copyright (C) 2019 Daniel Nicoletti <dantti12@gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 #include "useragent.h"
19 
20 #include <Cutelyst/Engine>
21 #include <Cutelyst/Context>
22 #include <Cutelyst/Request>
23 #include <Cutelyst/Response>
24 
25 #include <QHostAddress>
26 #include <QLoggingCategory>
27 #include <QNetworkAccessManager>
28 
29 #include <QBuffer>
30 #include <QHttpMultiPart>
31 
32 #include <QJsonDocument>
33 
34 using namespace Cutelyst;
35 
36 Q_LOGGING_CATEGORY(C_USERAGENT, "cutelyst.useragent", QtInfoMsg)
37 
38 static thread_local QNetworkAccessManager m_instance;
39 
40 QNetworkAccessManager *Cutelyst::UA::networkAccessManager()
41 {
42  return &m_instance;
43 }
44 
45 QNetworkReply *UA::head(const QNetworkRequest &request)
46 {
47  return m_instance.head(request);
48 }
49 
50 QNetworkReply *UA::get(const QNetworkRequest &request)
51 {
52  return m_instance.get(request);
53 }
54 
55 QNetworkReply *UA::post(const QNetworkRequest &request, QIODevice *data)
56 {
57  return m_instance.post(request, data);
58 }
59 
60 QNetworkReply *UA::post(const QNetworkRequest &request, const QByteArray &data)
61 {
62  return m_instance.post(request, data);
63 }
64 
65 QNetworkReply *UA::put(const QNetworkRequest &request, QIODevice *data)
66 {
67  return m_instance.put(request, data);
68 }
69 
70 QNetworkReply *UA::put(const QNetworkRequest &request, const QByteArray &data)
71 {
72  return m_instance.put(request, data);
73 }
74 
75 QNetworkReply *UA::deleteResource(const QNetworkRequest &request)
76 {
77  return m_instance.deleteResource(request);
78 }
79 
80 QNetworkReply *UA::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QIODevice *data)
81 {
82  return m_instance.sendCustomRequest(request, verb, data);
83 }
84 
85 QNetworkReply *UA::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, const QByteArray &data)
86 {
87 #if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0))
88  return m_instance.sendCustomRequest(request, verb, data);
89 #else
90  auto buffer = new QBuffer;
91  buffer->setData(data);
92  QNetworkReply *reply = m_instance.sendCustomRequest(request, verb, buffer);
93  buffer->setParent(reply);
94  return reply;
95 #endif
96 }
97 
98 QNetworkReply *UA::post(const QNetworkRequest &request, QHttpMultiPart *multiPart)
99 {
100  return m_instance.post(request, multiPart);
101 }
102 
103 QNetworkReply *UA::put(const QNetworkRequest &request, QHttpMultiPart *multiPart)
104 {
105  return m_instance.post(request, multiPart);
106 }
107 
108 QNetworkReply *UA::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QHttpMultiPart *multiPart)
109 {
110 #if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0))
111  return m_instance.sendCustomRequest(request, verb, multiPart);
112 #else
113  return nullptr;
114 #endif
115 }
116 
117 QNetworkReply *UA::postJson(const QNetworkRequest &request, const QJsonDocument &doc)
118 {
119  QNetworkRequest jsonRequest(request);
120  jsonRequest.setHeader(QNetworkRequest::ContentTypeHeader, QByteArrayLiteral("application/json"));
121  return m_instance.post(jsonRequest, doc.toJson(QJsonDocument::Compact));
122 }
123 
124 QNetworkReply *UA::putJson(const QNetworkRequest &request, const QJsonDocument &doc)
125 {
126  QNetworkRequest jsonRequest(request);
127  jsonRequest.setHeader(QNetworkRequest::ContentTypeHeader, QByteArrayLiteral("application/json"));
128  return m_instance.put(jsonRequest, doc.toJson(QJsonDocument::Compact));
129 }
130 
131 QNetworkReply *UA::sendCustomRequestJson(const QNetworkRequest &request, const QByteArray &verb, const QJsonDocument &doc)
132 {
133  QNetworkRequest jsonRequest(request);
134  jsonRequest.setHeader(QNetworkRequest::ContentTypeHeader, QByteArrayLiteral("application/json"));
135  return UA::sendCustomRequest(jsonRequest, verb, doc.toJson(QJsonDocument::Compact));
136 }
137 
138 QNetworkReply *UA::postJsonObject(const QNetworkRequest &request, const QJsonObject &obj)
139 {
140  QNetworkRequest jsonRequest(request);
141  jsonRequest.setHeader(QNetworkRequest::ContentTypeHeader, QByteArrayLiteral("application/json"));
142  return m_instance.post(jsonRequest, QJsonDocument(obj).toJson(QJsonDocument::Compact));
143 }
144 
145 QNetworkReply *UA::putJsonObject(const QNetworkRequest &request, const QJsonObject &obj)
146 {
147  QNetworkRequest jsonRequest(request);
148  jsonRequest.setHeader(QNetworkRequest::ContentTypeHeader, QByteArrayLiteral("application/json"));
149  return m_instance.put(jsonRequest, QJsonDocument(obj).toJson(QJsonDocument::Compact));
150 }
151 
152 QNetworkReply *UA::sendCustomRequestJsonObject(const QNetworkRequest &request, const QByteArray &verb, const QJsonObject &obj)
153 {
154  QNetworkRequest jsonRequest(request);
155  jsonRequest.setHeader(QNetworkRequest::ContentTypeHeader, QByteArrayLiteral("application/json"));
156  return UA::sendCustomRequest(jsonRequest, verb, QJsonDocument(obj).toJson(QJsonDocument::Compact));
157 }
158 
159 QNetworkReply *UA::postJsonArray(const QNetworkRequest &request, const QJsonArray &array)
160 {
161  QNetworkRequest jsonRequest(request);
162  jsonRequest.setHeader(QNetworkRequest::ContentTypeHeader, QByteArrayLiteral("application/json"));
163  return m_instance.post(jsonRequest, QJsonDocument(array).toJson(QJsonDocument::Compact));
164 }
165 
166 QNetworkReply *UA::putJsonArray(const QNetworkRequest &request, const QJsonArray &array)
167 {
168  QNetworkRequest jsonRequest(request);
169  jsonRequest.setHeader(QNetworkRequest::ContentTypeHeader, QByteArrayLiteral("application/json"));
170  return m_instance.put(jsonRequest, QJsonDocument(array).toJson(QJsonDocument::Compact));
171 }
172 
173 QNetworkReply *UA::sendCustomRequestJsonArray(const QNetworkRequest &request, const QByteArray &verb, const QJsonArray &array)
174 {
175  QNetworkRequest jsonRequest(request);
176  jsonRequest.setHeader(QNetworkRequest::ContentTypeHeader, QByteArrayLiteral("application/json"));
177  return UA::sendCustomRequest(jsonRequest, verb, QJsonDocument(array).toJson(QJsonDocument::Compact));
178 }
179 
180 QNetworkReply *UA::forwardRequest(Request *request, const QUrl &destination)
181 {
182  QUrl dest(request->uri());
183  dest.setHost(destination.host());
184  dest.setPort(destination.port());
185  dest.setScheme(destination.scheme());
186 
187  QNetworkRequest proxyReq(dest);
188 
189  const Headers reqHeaders = request->headers();
190  const auto headersData = reqHeaders.data();
191  auto it = headersData.constBegin();
192  while (it != headersData.constEnd()) {
193  proxyReq.setRawHeader(Cutelyst::Engine::camelCaseHeader(it.key()).toLatin1(), it.value().toLatin1());
194  ++it;
195  }
196 
197  return m_instance.sendCustomRequest(proxyReq, request->method().toLatin1(), request->body());
198 }
199 
200 QNetworkReply *UA::forwardRequestResponse(Context *c, const QUrl &destination)
201 {
202  QNetworkReply *reply = forwardRequest(c->request(), destination);
203  QObject::connect(reply, &QNetworkReply::finished, c, [=] {
204  Headers &responseHeaders = c->response()->headers();
205  const QList<QNetworkReply::RawHeaderPair> &headers = reply->rawHeaderPairs();
206  for (const QNetworkReply::RawHeaderPair &pair : headers) {
207  responseHeaders.setHeader(QString::fromLatin1(pair.first), QString::fromLatin1(pair.second));
208  }
209  c->response()->setStatus(quint16(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toUInt()));
210  c->response()->setBody(reply);
211  });
212  return reply;
213 }
214 
215 void UA::forwardAsync(Context *c, const QUrl &destination)
216 {
217  QNetworkReply *reply = forwardRequest(c->request(), destination);
218  QObject::connect(reply, &QNetworkReply::finished, c, [=] {
219  Headers &responseHeaders = c->response()->headers();
220  const QList<QNetworkReply::RawHeaderPair> &headers = reply->rawHeaderPairs();
221  for (const QNetworkReply::RawHeaderPair &pair : headers) {
222  responseHeaders.setHeader(QString::fromLatin1(pair.first), QString::fromLatin1(pair.second));
223  }
224  c->response()->setStatus(quint16(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toUInt()));
225  c->response()->setBody(reply);
226  c->attachAsync();
227  });
228  c->detachAsync();
229 }
QNetworkReply * sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QIODevice *data)
QNetworkReply * put(const QNetworkRequest &request, QIODevice *data)
const QList< RawHeaderPair > & rawHeaderPairs() const
QByteArray toJson(JsonFormat format) const
static QString camelCaseHeader(const QString &headerKey)
Definition: engine.h:116
void detachAsync()
Definition: context.cpp:356
QString host(ComponentFormattingOptions options) const
void setData(const QByteArray &data)
void setStatus(quint16 status)
Definition: response.cpp:85
int port(int defaultPort) const
QIODevice * body() const
Definition: request.cpp:192
The Cutelyst Context.
Definition: context.h:51
uint toUInt(bool *ok) const
QNetworkReply * deleteResource(const QNetworkRequest &request)
QNetworkReply * post(const QNetworkRequest &request, QIODevice *data)
Headers & headers()
Definition: response.cpp:316
typedef RawHeaderPair
void setHeader(const QString &field, const QString &value)
Definition: headers.cpp:403
QHash< QString, QString > data() const
Definition: headers.h:380
QString scheme() const
void setParent(QObject *parent)
Response * response() const
Definition: context.cpp:110
QNetworkReply * head(const QNetworkRequest &request)
const_iterator constBegin() const
QByteArray toLatin1() const
QVariant attribute(QNetworkRequest::Attribute code) const
QString fromLatin1(const char *str, int size)
void setHost(const QString &host, ParsingMode mode)
QNetworkReply * get(const QNetworkRequest &request)
void setBody(QIODevice *body)
Definition: response.cpp:114
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void attachAsync()
attachAsync
Definition: context.cpp:363