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
43QT_BEGIN_NAMESPACE
44
45QHttpNetworkRequestPrivate::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), http2Allowed(true),
49 http2Direct(false), withCredentials(true), preConnect(false), redirectCount(0),
50 redirectPolicy(QNetworkRequest::ManualRedirectPolicy)
51{
52}
53
54QHttpNetworkRequestPrivate::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 http2Allowed(other.http2Allowed),
63 http2Direct(other.http2Direct),
64 withCredentials(other.withCredentials),
65 ssl(other.ssl),
66 preConnect(other.preConnect),
67 ignoreDecompressionRatio(other.ignoreDecompressionRatio),
68 redirectCount(other.redirectCount),
69 redirectPolicy(other.redirectPolicy),
70 peerVerifyName(other.peerVerifyName)
71{
72}
73
74QHttpNetworkRequestPrivate::~QHttpNetworkRequestPrivate()
75{
76}
77
78bool 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 && (http2Allowed == other.http2Allowed)
87 && (http2Direct == other.http2Direct)
88 // we do not clear the customVerb in setOperation
89 && (operation != QHttpNetworkRequest::Custom || (customVerb == other.customVerb))
90 && (withCredentials == other.withCredentials)
91 && (ssl == other.ssl)
92 && (preConnect == other.preConnect)
93 && (redirectPolicy == other.redirectPolicy)
94 && (peerVerifyName == other.peerVerifyName);
95}
96
97QByteArray QHttpNetworkRequest::methodName() const
98{
99 switch (d->operation) {
100 case QHttpNetworkRequest::Get:
101 return "GET";
102 case QHttpNetworkRequest::Head:
103 return "HEAD";
104 case QHttpNetworkRequest::Post:
105 return "POST";
106 case QHttpNetworkRequest::Options:
107 return "OPTIONS";
108 case QHttpNetworkRequest::Put:
109 return "PUT";
110 case QHttpNetworkRequest::Delete:
111 return "DELETE";
112 case QHttpNetworkRequest::Trace:
113 return "TRACE";
114 case QHttpNetworkRequest::Connect:
115 return "CONNECT";
116 case QHttpNetworkRequest::Custom:
117 return d->customVerb;
118 default:
119 break;
120 }
121 return QByteArray();
122}
123
124QByteArray QHttpNetworkRequest::uri(bool throughProxy) const
125{
126 QUrl::FormattingOptions format(QUrl::RemoveFragment | QUrl::RemoveUserInfo | QUrl::FullyEncoded);
127
128 // for POST, query data is sent as content
129 if (d->operation == QHttpNetworkRequest::Post && !d->uploadByteDevice)
130 format |= QUrl::RemoveQuery;
131 // for requests through proxy, the Request-URI contains full url
132 if (!throughProxy)
133 format |= QUrl::RemoveScheme | QUrl::RemoveAuthority;
134 QUrl copy = d->url;
135 if (copy.path().isEmpty())
136 copy.setPath(QStringLiteral("/"));
137 else
138 format |= QUrl::NormalizePathSegments;
139 QByteArray uri = copy.toEncoded(format);
140 return uri;
141}
142
143QByteArray QHttpNetworkRequestPrivate::header(const QHttpNetworkRequest &request, bool throughProxy)
144{
145 QList<QPair<QByteArray, QByteArray> > fields = request.header();
146 QByteArray ba;
147 ba.reserve(40 + fields.length()*25); // very rough lower bound estimation
148
149 ba += request.methodName();
150 ba += ' ';
151 ba += request.uri(throughProxy);
152
153 ba += " HTTP/";
154 ba += QByteArray::number(request.majorVersion());
155 ba += '.';
156 ba += QByteArray::number(request.minorVersion());
157 ba += "\r\n";
158
159 QList<QPair<QByteArray, QByteArray> >::const_iterator it = fields.constBegin();
160 QList<QPair<QByteArray, QByteArray> >::const_iterator endIt = fields.constEnd();
161 for (; it != endIt; ++it) {
162 ba += it->first;
163 ba += ": ";
164 ba += it->second;
165 ba += "\r\n";
166 }
167 if (request.d->operation == QHttpNetworkRequest::Post) {
168 // add content type, if not set in the request
169 if (request.headerField("content-type").isEmpty() && ((request.d->uploadByteDevice && request.d->uploadByteDevice->size() > 0) || request.d->url.hasQuery())) {
170 //Content-Type is mandatory. We can't say anything about the encoding, but x-www-form-urlencoded is the most likely to work.
171 //This warning indicates a bug in application code not setting a required header.
172 //Note that if using QHttpMultipart, the content-type is set in QNetworkAccessManagerPrivate::prepareMultipart already
173 qWarning("content-type missing in HTTP POST, defaulting to application/x-www-form-urlencoded. Use QNetworkRequest::setHeader() to fix this problem.");
174 ba += "Content-Type: application/x-www-form-urlencoded\r\n";
175 }
176 if (!request.d->uploadByteDevice && request.d->url.hasQuery()) {
177 QByteArray query = request.d->url.query(QUrl::FullyEncoded).toLatin1();
178 ba += "Content-Length: ";
179 ba += QByteArray::number(query.size());
180 ba += "\r\n\r\n";
181 ba += query;
182 } else {
183 ba += "\r\n";
184 }
185 } else {
186 ba += "\r\n";
187 }
188 return ba;
189}
190
191
192// QHttpNetworkRequest
193
194QHttpNetworkRequest::QHttpNetworkRequest(const QUrl &url, Operation operation, Priority priority)
195 : d(new QHttpNetworkRequestPrivate(operation, priority, url))
196{
197}
198
199QHttpNetworkRequest::QHttpNetworkRequest(const QHttpNetworkRequest &other)
200 : QHttpNetworkHeader(other), d(other.d)
201{
202}
203
204QHttpNetworkRequest::~QHttpNetworkRequest()
205{
206}
207
208QUrl QHttpNetworkRequest::url() const
209{
210 return d->url;
211}
212void QHttpNetworkRequest::setUrl(const QUrl &url)
213{
214 d->url = url;
215}
216
217bool QHttpNetworkRequest::isSsl() const
218{
219 return d->ssl;
220}
221void QHttpNetworkRequest::setSsl(bool s)
222{
223 d->ssl = s;
224}
225
226bool QHttpNetworkRequest::isPreConnect() const
227{
228 return d->preConnect;
229}
230void QHttpNetworkRequest::setPreConnect(bool preConnect)
231{
232 d->preConnect = preConnect;
233}
234
235bool QHttpNetworkRequest::isFollowRedirects() const
236{
237 return d->redirectPolicy != QNetworkRequest::ManualRedirectPolicy;
238}
239
240void QHttpNetworkRequest::setRedirectPolicy(QNetworkRequest::RedirectPolicy policy)
241{
242 d->redirectPolicy = policy;
243}
244
245QNetworkRequest::RedirectPolicy QHttpNetworkRequest::redirectPolicy() const
246{
247 return d->redirectPolicy;
248}
249
250int QHttpNetworkRequest::redirectCount() const
251{
252 return d->redirectCount;
253}
254
255void QHttpNetworkRequest::setRedirectCount(int count)
256{
257 d->redirectCount = count;
258}
259
260qint64 QHttpNetworkRequest::contentLength() const
261{
262 return d->contentLength();
263}
264
265void QHttpNetworkRequest::setContentLength(qint64 length)
266{
267 d->setContentLength(length);
268}
269
270QList<QPair<QByteArray, QByteArray> > QHttpNetworkRequest::header() const
271{
272 return d->fields;
273}
274
275QByteArray QHttpNetworkRequest::headerField(const QByteArray &name, const QByteArray &defaultValue) const
276{
277 return d->headerField(name, defaultValue);
278}
279
280void QHttpNetworkRequest::setHeaderField(const QByteArray &name, const QByteArray &data)
281{
282 d->setHeaderField(name, data);
283}
284
285void QHttpNetworkRequest::prependHeaderField(const QByteArray &name, const QByteArray &data)
286{
287 d->prependHeaderField(name, data);
288}
289
290void QHttpNetworkRequest::clearHeaders()
291{
292 d->clearHeaders();
293}
294
295QHttpNetworkRequest &QHttpNetworkRequest::operator=(const QHttpNetworkRequest &other)
296{
297 d = other.d;
298 return *this;
299}
300
301bool QHttpNetworkRequest::operator==(const QHttpNetworkRequest &other) const
302{
303 return d->operator==(*other.d);
304}
305
306QHttpNetworkRequest::Operation QHttpNetworkRequest::operation() const
307{
308 return d->operation;
309}
310
311void QHttpNetworkRequest::setOperation(Operation operation)
312{
313 d->operation = operation;
314}
315
316QByteArray QHttpNetworkRequest::customVerb() const
317{
318 return d->customVerb;
319}
320
321void QHttpNetworkRequest::setCustomVerb(const QByteArray &customVerb)
322{
323 d->customVerb = customVerb;
324}
325
326QHttpNetworkRequest::Priority QHttpNetworkRequest::priority() const
327{
328 return d->priority;
329}
330
331void QHttpNetworkRequest::setPriority(Priority priority)
332{
333 d->priority = priority;
334}
335
336bool QHttpNetworkRequest::isPipeliningAllowed() const
337{
338 return d->pipeliningAllowed;
339}
340
341void QHttpNetworkRequest::setPipeliningAllowed(bool b)
342{
343 d->pipeliningAllowed = b;
344}
345
346bool QHttpNetworkRequest::isHTTP2Allowed() const
347{
348 return d->http2Allowed;
349}
350
351void QHttpNetworkRequest::setHTTP2Allowed(bool b)
352{
353 d->http2Allowed = b;
354}
355
356bool QHttpNetworkRequest::isHTTP2Direct() const
357{
358 return d->http2Direct;
359}
360
361void QHttpNetworkRequest::setHTTP2Direct(bool b)
362{
363 d->http2Direct = b;
364}
365
366bool QHttpNetworkRequest::withCredentials() const
367{
368 return d->withCredentials;
369}
370
371void QHttpNetworkRequest::setWithCredentials(bool b)
372{
373 d->withCredentials = b;
374}
375
376void QHttpNetworkRequest::setUploadByteDevice(QNonContiguousByteDevice *bd)
377{
378 d->uploadByteDevice = bd;
379}
380
381QNonContiguousByteDevice* QHttpNetworkRequest::uploadByteDevice() const
382{
383 return d->uploadByteDevice;
384}
385
386int QHttpNetworkRequest::majorVersion() const
387{
388 return 1;
389}
390
391int QHttpNetworkRequest::minorVersion() const
392{
393 return 1;
394}
395
396QString QHttpNetworkRequest::peerVerifyName() const
397{
398 return d->peerVerifyName;
399}
400
401void QHttpNetworkRequest::setPeerVerifyName(const QString &peerName)
402{
403 d->peerVerifyName = peerName;
404}
405
406bool QHttpNetworkRequest::ignoreDecompressionRatio()
407{
408 return d->ignoreDecompressionRatio;
409}
410
411void QHttpNetworkRequest::setIgnoreDecompressionRatio(bool enabled)
412{
413 d->ignoreDecompressionRatio = enabled;
414}
415
416QT_END_NAMESPACE
417
418