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