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 | |
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), http2Allowed(true), |
49 | http2Direct(false), withCredentials(true), preConnect(false), redirectCount(0), |
50 | redirectPolicy(QNetworkRequest::ManualRedirectPolicy) |
51 | { |
52 | } |
53 | |
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 | 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 | |
74 | QHttpNetworkRequestPrivate::~QHttpNetworkRequestPrivate() |
75 | { |
76 | } |
77 | |
78 | 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 | && (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 | |
97 | QByteArray 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 | |
124 | QByteArray 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 | |
143 | QByteArray QHttpNetworkRequestPrivate::(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 | |
194 | QHttpNetworkRequest::QHttpNetworkRequest(const QUrl &url, Operation operation, Priority priority) |
195 | : d(new QHttpNetworkRequestPrivate(operation, priority, url)) |
196 | { |
197 | } |
198 | |
199 | QHttpNetworkRequest::QHttpNetworkRequest(const QHttpNetworkRequest &other) |
200 | : QHttpNetworkHeader(other), d(other.d) |
201 | { |
202 | } |
203 | |
204 | QHttpNetworkRequest::~QHttpNetworkRequest() |
205 | { |
206 | } |
207 | |
208 | QUrl QHttpNetworkRequest::url() const |
209 | { |
210 | return d->url; |
211 | } |
212 | void QHttpNetworkRequest::setUrl(const QUrl &url) |
213 | { |
214 | d->url = url; |
215 | } |
216 | |
217 | bool QHttpNetworkRequest::isSsl() const |
218 | { |
219 | return d->ssl; |
220 | } |
221 | void QHttpNetworkRequest::setSsl(bool s) |
222 | { |
223 | d->ssl = s; |
224 | } |
225 | |
226 | bool QHttpNetworkRequest::isPreConnect() const |
227 | { |
228 | return d->preConnect; |
229 | } |
230 | void QHttpNetworkRequest::setPreConnect(bool preConnect) |
231 | { |
232 | d->preConnect = preConnect; |
233 | } |
234 | |
235 | bool QHttpNetworkRequest::isFollowRedirects() const |
236 | { |
237 | return d->redirectPolicy != QNetworkRequest::ManualRedirectPolicy; |
238 | } |
239 | |
240 | void QHttpNetworkRequest::setRedirectPolicy(QNetworkRequest::RedirectPolicy policy) |
241 | { |
242 | d->redirectPolicy = policy; |
243 | } |
244 | |
245 | QNetworkRequest::RedirectPolicy QHttpNetworkRequest::redirectPolicy() const |
246 | { |
247 | return d->redirectPolicy; |
248 | } |
249 | |
250 | int QHttpNetworkRequest::redirectCount() const |
251 | { |
252 | return d->redirectCount; |
253 | } |
254 | |
255 | void QHttpNetworkRequest::setRedirectCount(int count) |
256 | { |
257 | d->redirectCount = count; |
258 | } |
259 | |
260 | qint64 QHttpNetworkRequest::contentLength() const |
261 | { |
262 | return d->contentLength(); |
263 | } |
264 | |
265 | void QHttpNetworkRequest::setContentLength(qint64 length) |
266 | { |
267 | d->setContentLength(length); |
268 | } |
269 | |
270 | QList<QPair<QByteArray, QByteArray> > QHttpNetworkRequest::() const |
271 | { |
272 | return d->fields; |
273 | } |
274 | |
275 | QByteArray QHttpNetworkRequest::(const QByteArray &name, const QByteArray &defaultValue) const |
276 | { |
277 | return d->headerField(name, defaultValue); |
278 | } |
279 | |
280 | void QHttpNetworkRequest::(const QByteArray &name, const QByteArray &data) |
281 | { |
282 | d->setHeaderField(name, data); |
283 | } |
284 | |
285 | void QHttpNetworkRequest::(const QByteArray &name, const QByteArray &data) |
286 | { |
287 | d->prependHeaderField(name, data); |
288 | } |
289 | |
290 | void QHttpNetworkRequest::() |
291 | { |
292 | d->clearHeaders(); |
293 | } |
294 | |
295 | QHttpNetworkRequest &QHttpNetworkRequest::operator=(const QHttpNetworkRequest &other) |
296 | { |
297 | d = other.d; |
298 | return *this; |
299 | } |
300 | |
301 | bool QHttpNetworkRequest::operator==(const QHttpNetworkRequest &other) const |
302 | { |
303 | return d->operator==(*other.d); |
304 | } |
305 | |
306 | QHttpNetworkRequest::Operation QHttpNetworkRequest::operation() const |
307 | { |
308 | return d->operation; |
309 | } |
310 | |
311 | void QHttpNetworkRequest::setOperation(Operation operation) |
312 | { |
313 | d->operation = operation; |
314 | } |
315 | |
316 | QByteArray QHttpNetworkRequest::customVerb() const |
317 | { |
318 | return d->customVerb; |
319 | } |
320 | |
321 | void QHttpNetworkRequest::setCustomVerb(const QByteArray &customVerb) |
322 | { |
323 | d->customVerb = customVerb; |
324 | } |
325 | |
326 | QHttpNetworkRequest::Priority QHttpNetworkRequest::priority() const |
327 | { |
328 | return d->priority; |
329 | } |
330 | |
331 | void QHttpNetworkRequest::setPriority(Priority priority) |
332 | { |
333 | d->priority = priority; |
334 | } |
335 | |
336 | bool QHttpNetworkRequest::isPipeliningAllowed() const |
337 | { |
338 | return d->pipeliningAllowed; |
339 | } |
340 | |
341 | void QHttpNetworkRequest::setPipeliningAllowed(bool b) |
342 | { |
343 | d->pipeliningAllowed = b; |
344 | } |
345 | |
346 | bool QHttpNetworkRequest::isHTTP2Allowed() const |
347 | { |
348 | return d->http2Allowed; |
349 | } |
350 | |
351 | void QHttpNetworkRequest::setHTTP2Allowed(bool b) |
352 | { |
353 | d->http2Allowed = b; |
354 | } |
355 | |
356 | bool QHttpNetworkRequest::isHTTP2Direct() const |
357 | { |
358 | return d->http2Direct; |
359 | } |
360 | |
361 | void QHttpNetworkRequest::setHTTP2Direct(bool b) |
362 | { |
363 | d->http2Direct = b; |
364 | } |
365 | |
366 | bool QHttpNetworkRequest::withCredentials() const |
367 | { |
368 | return d->withCredentials; |
369 | } |
370 | |
371 | void QHttpNetworkRequest::setWithCredentials(bool b) |
372 | { |
373 | d->withCredentials = b; |
374 | } |
375 | |
376 | void QHttpNetworkRequest::setUploadByteDevice(QNonContiguousByteDevice *bd) |
377 | { |
378 | d->uploadByteDevice = bd; |
379 | } |
380 | |
381 | QNonContiguousByteDevice* QHttpNetworkRequest::uploadByteDevice() const |
382 | { |
383 | return d->uploadByteDevice; |
384 | } |
385 | |
386 | int QHttpNetworkRequest::majorVersion() const |
387 | { |
388 | return 1; |
389 | } |
390 | |
391 | int QHttpNetworkRequest::minorVersion() const |
392 | { |
393 | return 1; |
394 | } |
395 | |
396 | QString QHttpNetworkRequest::peerVerifyName() const |
397 | { |
398 | return d->peerVerifyName; |
399 | } |
400 | |
401 | void QHttpNetworkRequest::setPeerVerifyName(const QString &peerName) |
402 | { |
403 | d->peerVerifyName = peerName; |
404 | } |
405 | |
406 | bool QHttpNetworkRequest::ignoreDecompressionRatio() |
407 | { |
408 | return d->ignoreDecompressionRatio; |
409 | } |
410 | |
411 | void QHttpNetworkRequest::setIgnoreDecompressionRatio(bool enabled) |
412 | { |
413 | d->ignoreDecompressionRatio = enabled; |
414 | } |
415 | |
416 | QT_END_NAMESPACE |
417 | |
418 | |