1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qhttpnetworkrequest_p.h"
41 #include "private/qnoncontiguousbytedevice_p.h"
42
43 QT_BEGIN_NAMESPACE
44
QHttpNetworkRequestPrivate(QHttpNetworkRequest::Operation op,QHttpNetworkRequest::Priority pri,const QUrl & newUrl)45 QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(QHttpNetworkRequest::Operation op,
46 QHttpNetworkRequest::Priority pri, const QUrl &newUrl)
47 : QHttpNetworkHeaderPrivate(newUrl), operation(op), priority(pri), uploadByteDevice(nullptr),
48 autoDecompress(false), pipeliningAllowed(false), spdyAllowed(false), http2Allowed(false),
49 http2Direct(false), withCredentials(true), preConnect(false), redirectCount(0),
50 redirectPolicy(QNetworkRequest::ManualRedirectPolicy)
51 {
52 }
53
QHttpNetworkRequestPrivate(const QHttpNetworkRequestPrivate & other)54 QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(const QHttpNetworkRequestPrivate &other) // = default
55 : QHttpNetworkHeaderPrivate(other),
56 operation(other.operation),
57 customVerb(other.customVerb),
58 priority(other.priority),
59 uploadByteDevice(other.uploadByteDevice),
60 autoDecompress(other.autoDecompress),
61 pipeliningAllowed(other.pipeliningAllowed),
62 spdyAllowed(other.spdyAllowed),
63 http2Allowed(other.http2Allowed),
64 http2Direct(other.http2Direct),
65 withCredentials(other.withCredentials),
66 ssl(other.ssl),
67 preConnect(other.preConnect),
68 redirectCount(other.redirectCount),
69 redirectPolicy(other.redirectPolicy),
70 peerVerifyName(other.peerVerifyName)
71 {
72 }
73
~QHttpNetworkRequestPrivate()74 QHttpNetworkRequestPrivate::~QHttpNetworkRequestPrivate()
75 {
76 }
77
operator ==(const QHttpNetworkRequestPrivate & other) const78 bool QHttpNetworkRequestPrivate::operator==(const QHttpNetworkRequestPrivate &other) const
79 {
80 return QHttpNetworkHeaderPrivate::operator==(other)
81 && (operation == other.operation)
82 && (priority == other.priority)
83 && (uploadByteDevice == other.uploadByteDevice)
84 && (autoDecompress == other.autoDecompress)
85 && (pipeliningAllowed == other.pipeliningAllowed)
86 && (spdyAllowed == other.spdyAllowed)
87 && (http2Allowed == other.http2Allowed)
88 && (http2Direct == other.http2Direct)
89 // we do not clear the customVerb in setOperation
90 && (operation != QHttpNetworkRequest::Custom || (customVerb == other.customVerb))
91 && (withCredentials == other.withCredentials)
92 && (ssl == other.ssl)
93 && (preConnect == other.preConnect)
94 && (redirectPolicy == other.redirectPolicy)
95 && (peerVerifyName == other.peerVerifyName);
96 }
97
methodName() const98 QByteArray QHttpNetworkRequest::methodName() const
99 {
100 switch (d->operation) {
101 case QHttpNetworkRequest::Get:
102 return "GET";
103 case QHttpNetworkRequest::Head:
104 return "HEAD";
105 case QHttpNetworkRequest::Post:
106 return "POST";
107 case QHttpNetworkRequest::Options:
108 return "OPTIONS";
109 case QHttpNetworkRequest::Put:
110 return "PUT";
111 case QHttpNetworkRequest::Delete:
112 return "DELETE";
113 case QHttpNetworkRequest::Trace:
114 return "TRACE";
115 case QHttpNetworkRequest::Connect:
116 return "CONNECT";
117 case QHttpNetworkRequest::Custom:
118 return d->customVerb;
119 default:
120 break;
121 }
122 return QByteArray();
123 }
124
uri(bool throughProxy) const125 QByteArray QHttpNetworkRequest::uri(bool throughProxy) const
126 {
127 QUrl::FormattingOptions format(QUrl::RemoveFragment | QUrl::RemoveUserInfo | QUrl::FullyEncoded);
128
129 // for POST, query data is sent as content
130 if (d->operation == QHttpNetworkRequest::Post && !d->uploadByteDevice)
131 format |= QUrl::RemoveQuery;
132 // for requests through proxy, the Request-URI contains full url
133 if (!throughProxy)
134 format |= QUrl::RemoveScheme | QUrl::RemoveAuthority;
135 QUrl copy = d->url;
136 if (copy.path().isEmpty())
137 copy.setPath(QStringLiteral("/"));
138 else
139 format |= QUrl::NormalizePathSegments;
140 QByteArray uri = copy.toEncoded(format);
141 return uri;
142 }
143
header(const QHttpNetworkRequest & request,bool throughProxy)144 QByteArray QHttpNetworkRequestPrivate::header(const QHttpNetworkRequest &request, bool throughProxy)
145 {
146 QList<QPair<QByteArray, QByteArray> > fields = request.header();
147 QByteArray ba;
148 ba.reserve(40 + fields.length()*25); // very rough lower bound estimation
149
150 ba += request.methodName();
151 ba += ' ';
152 ba += request.uri(throughProxy);
153
154 ba += " HTTP/";
155 ba += QByteArray::number(request.majorVersion());
156 ba += '.';
157 ba += QByteArray::number(request.minorVersion());
158 ba += "\r\n";
159
160 QList<QPair<QByteArray, QByteArray> >::const_iterator it = fields.constBegin();
161 QList<QPair<QByteArray, QByteArray> >::const_iterator endIt = fields.constEnd();
162 for (; it != endIt; ++it) {
163 ba += it->first;
164 ba += ": ";
165 ba += it->second;
166 ba += "\r\n";
167 }
168 if (request.d->operation == QHttpNetworkRequest::Post) {
169 // add content type, if not set in the request
170 if (request.headerField("content-type").isEmpty() && ((request.d->uploadByteDevice && request.d->uploadByteDevice->size() > 0) || request.d->url.hasQuery())) {
171 //Content-Type is mandatory. We can't say anything about the encoding, but x-www-form-urlencoded is the most likely to work.
172 //This warning indicates a bug in application code not setting a required header.
173 //Note that if using QHttpMultipart, the content-type is set in QNetworkAccessManagerPrivate::prepareMultipart already
174 qWarning("content-type missing in HTTP POST, defaulting to application/x-www-form-urlencoded. Use QNetworkRequest::setHeader() to fix this problem.");
175 ba += "Content-Type: application/x-www-form-urlencoded\r\n";
176 }
177 if (!request.d->uploadByteDevice && request.d->url.hasQuery()) {
178 QByteArray query = request.d->url.query(QUrl::FullyEncoded).toLatin1();
179 ba += "Content-Length: ";
180 ba += QByteArray::number(query.size());
181 ba += "\r\n\r\n";
182 ba += query;
183 } else {
184 ba += "\r\n";
185 }
186 } else {
187 ba += "\r\n";
188 }
189 return ba;
190 }
191
192
193 // QHttpNetworkRequest
194
QHttpNetworkRequest(const QUrl & url,Operation operation,Priority priority)195 QHttpNetworkRequest::QHttpNetworkRequest(const QUrl &url, Operation operation, Priority priority)
196 : d(new QHttpNetworkRequestPrivate(operation, priority, url))
197 {
198 }
199
QHttpNetworkRequest(const QHttpNetworkRequest & other)200 QHttpNetworkRequest::QHttpNetworkRequest(const QHttpNetworkRequest &other)
201 : QHttpNetworkHeader(other), d(other.d)
202 {
203 }
204
~QHttpNetworkRequest()205 QHttpNetworkRequest::~QHttpNetworkRequest()
206 {
207 }
208
url() const209 QUrl QHttpNetworkRequest::url() const
210 {
211 return d->url;
212 }
setUrl(const QUrl & url)213 void QHttpNetworkRequest::setUrl(const QUrl &url)
214 {
215 d->url = url;
216 }
217
isSsl() const218 bool QHttpNetworkRequest::isSsl() const
219 {
220 return d->ssl;
221 }
setSsl(bool s)222 void QHttpNetworkRequest::setSsl(bool s)
223 {
224 d->ssl = s;
225 }
226
isPreConnect() const227 bool QHttpNetworkRequest::isPreConnect() const
228 {
229 return d->preConnect;
230 }
setPreConnect(bool preConnect)231 void QHttpNetworkRequest::setPreConnect(bool preConnect)
232 {
233 d->preConnect = preConnect;
234 }
235
isFollowRedirects() const236 bool QHttpNetworkRequest::isFollowRedirects() const
237 {
238 return d->redirectPolicy != QNetworkRequest::ManualRedirectPolicy;
239 }
240
setRedirectPolicy(QNetworkRequest::RedirectPolicy policy)241 void QHttpNetworkRequest::setRedirectPolicy(QNetworkRequest::RedirectPolicy policy)
242 {
243 d->redirectPolicy = policy;
244 }
245
redirectPolicy() const246 QNetworkRequest::RedirectPolicy QHttpNetworkRequest::redirectPolicy() const
247 {
248 return d->redirectPolicy;
249 }
250
redirectCount() const251 int QHttpNetworkRequest::redirectCount() const
252 {
253 return d->redirectCount;
254 }
255
setRedirectCount(int count)256 void QHttpNetworkRequest::setRedirectCount(int count)
257 {
258 d->redirectCount = count;
259 }
260
contentLength() const261 qint64 QHttpNetworkRequest::contentLength() const
262 {
263 return d->contentLength();
264 }
265
setContentLength(qint64 length)266 void QHttpNetworkRequest::setContentLength(qint64 length)
267 {
268 d->setContentLength(length);
269 }
270
header() const271 QList<QPair<QByteArray, QByteArray> > QHttpNetworkRequest::header() const
272 {
273 return d->fields;
274 }
275
headerField(const QByteArray & name,const QByteArray & defaultValue) const276 QByteArray QHttpNetworkRequest::headerField(const QByteArray &name, const QByteArray &defaultValue) const
277 {
278 return d->headerField(name, defaultValue);
279 }
280
setHeaderField(const QByteArray & name,const QByteArray & data)281 void QHttpNetworkRequest::setHeaderField(const QByteArray &name, const QByteArray &data)
282 {
283 d->setHeaderField(name, data);
284 }
285
prependHeaderField(const QByteArray & name,const QByteArray & data)286 void QHttpNetworkRequest::prependHeaderField(const QByteArray &name, const QByteArray &data)
287 {
288 d->prependHeaderField(name, data);
289 }
290
clearHeaders()291 void QHttpNetworkRequest::clearHeaders()
292 {
293 d->clearHeaders();
294 }
295
operator =(const QHttpNetworkRequest & other)296 QHttpNetworkRequest &QHttpNetworkRequest::operator=(const QHttpNetworkRequest &other)
297 {
298 d = other.d;
299 return *this;
300 }
301
operator ==(const QHttpNetworkRequest & other) const302 bool QHttpNetworkRequest::operator==(const QHttpNetworkRequest &other) const
303 {
304 return d->operator==(*other.d);
305 }
306
operation() const307 QHttpNetworkRequest::Operation QHttpNetworkRequest::operation() const
308 {
309 return d->operation;
310 }
311
setOperation(Operation operation)312 void QHttpNetworkRequest::setOperation(Operation operation)
313 {
314 d->operation = operation;
315 }
316
customVerb() const317 QByteArray QHttpNetworkRequest::customVerb() const
318 {
319 return d->customVerb;
320 }
321
setCustomVerb(const QByteArray & customVerb)322 void QHttpNetworkRequest::setCustomVerb(const QByteArray &customVerb)
323 {
324 d->customVerb = customVerb;
325 }
326
priority() const327 QHttpNetworkRequest::Priority QHttpNetworkRequest::priority() const
328 {
329 return d->priority;
330 }
331
setPriority(Priority priority)332 void QHttpNetworkRequest::setPriority(Priority priority)
333 {
334 d->priority = priority;
335 }
336
isPipeliningAllowed() const337 bool QHttpNetworkRequest::isPipeliningAllowed() const
338 {
339 return d->pipeliningAllowed;
340 }
341
setPipeliningAllowed(bool b)342 void QHttpNetworkRequest::setPipeliningAllowed(bool b)
343 {
344 d->pipeliningAllowed = b;
345 }
346
isSPDYAllowed() const347 bool QHttpNetworkRequest::isSPDYAllowed() const
348 {
349 return d->spdyAllowed;
350 }
351
setSPDYAllowed(bool b)352 void QHttpNetworkRequest::setSPDYAllowed(bool b)
353 {
354 d->spdyAllowed = b;
355 }
356
isHTTP2Allowed() const357 bool QHttpNetworkRequest::isHTTP2Allowed() const
358 {
359 return d->http2Allowed;
360 }
361
setHTTP2Allowed(bool b)362 void QHttpNetworkRequest::setHTTP2Allowed(bool b)
363 {
364 d->http2Allowed = b;
365 }
366
isHTTP2Direct() const367 bool QHttpNetworkRequest::isHTTP2Direct() const
368 {
369 return d->http2Direct;
370 }
371
setHTTP2Direct(bool b)372 void QHttpNetworkRequest::setHTTP2Direct(bool b)
373 {
374 d->http2Direct = b;
375 }
376
withCredentials() const377 bool QHttpNetworkRequest::withCredentials() const
378 {
379 return d->withCredentials;
380 }
381
setWithCredentials(bool b)382 void QHttpNetworkRequest::setWithCredentials(bool b)
383 {
384 d->withCredentials = b;
385 }
386
setUploadByteDevice(QNonContiguousByteDevice * bd)387 void QHttpNetworkRequest::setUploadByteDevice(QNonContiguousByteDevice *bd)
388 {
389 d->uploadByteDevice = bd;
390 }
391
uploadByteDevice() const392 QNonContiguousByteDevice* QHttpNetworkRequest::uploadByteDevice() const
393 {
394 return d->uploadByteDevice;
395 }
396
majorVersion() const397 int QHttpNetworkRequest::majorVersion() const
398 {
399 return 1;
400 }
401
minorVersion() const402 int QHttpNetworkRequest::minorVersion() const
403 {
404 return 1;
405 }
406
peerVerifyName() const407 QString QHttpNetworkRequest::peerVerifyName() const
408 {
409 return d->peerVerifyName;
410 }
411
setPeerVerifyName(const QString & peerName)412 void QHttpNetworkRequest::setPeerVerifyName(const QString &peerName)
413 {
414 d->peerVerifyName = peerName;
415 }
416
417 QT_END_NAMESPACE
418
419