1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2022 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 "qnetworkrequest.h" |
41 | #include "qnetworkrequest_p.h" |
42 | #include "qplatformdefs.h" |
43 | #include "qnetworkcookie.h" |
44 | #include "qsslconfiguration.h" |
45 | #if QT_CONFIG(http) || defined(Q_CLANG_QDOC) |
46 | #include "qhttp2configuration.h" |
47 | #include "private/http2protocol_p.h" |
48 | #endif |
49 | #include "QtCore/qshareddata.h" |
50 | #include "QtCore/qlocale.h" |
51 | #include "QtCore/qdatetime.h" |
52 | |
53 | #include <ctype.h> |
54 | #if QT_CONFIG(datestring) |
55 | # include <stdio.h> |
56 | #endif |
57 | |
58 | #include <algorithm> |
59 | |
60 | QT_BEGIN_NAMESPACE |
61 | |
62 | /*! |
63 | \class QNetworkRequest |
64 | \since 4.4 |
65 | \ingroup network |
66 | \ingroup shared |
67 | \inmodule QtNetwork |
68 | |
69 | \brief The QNetworkRequest class holds a request to be sent with QNetworkAccessManager. |
70 | |
71 | QNetworkRequest is part of the Network Access API and is the class |
72 | holding the information necessary to send a request over the |
73 | network. It contains a URL and some ancillary information that can |
74 | be used to modify the request. |
75 | |
76 | \sa QNetworkReply, QNetworkAccessManager |
77 | */ |
78 | |
79 | /*! |
80 | \enum QNetworkRequest::KnownHeaders |
81 | |
82 | List of known header types that QNetworkRequest parses. Each known |
83 | header is also represented in raw form with its full HTTP name. |
84 | |
85 | \value ContentDispositionHeader Corresponds to the HTTP |
86 | Content-Disposition header and contains a string containing the |
87 | disposition type (for instance, attachment) and a parameter (for |
88 | instance, filename). |
89 | |
90 | \value ContentTypeHeader Corresponds to the HTTP Content-Type |
91 | header and contains a string containing the media (MIME) type and |
92 | any auxiliary data (for instance, charset). |
93 | |
94 | \value ContentLengthHeader Corresponds to the HTTP Content-Length |
95 | header and contains the length in bytes of the data transmitted. |
96 | |
97 | \value LocationHeader Corresponds to the HTTP Location |
98 | header and contains a URL representing the actual location of the |
99 | data, including the destination URL in case of redirections. |
100 | |
101 | \value LastModifiedHeader Corresponds to the HTTP Last-Modified |
102 | header and contains a QDateTime representing the last modification |
103 | date of the contents. |
104 | |
105 | \value IfModifiedSinceHeader Corresponds to the HTTP If-Modified-Since |
106 | header and contains a QDateTime. It is usually added to a |
107 | QNetworkRequest. The server shall send a 304 (Not Modified) response |
108 | if the resource has not changed since this time. |
109 | |
110 | \value ETagHeader Corresponds to the HTTP ETag |
111 | header and contains a QString representing the last modification |
112 | state of the contents. |
113 | |
114 | \value IfMatchHeader Corresponds to the HTTP If-Match |
115 | header and contains a QStringList. It is usually added to a |
116 | QNetworkRequest. The server shall send a 412 (Precondition Failed) |
117 | response if the resource does not match. |
118 | |
119 | \value IfNoneMatchHeader Corresponds to the HTTP If-None-Match |
120 | header and contains a QStringList. It is usually added to a |
121 | QNetworkRequest. The server shall send a 304 (Not Modified) response |
122 | if the resource does match. |
123 | |
124 | \value CookieHeader Corresponds to the HTTP Cookie header |
125 | and contains a QList<QNetworkCookie> representing the cookies to |
126 | be sent back to the server. |
127 | |
128 | \value SetCookieHeader Corresponds to the HTTP Set-Cookie |
129 | header and contains a QList<QNetworkCookie> representing the |
130 | cookies sent by the server to be stored locally. |
131 | |
132 | \value UserAgentHeader The User-Agent header sent by HTTP clients. |
133 | |
134 | \value ServerHeader The Server header received by HTTP clients. |
135 | |
136 | \sa header(), setHeader(), rawHeader(), setRawHeader() |
137 | */ |
138 | |
139 | /*! |
140 | \enum QNetworkRequest::Attribute |
141 | \since 4.7 |
142 | |
143 | Attribute codes for the QNetworkRequest and QNetworkReply. |
144 | |
145 | Attributes are extra meta-data that are used to control the |
146 | behavior of the request and to pass further information from the |
147 | reply back to the application. Attributes are also extensible, |
148 | allowing custom implementations to pass custom values. |
149 | |
150 | The following table explains what the default attribute codes are, |
151 | the QVariant types associated, the default value if said attribute |
152 | is missing and whether it's used in requests or replies. |
153 | |
154 | \value HttpStatusCodeAttribute |
155 | Replies only, type: QMetaType::Int (no default) |
156 | Indicates the HTTP status code received from the HTTP server |
157 | (like 200, 304, 404, 401, etc.). If the connection was not |
158 | HTTP-based, this attribute will not be present. |
159 | |
160 | \value HttpReasonPhraseAttribute |
161 | Replies only, type: QMetaType::QByteArray (no default) |
162 | Indicates the HTTP reason phrase as received from the HTTP |
163 | server (like "Ok", "Found", "Not Found", "Access Denied", |
164 | etc.) This is the human-readable representation of the status |
165 | code (see above). If the connection was not HTTP-based, this |
166 | attribute will not be present. |
167 | |
168 | \value RedirectionTargetAttribute |
169 | Replies only, type: QMetaType::QUrl (no default) |
170 | If present, it indicates that the server is redirecting the |
171 | request to a different URL. The Network Access API does not by |
172 | default follow redirections: the application can |
173 | determine if the requested redirection should be allowed, |
174 | according to its security policies, or it can set |
175 | QNetworkRequest::FollowRedirectsAttribute to true (in which case |
176 | the redirection will be followed and this attribute will not |
177 | be present in the reply). |
178 | The returned URL might be relative. Use QUrl::resolved() |
179 | to create an absolute URL out of it. |
180 | |
181 | \value ConnectionEncryptedAttribute |
182 | Replies only, type: QMetaType::Bool (default: false) |
183 | Indicates whether the data was obtained through an encrypted |
184 | (secure) connection. |
185 | |
186 | \value CacheLoadControlAttribute |
187 | Requests only, type: QMetaType::Int (default: QNetworkRequest::PreferNetwork) |
188 | Controls how the cache should be accessed. The possible values |
189 | are those of QNetworkRequest::CacheLoadControl. Note that the |
190 | default QNetworkAccessManager implementation does not support |
191 | caching. However, this attribute may be used by certain |
192 | backends to modify their requests (for example, for caching proxies). |
193 | |
194 | \value CacheSaveControlAttribute |
195 | Requests only, type: QMetaType::Bool (default: true) |
196 | Controls if the data obtained should be saved to cache for |
197 | future uses. If the value is false, the data obtained will not |
198 | be automatically cached. If true, data may be cached, provided |
199 | it is cacheable (what is cacheable depends on the protocol |
200 | being used). |
201 | |
202 | \value SourceIsFromCacheAttribute |
203 | Replies only, type: QMetaType::Bool (default: false) |
204 | Indicates whether the data was obtained from cache |
205 | or not. |
206 | |
207 | \value DoNotBufferUploadDataAttribute |
208 | Requests only, type: QMetaType::Bool (default: false) |
209 | Indicates whether the QNetworkAccessManager code is |
210 | allowed to buffer the upload data, e.g. when doing a HTTP POST. |
211 | When using this flag with sequential upload data, the ContentLengthHeader |
212 | header must be set. |
213 | |
214 | \value HttpPipeliningAllowedAttribute |
215 | Requests only, type: QMetaType::Bool (default: false) |
216 | Indicates whether the QNetworkAccessManager code is |
217 | allowed to use HTTP pipelining with this request. |
218 | |
219 | \value HttpPipeliningWasUsedAttribute |
220 | Replies only, type: QMetaType::Bool |
221 | Indicates whether the HTTP pipelining was used for receiving |
222 | this reply. |
223 | |
224 | \value CustomVerbAttribute |
225 | Requests only, type: QMetaType::QByteArray |
226 | Holds the value for the custom HTTP verb to send (destined for usage |
227 | of other verbs than GET, POST, PUT and DELETE). This verb is set |
228 | when calling QNetworkAccessManager::sendCustomRequest(). |
229 | |
230 | \value CookieLoadControlAttribute |
231 | Requests only, type: QMetaType::Int (default: QNetworkRequest::Automatic) |
232 | Indicates whether to send 'Cookie' headers in the request. |
233 | This attribute is set to false by Qt WebKit when creating a cross-origin |
234 | XMLHttpRequest where withCredentials has not been set explicitly to true by the |
235 | Javascript that created the request. |
236 | See \l{http://www.w3.org/TR/XMLHttpRequest2/#credentials-flag}{here} for more information. |
237 | (This value was introduced in 4.7.) |
238 | |
239 | \value CookieSaveControlAttribute |
240 | Requests only, type: QMetaType::Int (default: QNetworkRequest::Automatic) |
241 | Indicates whether to save 'Cookie' headers received from the server in reply |
242 | to the request. |
243 | This attribute is set to false by Qt WebKit when creating a cross-origin |
244 | XMLHttpRequest where withCredentials has not been set explicitly to true by the |
245 | Javascript that created the request. |
246 | See \l{http://www.w3.org/TR/XMLHttpRequest2/#credentials-flag} {here} for more information. |
247 | (This value was introduced in 4.7.) |
248 | |
249 | \value AuthenticationReuseAttribute |
250 | Requests only, type: QMetaType::Int (default: QNetworkRequest::Automatic) |
251 | Indicates whether to use cached authorization credentials in the request, |
252 | if available. If this is set to QNetworkRequest::Manual and the authentication |
253 | mechanism is 'Basic' or 'Digest', Qt will not send an an 'Authorization' HTTP |
254 | header with any cached credentials it may have for the request's URL. |
255 | This attribute is set to QNetworkRequest::Manual by Qt WebKit when creating a cross-origin |
256 | XMLHttpRequest where withCredentials has not been set explicitly to true by the |
257 | Javascript that created the request. |
258 | See \l{http://www.w3.org/TR/XMLHttpRequest2/#credentials-flag} {here} for more information. |
259 | (This value was introduced in 4.7.) |
260 | |
261 | \omitvalue MaximumDownloadBufferSizeAttribute |
262 | |
263 | \omitvalue DownloadBufferAttribute |
264 | |
265 | \omitvalue SynchronousRequestAttribute |
266 | |
267 | \value BackgroundRequestAttribute |
268 | Type: QMetaType::Bool (default: false) |
269 | Indicates that this is a background transfer, rather than a user initiated |
270 | transfer. Depending on the platform, background transfers may be subject |
271 | to different policies. |
272 | The QNetworkSession ConnectInBackground property will be set according to |
273 | this attribute. |
274 | |
275 | \value SpdyAllowedAttribute |
276 | Requests only, type: QMetaType::Bool (default: false) |
277 | Indicates whether the QNetworkAccessManager code is |
278 | allowed to use SPDY with this request. This applies only |
279 | to SSL requests, and depends on the server supporting SPDY. |
280 | Obsolete, use Http2 instead of Spdy. |
281 | |
282 | \value SpdyWasUsedAttribute |
283 | Replies only, type: QMetaType::Bool |
284 | Indicates whether SPDY was used for receiving |
285 | this reply. Obsolete, use Http2 instead of Spdy. |
286 | |
287 | \value Http2AllowedAttribute |
288 | Requests only, type: QMetaType::Bool (default: false) |
289 | Indicates whether the QNetworkAccessManager code is |
290 | allowed to use HTTP/2 with this request. This applies |
291 | to SSL requests or 'cleartext' HTTP/2. |
292 | |
293 | \value Http2WasUsedAttribute |
294 | Replies only, type: QMetaType::Bool (default: false) |
295 | Indicates whether HTTP/2 was used for receiving this reply. |
296 | (This value was introduced in 5.9.) |
297 | |
298 | \value HTTP2AllowedAttribute |
299 | Obsolete alias for Http2AllowedAttribute. |
300 | |
301 | \value HTTP2WasUsedAttribute |
302 | Obsolete alias for Http2WasUsedAttribute. |
303 | |
304 | \value EmitAllUploadProgressSignalsAttribute |
305 | Requests only, type: QMetaType::Bool (default: false) |
306 | Indicates whether all upload signals should be emitted. |
307 | By default, the uploadProgress signal is emitted only |
308 | in 100 millisecond intervals. |
309 | (This value was introduced in 5.5.) |
310 | |
311 | \value FollowRedirectsAttribute |
312 | Requests only, type: QMetaType::Bool (default: false) |
313 | Indicates whether the Network Access API should automatically follow a |
314 | HTTP redirect response or not. Currently redirects that are insecure, |
315 | that is redirecting from "https" to "http" protocol, are not allowed. |
316 | (This value was introduced in 5.6.) |
317 | |
318 | \value OriginalContentLengthAttribute |
319 | Replies only, type QMetaType::Int |
320 | Holds the original content-length attribute before being invalidated and |
321 | removed from the header when the data is compressed and the request was |
322 | marked to be decompressed automatically. |
323 | (This value was introduced in 5.9.) |
324 | |
325 | \value RedirectPolicyAttribute |
326 | Requests only, type: QMetaType::Int, should be one of the |
327 | QNetworkRequest::RedirectPolicy values (default: ManualRedirectPolicy). |
328 | This attribute obsoletes FollowRedirectsAttribute. |
329 | (This value was introduced in 5.9.) |
330 | |
331 | \value Http2DirectAttribute |
332 | Requests only, type: QMetaType::Bool (default: false) |
333 | If set, this attribute will force QNetworkAccessManager to use |
334 | HTTP/2 protocol without initial HTTP/2 protocol negotiation. |
335 | Use of this attribute implies prior knowledge that a particular |
336 | server supports HTTP/2. The attribute works with SSL or 'cleartext' |
337 | HTTP/2. If a server turns out to not support HTTP/2, when HTTP/2 direct |
338 | was specified, QNetworkAccessManager gives up, without attempting to |
339 | fall back to HTTP/1.1. If both Http2AllowedAttribute and |
340 | Http2DirectAttribute are set, Http2DirectAttribute takes priority. |
341 | (This value was introduced in 5.11.) |
342 | |
343 | \omitvalue ResourceTypeAttribute |
344 | |
345 | \value AutoDeleteReplyOnFinishAttribute |
346 | Requests only, type: QMetaType::Bool (default: false) |
347 | If set, this attribute will make QNetworkAccessManager delete |
348 | the QNetworkReply after having emitted "finished". |
349 | (This value was introduced in 5.14.) |
350 | |
351 | \value User |
352 | Special type. Additional information can be passed in |
353 | QVariants with types ranging from User to UserMax. The default |
354 | implementation of Network Access will ignore any request |
355 | attributes in this range and it will not produce any |
356 | attributes in this range in replies. The range is reserved for |
357 | extensions of QNetworkAccessManager. |
358 | |
359 | \value UserMax |
360 | Special type. See User. |
361 | */ |
362 | |
363 | /*! |
364 | \enum QNetworkRequest::CacheLoadControl |
365 | |
366 | Controls the caching mechanism of QNetworkAccessManager. |
367 | |
368 | \value AlwaysNetwork always load from network and do not |
369 | check if the cache has a valid entry (similar to the |
370 | "Reload" feature in browsers); in addition, force intermediate |
371 | caches to re-validate. |
372 | |
373 | \value PreferNetwork default value; load from the network |
374 | if the cached entry is older than the network entry. This will never |
375 | return stale data from the cache, but revalidate resources that |
376 | have become stale. |
377 | |
378 | \value PreferCache load from cache if available, |
379 | otherwise load from network. Note that this can return possibly |
380 | stale (but not expired) items from cache. |
381 | |
382 | \value AlwaysCache only load from cache, indicating error |
383 | if the item was not cached (i.e., off-line mode) |
384 | */ |
385 | |
386 | /*! |
387 | \enum QNetworkRequest::LoadControl |
388 | \since 4.7 |
389 | |
390 | Indicates if an aspect of the request's loading mechanism has been |
391 | manually overridden, e.g. by Qt WebKit. |
392 | |
393 | \value Automatic default value: indicates default behaviour. |
394 | |
395 | \value Manual indicates behaviour has been manually overridden. |
396 | */ |
397 | |
398 | /*! |
399 | \enum QNetworkRequest::RedirectPolicy |
400 | \since 5.9 |
401 | |
402 | Indicates whether the Network Access API should automatically follow a |
403 | HTTP redirect response or not. |
404 | |
405 | \value ManualRedirectPolicy Default value: not following any redirects. |
406 | |
407 | \value NoLessSafeRedirectPolicy Only "http"->"http", "http" -> "https" |
408 | or "https" -> "https" redirects are allowed. |
409 | Equivalent to setting the old FollowRedirectsAttribute |
410 | to true |
411 | |
412 | \value SameOriginRedirectPolicy Require the same protocol, host and port. |
413 | Note, http://example.com and http://example.com:80 |
414 | will fail with this policy (implicit/explicit ports |
415 | are considered to be a mismatch). |
416 | |
417 | \value UserVerifiedRedirectPolicy Client decides whether to follow each |
418 | redirect by handling the redirected() |
419 | signal, emitting redirectAllowed() on |
420 | the QNetworkReply object to allow |
421 | the redirect or aborting/finishing it to |
422 | reject the redirect. This can be used, |
423 | for example, to ask the user whether to |
424 | accept the redirect, or to decide |
425 | based on some app-specific configuration. |
426 | |
427 | \note When Qt handles redirects it will, for legacy and compatibility |
428 | reasons, issue the redirected request using GET when the server returns |
429 | a 301 or 302 response, regardless of the original method used, unless it was |
430 | HEAD. |
431 | */ |
432 | |
433 | /*! |
434 | \enum QNetworkRequest::TransferTimeoutConstant |
435 | \since 5.15 |
436 | |
437 | A constant that can be used for enabling transfer |
438 | timeouts with a preset value. |
439 | |
440 | \value DefaultTransferTimeoutConstant The transfer timeout in milliseconds. |
441 | Used if setTimeout() is called |
442 | without an argument. |
443 | */ |
444 | |
445 | class QNetworkRequestPrivate: public QSharedData, public QNetworkHeadersPrivate |
446 | { |
447 | public: |
448 | static const int maxRedirectCount = 50; |
449 | inline QNetworkRequestPrivate() |
450 | : priority(QNetworkRequest::NormalPriority) |
451 | #ifndef QT_NO_SSL |
452 | , sslConfiguration(nullptr) |
453 | #endif |
454 | , maxRedirectsAllowed(maxRedirectCount) |
455 | , transferTimeout(0) |
456 | { qRegisterMetaType<QNetworkRequest>(); } |
457 | ~QNetworkRequestPrivate() |
458 | { |
459 | #ifndef QT_NO_SSL |
460 | delete sslConfiguration; |
461 | #endif |
462 | } |
463 | |
464 | |
465 | QNetworkRequestPrivate(const QNetworkRequestPrivate &other) |
466 | : QSharedData(other), QNetworkHeadersPrivate(other) |
467 | { |
468 | url = other.url; |
469 | priority = other.priority; |
470 | maxRedirectsAllowed = other.maxRedirectsAllowed; |
471 | #ifndef QT_NO_SSL |
472 | sslConfiguration = nullptr; |
473 | if (other.sslConfiguration) |
474 | sslConfiguration = new QSslConfiguration(*other.sslConfiguration); |
475 | #endif |
476 | peerVerifyName = other.peerVerifyName; |
477 | #if QT_CONFIG(http) |
478 | h2Configuration = other.h2Configuration; |
479 | #endif |
480 | transferTimeout = other.transferTimeout; |
481 | } |
482 | |
483 | inline bool operator==(const QNetworkRequestPrivate &other) const |
484 | { |
485 | return url == other.url && |
486 | priority == other.priority && |
487 | rawHeaders == other.rawHeaders && |
488 | attributes == other.attributes && |
489 | maxRedirectsAllowed == other.maxRedirectsAllowed && |
490 | peerVerifyName == other.peerVerifyName |
491 | #if QT_CONFIG(http) |
492 | && h2Configuration == other.h2Configuration |
493 | #endif |
494 | && transferTimeout == other.transferTimeout |
495 | ; |
496 | // don't compare cookedHeaders |
497 | } |
498 | |
499 | QUrl url; |
500 | QNetworkRequest::Priority priority; |
501 | #ifndef QT_NO_SSL |
502 | mutable QSslConfiguration *sslConfiguration; |
503 | #endif |
504 | int maxRedirectsAllowed; |
505 | QString peerVerifyName; |
506 | #if QT_CONFIG(http) |
507 | QHttp2Configuration h2Configuration; |
508 | #endif |
509 | int transferTimeout; |
510 | }; |
511 | |
512 | /*! |
513 | Constructs a QNetworkRequest object with no URL to be requested. |
514 | Use setUrl() to set one. |
515 | |
516 | \sa url(), setUrl() |
517 | */ |
518 | QNetworkRequest::QNetworkRequest() |
519 | : d(new QNetworkRequestPrivate) |
520 | { |
521 | #if QT_CONFIG(http) |
522 | // Initial values proposed by RFC 7540 are quite draconian, |
523 | // so unless an application will set its own parameters, we |
524 | // make stream window size larger and increase (via WINDOW_UPDATE) |
525 | // the session window size. These are our 'defaults': |
526 | d->h2Configuration.setStreamReceiveWindowSize(Http2::qtDefaultStreamReceiveWindowSize); |
527 | d->h2Configuration.setSessionReceiveWindowSize(Http2::maxSessionReceiveWindowSize); |
528 | d->h2Configuration.setServerPushEnabled(false); |
529 | #endif // QT_CONFIG(http) |
530 | } |
531 | |
532 | /*! |
533 | Constructs a QNetworkRequest object with \a url as the URL to be |
534 | requested. |
535 | |
536 | \sa url(), setUrl() |
537 | */ |
538 | QNetworkRequest::QNetworkRequest(const QUrl &url) |
539 | : QNetworkRequest() |
540 | { |
541 | d->url = url; |
542 | } |
543 | |
544 | /*! |
545 | Creates a copy of \a other. |
546 | */ |
547 | QNetworkRequest::QNetworkRequest(const QNetworkRequest &other) |
548 | : d(other.d) |
549 | { |
550 | } |
551 | |
552 | /*! |
553 | Disposes of the QNetworkRequest object. |
554 | */ |
555 | QNetworkRequest::~QNetworkRequest() |
556 | { |
557 | // QSharedDataPointer auto deletes |
558 | d = nullptr; |
559 | } |
560 | |
561 | /*! |
562 | Returns \c true if this object is the same as \a other (i.e., if they |
563 | have the same URL, same headers and same meta-data settings). |
564 | |
565 | \sa operator!=() |
566 | */ |
567 | bool QNetworkRequest::operator==(const QNetworkRequest &other) const |
568 | { |
569 | return d == other.d || *d == *other.d; |
570 | } |
571 | |
572 | /*! |
573 | \fn bool QNetworkRequest::operator!=(const QNetworkRequest &other) const |
574 | |
575 | Returns \c false if this object is not the same as \a other. |
576 | |
577 | \sa operator==() |
578 | */ |
579 | |
580 | /*! |
581 | Creates a copy of \a other |
582 | */ |
583 | QNetworkRequest &QNetworkRequest::operator=(const QNetworkRequest &other) |
584 | { |
585 | d = other.d; |
586 | return *this; |
587 | } |
588 | |
589 | /*! |
590 | \fn void QNetworkRequest::swap(QNetworkRequest &other) |
591 | \since 5.0 |
592 | |
593 | Swaps this network request with \a other. This function is very |
594 | fast and never fails. |
595 | */ |
596 | |
597 | /*! |
598 | Returns the URL this network request is referring to. |
599 | |
600 | \sa setUrl() |
601 | */ |
602 | QUrl QNetworkRequest::url() const |
603 | { |
604 | return d->url; |
605 | } |
606 | |
607 | /*! |
608 | Sets the URL this network request is referring to be \a url. |
609 | |
610 | \sa url() |
611 | */ |
612 | void QNetworkRequest::setUrl(const QUrl &url) |
613 | { |
614 | d->url = url; |
615 | } |
616 | |
617 | /*! |
618 | Returns the value of the known network header \a header if it is |
619 | present in this request. If it is not present, returns QVariant() |
620 | (i.e., an invalid variant). |
621 | |
622 | \sa KnownHeaders, rawHeader(), setHeader() |
623 | */ |
624 | QVariant QNetworkRequest::(KnownHeaders ) const |
625 | { |
626 | return d->cookedHeaders.value(akey: header); |
627 | } |
628 | |
629 | /*! |
630 | Sets the value of the known header \a header to be \a value, |
631 | overriding any previously set headers. This operation also sets |
632 | the equivalent raw HTTP header. |
633 | |
634 | \sa KnownHeaders, setRawHeader(), header() |
635 | */ |
636 | void QNetworkRequest::(KnownHeaders , const QVariant &value) |
637 | { |
638 | d->setCookedHeader(header, value); |
639 | } |
640 | |
641 | /*! |
642 | Returns \c true if the raw header \a headerName is present in this |
643 | network request. |
644 | |
645 | \sa rawHeader(), setRawHeader() |
646 | */ |
647 | bool QNetworkRequest::(const QByteArray &) const |
648 | { |
649 | return d->findRawHeader(key: headerName) != d->rawHeaders.constEnd(); |
650 | } |
651 | |
652 | /*! |
653 | Returns the raw form of header \a headerName. If no such header is |
654 | present, an empty QByteArray is returned, which may be |
655 | indistinguishable from a header that is present but has no content |
656 | (use hasRawHeader() to find out if the header exists or not). |
657 | |
658 | Raw headers can be set with setRawHeader() or with setHeader(). |
659 | |
660 | \sa header(), setRawHeader() |
661 | */ |
662 | QByteArray QNetworkRequest::(const QByteArray &) const |
663 | { |
664 | QNetworkHeadersPrivate::RawHeadersList::ConstIterator it = |
665 | d->findRawHeader(key: headerName); |
666 | if (it != d->rawHeaders.constEnd()) |
667 | return it->second; |
668 | return QByteArray(); |
669 | } |
670 | |
671 | /*! |
672 | Returns a list of all raw headers that are set in this network |
673 | request. The list is in the order that the headers were set. |
674 | |
675 | \sa hasRawHeader(), rawHeader() |
676 | */ |
677 | QList<QByteArray> QNetworkRequest::() const |
678 | { |
679 | return d->rawHeadersKeys(); |
680 | } |
681 | |
682 | /*! |
683 | Sets the header \a headerName to be of value \a headerValue. If \a |
684 | headerName corresponds to a known header (see |
685 | QNetworkRequest::KnownHeaders), the raw format will be parsed and |
686 | the corresponding "cooked" header will be set as well. |
687 | |
688 | For example: |
689 | \snippet code/src_network_access_qnetworkrequest.cpp 0 |
690 | |
691 | will also set the known header LastModifiedHeader to be the |
692 | QDateTime object of the parsed date. |
693 | |
694 | \note Setting the same header twice overrides the previous |
695 | setting. To accomplish the behaviour of multiple HTTP headers of |
696 | the same name, you should concatenate the two values, separating |
697 | them with a comma (",") and set one single raw header. |
698 | |
699 | \sa KnownHeaders, setHeader(), hasRawHeader(), rawHeader() |
700 | */ |
701 | void QNetworkRequest::(const QByteArray &, const QByteArray &) |
702 | { |
703 | d->setRawHeader(key: headerName, value: headerValue); |
704 | } |
705 | |
706 | /*! |
707 | Returns the attribute associated with the code \a code. If the |
708 | attribute has not been set, it returns \a defaultValue. |
709 | |
710 | \note This function does not apply the defaults listed in |
711 | QNetworkRequest::Attribute. |
712 | |
713 | \sa setAttribute(), QNetworkRequest::Attribute |
714 | */ |
715 | QVariant QNetworkRequest::attribute(Attribute code, const QVariant &defaultValue) const |
716 | { |
717 | return d->attributes.value(akey: code, adefaultValue: defaultValue); |
718 | } |
719 | |
720 | /*! |
721 | Sets the attribute associated with code \a code to be value \a |
722 | value. If the attribute is already set, the previous value is |
723 | discarded. In special, if \a value is an invalid QVariant, the |
724 | attribute is unset. |
725 | |
726 | \sa attribute(), QNetworkRequest::Attribute |
727 | */ |
728 | void QNetworkRequest::setAttribute(Attribute code, const QVariant &value) |
729 | { |
730 | if (value.isValid()) |
731 | d->attributes.insert(akey: code, avalue: value); |
732 | else |
733 | d->attributes.remove(akey: code); |
734 | } |
735 | |
736 | #ifndef QT_NO_SSL |
737 | /*! |
738 | Returns this network request's SSL configuration. By default this is the same |
739 | as QSslConfiguration::defaultConfiguration(). |
740 | |
741 | \sa setSslConfiguration(), QSslConfiguration::defaultConfiguration() |
742 | */ |
743 | QSslConfiguration QNetworkRequest::sslConfiguration() const |
744 | { |
745 | if (!d->sslConfiguration) |
746 | d->sslConfiguration = new QSslConfiguration(QSslConfiguration::defaultConfiguration()); |
747 | return *d->sslConfiguration; |
748 | } |
749 | |
750 | /*! |
751 | Sets this network request's SSL configuration to be \a config. The |
752 | settings that apply are the private key, the local certificate, |
753 | the SSL protocol (SSLv2, SSLv3, TLSv1.0 where applicable), the CA |
754 | certificates and the ciphers that the SSL backend is allowed to |
755 | use. |
756 | |
757 | \sa sslConfiguration(), QSslConfiguration::defaultConfiguration() |
758 | */ |
759 | void QNetworkRequest::setSslConfiguration(const QSslConfiguration &config) |
760 | { |
761 | if (!d->sslConfiguration) |
762 | d->sslConfiguration = new QSslConfiguration(config); |
763 | else |
764 | *d->sslConfiguration = config; |
765 | } |
766 | #endif |
767 | |
768 | /*! |
769 | \since 4.6 |
770 | |
771 | Allows setting a reference to the \a object initiating |
772 | the request. |
773 | |
774 | For example Qt WebKit sets the originating object to the |
775 | QWebFrame that initiated the request. |
776 | |
777 | \sa originatingObject() |
778 | */ |
779 | void QNetworkRequest::setOriginatingObject(QObject *object) |
780 | { |
781 | d->originatingObject = object; |
782 | } |
783 | |
784 | /*! |
785 | \since 4.6 |
786 | |
787 | Returns a reference to the object that initiated this |
788 | network request; returns \nullptr if not set or the object has |
789 | been destroyed. |
790 | |
791 | \sa setOriginatingObject() |
792 | */ |
793 | QObject *QNetworkRequest::originatingObject() const |
794 | { |
795 | return d->originatingObject.data(); |
796 | } |
797 | |
798 | /*! |
799 | \since 4.7 |
800 | |
801 | Return the priority of this request. |
802 | |
803 | \sa setPriority() |
804 | */ |
805 | QNetworkRequest::Priority QNetworkRequest::priority() const |
806 | { |
807 | return d->priority; |
808 | } |
809 | |
810 | /*! \enum QNetworkRequest::Priority |
811 | |
812 | \since 4.7 |
813 | |
814 | This enum lists the possible network request priorities. |
815 | |
816 | \value HighPriority High priority |
817 | \value NormalPriority Normal priority |
818 | \value LowPriority Low priority |
819 | */ |
820 | |
821 | /*! |
822 | \since 4.7 |
823 | |
824 | Set the priority of this request to \a priority. |
825 | |
826 | \note The \a priority is only a hint to the network access |
827 | manager. It can use it or not. Currently it is used for HTTP to |
828 | decide which request should be sent first to a server. |
829 | |
830 | \sa priority() |
831 | */ |
832 | void QNetworkRequest::setPriority(Priority priority) |
833 | { |
834 | d->priority = priority; |
835 | } |
836 | |
837 | /*! |
838 | \since 5.6 |
839 | |
840 | Returns the maximum number of redirects allowed to be followed for this |
841 | request. |
842 | |
843 | \sa setMaximumRedirectsAllowed() |
844 | */ |
845 | int QNetworkRequest::maximumRedirectsAllowed() const |
846 | { |
847 | return d->maxRedirectsAllowed; |
848 | } |
849 | |
850 | /*! |
851 | \since 5.6 |
852 | |
853 | Sets the maximum number of redirects allowed to be followed for this |
854 | request to \a maxRedirectsAllowed. |
855 | |
856 | \sa maximumRedirectsAllowed() |
857 | */ |
858 | void QNetworkRequest::setMaximumRedirectsAllowed(int maxRedirectsAllowed) |
859 | { |
860 | d->maxRedirectsAllowed = maxRedirectsAllowed; |
861 | } |
862 | |
863 | /*! |
864 | \since 5.13 |
865 | |
866 | Returns the host name set for the certificate validation, as set by |
867 | setPeerVerifyName. By default this returns a null string. |
868 | |
869 | \sa setPeerVerifyName |
870 | */ |
871 | QString QNetworkRequest::peerVerifyName() const |
872 | { |
873 | return d->peerVerifyName; |
874 | } |
875 | |
876 | /*! |
877 | \since 5.13 |
878 | |
879 | Sets \a peerName as host name for the certificate validation, instead of the one used for the |
880 | TCP connection. |
881 | |
882 | \sa peerVerifyName |
883 | */ |
884 | void QNetworkRequest::setPeerVerifyName(const QString &peerName) |
885 | { |
886 | d->peerVerifyName = peerName; |
887 | } |
888 | |
889 | #if QT_CONFIG(http) || defined(Q_CLANG_QDOC) |
890 | /*! |
891 | \since 5.14 |
892 | |
893 | Returns the current parameters that QNetworkAccessManager is |
894 | using for this request and its underlying HTTP/2 connection. |
895 | This is either a configuration previously set by an application |
896 | or a default configuration. |
897 | |
898 | The default values that QNetworkAccessManager is using are: |
899 | |
900 | \list |
901 | \li Window size for connection-level flowcontrol is 2147483647 octets |
902 | \li Window size for stream-level flowcontrol is 21474836 octets |
903 | \li Max frame size is 16384 |
904 | \endlist |
905 | |
906 | By default, server push is disabled, Huffman compression and |
907 | string indexing are enabled. |
908 | |
909 | \sa setHttp2Configuration |
910 | */ |
911 | QHttp2Configuration QNetworkRequest::http2Configuration() const |
912 | { |
913 | return d->h2Configuration; |
914 | } |
915 | |
916 | /*! |
917 | \since 5.14 |
918 | |
919 | Sets request's HTTP/2 parameters from \a configuration. |
920 | |
921 | \note The configuration must be set prior to making a request. |
922 | \note HTTP/2 multiplexes several streams in a single HTTP/2 |
923 | connection. This implies that QNetworkAccessManager will use |
924 | the configuration found in the first request from a series |
925 | of requests sent to the same host. |
926 | |
927 | \sa http2Configuration, QNetworkAccessManager, QHttp2Configuration |
928 | */ |
929 | void QNetworkRequest::setHttp2Configuration(const QHttp2Configuration &configuration) |
930 | { |
931 | d->h2Configuration = configuration; |
932 | } |
933 | #endif // QT_CONFIG(http) || defined(Q_CLANG_QDOC) |
934 | #if QT_CONFIG(http) || defined(Q_CLANG_QDOC) || defined (Q_OS_WASM) |
935 | /*! |
936 | \since 5.15 |
937 | |
938 | Returns the timeout used for transfers, in milliseconds. |
939 | |
940 | This timeout is zero if setTransferTimeout hasn't been |
941 | called, which means that the timeout is not used. |
942 | |
943 | \sa setTransferTimeout |
944 | */ |
945 | int QNetworkRequest::transferTimeout() const |
946 | { |
947 | return d->transferTimeout; |
948 | } |
949 | |
950 | /*! |
951 | \since 5.15 |
952 | |
953 | Sets \a timeout as the transfer timeout in milliseconds. |
954 | |
955 | Transfers are aborted if no bytes are transferred before |
956 | the timeout expires. Zero means no timer is set. If no |
957 | argument is provided, the timeout is |
958 | QNetworkRequest::DefaultTransferTimeoutConstant. If this function |
959 | is not called, the timeout is disabled and has the |
960 | value zero. |
961 | |
962 | \sa transferTimeout |
963 | */ |
964 | void QNetworkRequest::setTransferTimeout(int timeout) |
965 | { |
966 | d->transferTimeout = timeout; |
967 | } |
968 | #endif // QT_CONFIG(http) || defined(Q_CLANG_QDOC) || defined (Q_OS_WASM) |
969 | |
970 | static QByteArray (QNetworkRequest::KnownHeaders ) |
971 | { |
972 | switch (header) { |
973 | case QNetworkRequest::ContentTypeHeader: |
974 | return "Content-Type" ; |
975 | |
976 | case QNetworkRequest::ContentLengthHeader: |
977 | return "Content-Length" ; |
978 | |
979 | case QNetworkRequest::LocationHeader: |
980 | return "Location" ; |
981 | |
982 | case QNetworkRequest::LastModifiedHeader: |
983 | return "Last-Modified" ; |
984 | |
985 | case QNetworkRequest::IfModifiedSinceHeader: |
986 | return "If-Modified-Since" ; |
987 | |
988 | case QNetworkRequest::ETagHeader: |
989 | return "ETag" ; |
990 | |
991 | case QNetworkRequest::IfMatchHeader: |
992 | return "If-Match" ; |
993 | |
994 | case QNetworkRequest::IfNoneMatchHeader: |
995 | return "If-None-Match" ; |
996 | |
997 | case QNetworkRequest::CookieHeader: |
998 | return "Cookie" ; |
999 | |
1000 | case QNetworkRequest::SetCookieHeader: |
1001 | return "Set-Cookie" ; |
1002 | |
1003 | case QNetworkRequest::ContentDispositionHeader: |
1004 | return "Content-Disposition" ; |
1005 | |
1006 | case QNetworkRequest::UserAgentHeader: |
1007 | return "User-Agent" ; |
1008 | |
1009 | case QNetworkRequest::ServerHeader: |
1010 | return "Server" ; |
1011 | |
1012 | // no default: |
1013 | // if new values are added, this will generate a compiler warning |
1014 | } |
1015 | |
1016 | return QByteArray(); |
1017 | } |
1018 | |
1019 | static QByteArray (QNetworkRequest::KnownHeaders , const QVariant &value) |
1020 | { |
1021 | switch (header) { |
1022 | case QNetworkRequest::ContentTypeHeader: |
1023 | case QNetworkRequest::ContentLengthHeader: |
1024 | case QNetworkRequest::ContentDispositionHeader: |
1025 | case QNetworkRequest::UserAgentHeader: |
1026 | case QNetworkRequest::ServerHeader: |
1027 | case QNetworkRequest::ETagHeader: |
1028 | case QNetworkRequest::IfMatchHeader: |
1029 | case QNetworkRequest::IfNoneMatchHeader: |
1030 | return value.toByteArray(); |
1031 | |
1032 | case QNetworkRequest::LocationHeader: |
1033 | switch (value.userType()) { |
1034 | case QMetaType::QUrl: |
1035 | return value.toUrl().toEncoded(); |
1036 | |
1037 | default: |
1038 | return value.toByteArray(); |
1039 | } |
1040 | |
1041 | case QNetworkRequest::LastModifiedHeader: |
1042 | case QNetworkRequest::IfModifiedSinceHeader: |
1043 | switch (value.userType()) { |
1044 | // Generate RFC 1123/822 dates: |
1045 | case QMetaType::QDate: |
1046 | return QNetworkHeadersPrivate::toHttpDate(dt: value.toDate().startOfDay(spec: Qt::UTC)); |
1047 | case QMetaType::QDateTime: |
1048 | return QNetworkHeadersPrivate::toHttpDate(dt: value.toDateTime()); |
1049 | |
1050 | default: |
1051 | return value.toByteArray(); |
1052 | } |
1053 | |
1054 | case QNetworkRequest::CookieHeader: { |
1055 | QList<QNetworkCookie> cookies = qvariant_cast<QList<QNetworkCookie> >(v: value); |
1056 | if (cookies.isEmpty() && value.userType() == qMetaTypeId<QNetworkCookie>()) |
1057 | cookies << qvariant_cast<QNetworkCookie>(v: value); |
1058 | |
1059 | QByteArray result; |
1060 | bool first = true; |
1061 | for (const QNetworkCookie &cookie : qAsConst(t&: cookies)) { |
1062 | if (!first) |
1063 | result += "; " ; |
1064 | first = false; |
1065 | result += cookie.toRawForm(form: QNetworkCookie::NameAndValueOnly); |
1066 | } |
1067 | return result; |
1068 | } |
1069 | |
1070 | case QNetworkRequest::SetCookieHeader: { |
1071 | QList<QNetworkCookie> cookies = qvariant_cast<QList<QNetworkCookie> >(v: value); |
1072 | if (cookies.isEmpty() && value.userType() == qMetaTypeId<QNetworkCookie>()) |
1073 | cookies << qvariant_cast<QNetworkCookie>(v: value); |
1074 | |
1075 | QByteArray result; |
1076 | bool first = true; |
1077 | for (const QNetworkCookie &cookie : qAsConst(t&: cookies)) { |
1078 | if (!first) |
1079 | result += ", " ; |
1080 | first = false; |
1081 | result += cookie.toRawForm(form: QNetworkCookie::Full); |
1082 | } |
1083 | return result; |
1084 | } |
1085 | } |
1086 | |
1087 | return QByteArray(); |
1088 | } |
1089 | |
1090 | static int (const QByteArray &) |
1091 | { |
1092 | if (headerName.isEmpty()) |
1093 | return -1; |
1094 | |
1095 | switch (tolower(c: headerName.at(i: 0))) { |
1096 | case 'c': |
1097 | if (headerName.compare(c: "content-type" , cs: Qt::CaseInsensitive) == 0) |
1098 | return QNetworkRequest::ContentTypeHeader; |
1099 | else if (headerName.compare(c: "content-length" , cs: Qt::CaseInsensitive) == 0) |
1100 | return QNetworkRequest::ContentLengthHeader; |
1101 | else if (headerName.compare(c: "cookie" , cs: Qt::CaseInsensitive) == 0) |
1102 | return QNetworkRequest::CookieHeader; |
1103 | else if (qstricmp(headerName.constData(), "content-disposition" ) == 0) |
1104 | return QNetworkRequest::ContentDispositionHeader; |
1105 | break; |
1106 | |
1107 | case 'e': |
1108 | if (qstricmp(headerName.constData(), "etag" ) == 0) |
1109 | return QNetworkRequest::ETagHeader; |
1110 | break; |
1111 | |
1112 | case 'i': |
1113 | if (qstricmp(headerName.constData(), "if-modified-since" ) == 0) |
1114 | return QNetworkRequest::IfModifiedSinceHeader; |
1115 | if (qstricmp(headerName.constData(), "if-match" ) == 0) |
1116 | return QNetworkRequest::IfMatchHeader; |
1117 | if (qstricmp(headerName.constData(), "if-none-match" ) == 0) |
1118 | return QNetworkRequest::IfNoneMatchHeader; |
1119 | break; |
1120 | |
1121 | case 'l': |
1122 | if (headerName.compare(c: "location" , cs: Qt::CaseInsensitive) == 0) |
1123 | return QNetworkRequest::LocationHeader; |
1124 | else if (headerName.compare(c: "last-modified" , cs: Qt::CaseInsensitive) == 0) |
1125 | return QNetworkRequest::LastModifiedHeader; |
1126 | break; |
1127 | |
1128 | case 's': |
1129 | if (headerName.compare(c: "set-cookie" , cs: Qt::CaseInsensitive) == 0) |
1130 | return QNetworkRequest::SetCookieHeader; |
1131 | else if (headerName.compare(c: "server" , cs: Qt::CaseInsensitive) == 0) |
1132 | return QNetworkRequest::ServerHeader; |
1133 | break; |
1134 | |
1135 | case 'u': |
1136 | if (headerName.compare(c: "user-agent" , cs: Qt::CaseInsensitive) == 0) |
1137 | return QNetworkRequest::UserAgentHeader; |
1138 | break; |
1139 | } |
1140 | |
1141 | return -1; // nothing found |
1142 | } |
1143 | |
1144 | static QVariant parseHttpDate(const QByteArray &raw) |
1145 | { |
1146 | QDateTime dt = QNetworkHeadersPrivate::fromHttpDate(value: raw); |
1147 | if (dt.isValid()) |
1148 | return dt; |
1149 | return QVariant(); // transform an invalid QDateTime into a null QVariant |
1150 | } |
1151 | |
1152 | static QVariant (const QByteArray &raw) |
1153 | { |
1154 | QList<QNetworkCookie> result; |
1155 | const QList<QByteArray> cookieList = raw.split(sep: ';'); |
1156 | for (const QByteArray &cookie : cookieList) { |
1157 | QList<QNetworkCookie> parsed = QNetworkCookie::parseCookies(cookieString: cookie.trimmed()); |
1158 | if (parsed.count() != 1) |
1159 | return QVariant(); // invalid Cookie: header |
1160 | |
1161 | result += parsed; |
1162 | } |
1163 | |
1164 | return QVariant::fromValue(value: result); |
1165 | } |
1166 | |
1167 | static QVariant parseETag(const QByteArray &raw) |
1168 | { |
1169 | const QByteArray trimmed = raw.trimmed(); |
1170 | if (!trimmed.startsWith(c: '"') && !trimmed.startsWith(c: R"(W/")" )) |
1171 | return QVariant(); |
1172 | |
1173 | if (!trimmed.endsWith(c: '"')) |
1174 | return QVariant(); |
1175 | |
1176 | return QString::fromLatin1(str: trimmed); |
1177 | } |
1178 | |
1179 | static QVariant parseIfMatch(const QByteArray &raw) |
1180 | { |
1181 | const QByteArray trimmedRaw = raw.trimmed(); |
1182 | if (trimmedRaw == "*" ) |
1183 | return QStringList(QStringLiteral("*" )); |
1184 | |
1185 | QStringList tags; |
1186 | const QList<QByteArray> split = trimmedRaw.split(sep: ','); |
1187 | for (const QByteArray &element : split) { |
1188 | const QByteArray trimmed = element.trimmed(); |
1189 | if (!trimmed.startsWith(c: '"')) |
1190 | continue; |
1191 | |
1192 | if (!trimmed.endsWith(c: '"')) |
1193 | continue; |
1194 | |
1195 | tags += QString::fromLatin1(str: trimmed); |
1196 | } |
1197 | return tags; |
1198 | } |
1199 | |
1200 | static QVariant parseIfNoneMatch(const QByteArray &raw) |
1201 | { |
1202 | const QByteArray trimmedRaw = raw.trimmed(); |
1203 | if (trimmedRaw == "*" ) |
1204 | return QStringList(QStringLiteral("*" )); |
1205 | |
1206 | QStringList tags; |
1207 | const QList<QByteArray> split = trimmedRaw.split(sep: ','); |
1208 | for (const QByteArray &element : split) { |
1209 | const QByteArray trimmed = element.trimmed(); |
1210 | if (!trimmed.startsWith(c: '"') && !trimmed.startsWith(c: R"(W/")" )) |
1211 | continue; |
1212 | |
1213 | if (!trimmed.endsWith(c: '"')) |
1214 | continue; |
1215 | |
1216 | tags += QString::fromLatin1(str: trimmed); |
1217 | } |
1218 | return tags; |
1219 | } |
1220 | |
1221 | |
1222 | static QVariant (QNetworkRequest::KnownHeaders , const QByteArray &value) |
1223 | { |
1224 | // header is always a valid value |
1225 | switch (header) { |
1226 | case QNetworkRequest::UserAgentHeader: |
1227 | case QNetworkRequest::ServerHeader: |
1228 | case QNetworkRequest::ContentTypeHeader: |
1229 | case QNetworkRequest::ContentDispositionHeader: |
1230 | // copy exactly, convert to QString |
1231 | return QString::fromLatin1(str: value); |
1232 | |
1233 | case QNetworkRequest::ContentLengthHeader: { |
1234 | bool ok; |
1235 | qint64 result = value.trimmed().toLongLong(ok: &ok); |
1236 | if (ok) |
1237 | return result; |
1238 | return QVariant(); |
1239 | } |
1240 | |
1241 | case QNetworkRequest::LocationHeader: { |
1242 | QUrl result = QUrl::fromEncoded(url: value, mode: QUrl::StrictMode); |
1243 | if (result.isValid() && !result.scheme().isEmpty()) |
1244 | return result; |
1245 | return QVariant(); |
1246 | } |
1247 | |
1248 | case QNetworkRequest::LastModifiedHeader: |
1249 | case QNetworkRequest::IfModifiedSinceHeader: |
1250 | return parseHttpDate(raw: value); |
1251 | |
1252 | case QNetworkRequest::ETagHeader: |
1253 | return parseETag(raw: value); |
1254 | |
1255 | case QNetworkRequest::IfMatchHeader: |
1256 | return parseIfMatch(raw: value); |
1257 | |
1258 | case QNetworkRequest::IfNoneMatchHeader: |
1259 | return parseIfNoneMatch(raw: value); |
1260 | |
1261 | case QNetworkRequest::CookieHeader: |
1262 | return parseCookieHeader(raw: value); |
1263 | |
1264 | case QNetworkRequest::SetCookieHeader: |
1265 | return QVariant::fromValue(value: QNetworkCookie::parseCookies(cookieString: value)); |
1266 | |
1267 | default: |
1268 | Q_ASSERT(0); |
1269 | } |
1270 | return QVariant(); |
1271 | } |
1272 | |
1273 | QNetworkHeadersPrivate::RawHeadersList::ConstIterator |
1274 | QNetworkHeadersPrivate::(const QByteArray &key) const |
1275 | { |
1276 | RawHeadersList::ConstIterator it = rawHeaders.constBegin(); |
1277 | RawHeadersList::ConstIterator end = rawHeaders.constEnd(); |
1278 | for ( ; it != end; ++it) |
1279 | if (it->first.compare(a: key, cs: Qt::CaseInsensitive) == 0) |
1280 | return it; |
1281 | |
1282 | return end; // not found |
1283 | } |
1284 | |
1285 | QNetworkHeadersPrivate::RawHeadersList QNetworkHeadersPrivate::() const |
1286 | { |
1287 | return rawHeaders; |
1288 | } |
1289 | |
1290 | QList<QByteArray> QNetworkHeadersPrivate::() const |
1291 | { |
1292 | QList<QByteArray> result; |
1293 | result.reserve(alloc: rawHeaders.size()); |
1294 | RawHeadersList::ConstIterator it = rawHeaders.constBegin(), |
1295 | end = rawHeaders.constEnd(); |
1296 | for ( ; it != end; ++it) |
1297 | result << it->first; |
1298 | |
1299 | return result; |
1300 | } |
1301 | |
1302 | void QNetworkHeadersPrivate::(const QByteArray &key, const QByteArray &value) |
1303 | { |
1304 | if (key.isEmpty()) |
1305 | // refuse to accept an empty raw header |
1306 | return; |
1307 | |
1308 | setRawHeaderInternal(key, value); |
1309 | parseAndSetHeader(key, value); |
1310 | } |
1311 | |
1312 | /*! |
1313 | \internal |
1314 | Sets the internal raw headers list to match \a list. The cooked headers |
1315 | will also be updated. |
1316 | |
1317 | If \a list contains duplicates, they will be stored, but only the first one |
1318 | is usually accessed. |
1319 | */ |
1320 | void QNetworkHeadersPrivate::(const RawHeadersList &list) |
1321 | { |
1322 | cookedHeaders.clear(); |
1323 | rawHeaders = list; |
1324 | |
1325 | RawHeadersList::ConstIterator it = rawHeaders.constBegin(); |
1326 | RawHeadersList::ConstIterator end = rawHeaders.constEnd(); |
1327 | for ( ; it != end; ++it) |
1328 | parseAndSetHeader(key: it->first, value: it->second); |
1329 | } |
1330 | |
1331 | void QNetworkHeadersPrivate::(QNetworkRequest::KnownHeaders , |
1332 | const QVariant &value) |
1333 | { |
1334 | QByteArray name = headerName(header); |
1335 | if (name.isEmpty()) { |
1336 | // headerName verifies that \a header is a known value |
1337 | qWarning(msg: "QNetworkRequest::setHeader: invalid header value KnownHeader(%d) received" , header); |
1338 | return; |
1339 | } |
1340 | |
1341 | if (value.isNull()) { |
1342 | setRawHeaderInternal(key: name, value: QByteArray()); |
1343 | cookedHeaders.remove(akey: header); |
1344 | } else { |
1345 | QByteArray rawValue = headerValue(header, value); |
1346 | if (rawValue.isEmpty()) { |
1347 | qWarning(msg: "QNetworkRequest::setHeader: QVariant of type %s cannot be used with header %s" , |
1348 | value.typeName(), name.constData()); |
1349 | return; |
1350 | } |
1351 | |
1352 | setRawHeaderInternal(key: name, value: rawValue); |
1353 | cookedHeaders.insert(akey: header, avalue: value); |
1354 | } |
1355 | } |
1356 | |
1357 | void QNetworkHeadersPrivate::(const QByteArray &key, const QByteArray &value) |
1358 | { |
1359 | auto firstEqualsKey = [&key](const RawHeaderPair &) { |
1360 | return header.first.compare(a: key, cs: Qt::CaseInsensitive) == 0; |
1361 | }; |
1362 | rawHeaders.erase(afirst: std::remove_if(first: rawHeaders.begin(), last: rawHeaders.end(), |
1363 | pred: firstEqualsKey), |
1364 | alast: rawHeaders.end()); |
1365 | |
1366 | if (value.isNull()) |
1367 | return; // only wanted to erase key |
1368 | |
1369 | RawHeaderPair pair; |
1370 | pair.first = key; |
1371 | pair.second = value; |
1372 | rawHeaders.append(t: pair); |
1373 | } |
1374 | |
1375 | void QNetworkHeadersPrivate::parseAndSetHeader(const QByteArray &key, const QByteArray &value) |
1376 | { |
1377 | // is it a known header? |
1378 | const int parsedKeyAsInt = parseHeaderName(headerName: key); |
1379 | if (parsedKeyAsInt != -1) { |
1380 | const QNetworkRequest::KnownHeaders parsedKey |
1381 | = static_cast<QNetworkRequest::KnownHeaders>(parsedKeyAsInt); |
1382 | if (value.isNull()) { |
1383 | cookedHeaders.remove(akey: parsedKey); |
1384 | } else if (parsedKey == QNetworkRequest::ContentLengthHeader |
1385 | && cookedHeaders.contains(akey: QNetworkRequest::ContentLengthHeader)) { |
1386 | // Only set the cooked header "Content-Length" once. |
1387 | // See bug QTBUG-15311 |
1388 | } else { |
1389 | cookedHeaders.insert(akey: parsedKey, avalue: parseHeaderValue(header: parsedKey, value)); |
1390 | } |
1391 | |
1392 | } |
1393 | } |
1394 | |
1395 | // Fast month string to int conversion. This code |
1396 | // assumes that the Month name is correct and that |
1397 | // the string is at least three chars long. |
1398 | static int name_to_month(const char* month_str) |
1399 | { |
1400 | switch (month_str[0]) { |
1401 | case 'J': |
1402 | switch (month_str[1]) { |
1403 | case 'a': |
1404 | return 1; |
1405 | case 'u': |
1406 | switch (month_str[2] ) { |
1407 | case 'n': |
1408 | return 6; |
1409 | case 'l': |
1410 | return 7; |
1411 | } |
1412 | } |
1413 | break; |
1414 | case 'F': |
1415 | return 2; |
1416 | case 'M': |
1417 | switch (month_str[2] ) { |
1418 | case 'r': |
1419 | return 3; |
1420 | case 'y': |
1421 | return 5; |
1422 | } |
1423 | break; |
1424 | case 'A': |
1425 | switch (month_str[1]) { |
1426 | case 'p': |
1427 | return 4; |
1428 | case 'u': |
1429 | return 8; |
1430 | } |
1431 | break; |
1432 | case 'O': |
1433 | return 10; |
1434 | case 'S': |
1435 | return 9; |
1436 | case 'N': |
1437 | return 11; |
1438 | case 'D': |
1439 | return 12; |
1440 | } |
1441 | |
1442 | return 0; |
1443 | } |
1444 | |
1445 | QDateTime QNetworkHeadersPrivate::(const QByteArray &value) |
1446 | { |
1447 | // HTTP dates have three possible formats: |
1448 | // RFC 1123/822 - ddd, dd MMM yyyy hh:mm:ss "GMT" |
1449 | // RFC 850 - dddd, dd-MMM-yy hh:mm:ss "GMT" |
1450 | // ANSI C's asctime - ddd MMM d hh:mm:ss yyyy |
1451 | // We only handle them exactly. If they deviate, we bail out. |
1452 | |
1453 | int pos = value.indexOf(c: ','); |
1454 | QDateTime dt; |
1455 | #if QT_CONFIG(datestring) |
1456 | if (pos == -1) { |
1457 | // no comma -> asctime(3) format |
1458 | dt = QDateTime::fromString(s: QString::fromLatin1(str: value), f: Qt::TextDate); |
1459 | } else { |
1460 | // Use sscanf over QLocal/QDateTimeParser for speed reasons. See the |
1461 | // Qt WebKit performance benchmarks to get an idea. |
1462 | if (pos == 3) { |
1463 | char month_name[4]; |
1464 | int day, year, hour, minute, second; |
1465 | #ifdef Q_CC_MSVC |
1466 | // Use secure version to avoid compiler warning |
1467 | if (sscanf_s(value.constData(), "%*3s, %d %3s %d %d:%d:%d 'GMT'" , &day, month_name, 4, &year, &hour, &minute, &second) == 6) |
1468 | #else |
1469 | // The POSIX secure mode is %ms (which allocates memory), too bleeding edge for now |
1470 | // In any case this is already safe as field width is specified. |
1471 | if (sscanf(s: value.constData(), format: "%*3s, %d %3s %d %d:%d:%d 'GMT'" , &day, month_name, &year, &hour, &minute, &second) == 6) |
1472 | #endif |
1473 | dt = QDateTime(QDate(year, name_to_month(month_str: month_name), day), QTime(hour, minute, second)); |
1474 | } else { |
1475 | QLocale c = QLocale::c(); |
1476 | // eat the weekday, the comma and the space following it |
1477 | QString sansWeekday = QString::fromLatin1(str: value.constData() + pos + 2); |
1478 | // must be RFC 850 date |
1479 | dt = c.toDateTime(string: sansWeekday, format: QLatin1String("dd-MMM-yy hh:mm:ss 'GMT'" )); |
1480 | } |
1481 | } |
1482 | #endif // datestring |
1483 | |
1484 | if (dt.isValid()) |
1485 | dt.setTimeSpec(Qt::UTC); |
1486 | return dt; |
1487 | } |
1488 | |
1489 | QByteArray QNetworkHeadersPrivate::(const QDateTime &dt) |
1490 | { |
1491 | return QLocale::c().toString(dateTime: dt.toUTC(), format: u"ddd, dd MMM yyyy hh:mm:ss 'GMT'" ).toLatin1(); |
1492 | } |
1493 | |
1494 | QT_END_NAMESPACE |
1495 | |