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