1/****************************************************************************
2**
3** Copyright (C) 2020 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 "qnetworkaccessbackend_p.h"
41#include "qnetworkreplyimpl_p.h"
42#include "qnetworkaccessmanager_p.h"
43#include "qnetworkrequest.h"
44#include "qnetworkreply.h"
45#include "qnetworkreply_p.h"
46#include "QtCore/qmutex.h"
47#include "QtCore/qstringlist.h"
48
49#include "qnetworkaccesscachebackend_p.h"
50#include "qabstractnetworkcache.h"
51#include "qhostinfo.h"
52
53#include "private/qnoncontiguousbytedevice_p.h"
54
55QT_BEGIN_NAMESPACE
56
57class QNetworkAccessBackendFactoryData: public QList<QNetworkAccessBackendFactory *>
58{
59public:
60 QNetworkAccessBackendFactoryData()
61 {
62 valid.ref();
63 }
64 ~QNetworkAccessBackendFactoryData()
65 {
66 QMutexLocker locker(&mutex); // why do we need to lock?
67 valid.deref();
68 }
69
70 QRecursiveMutex mutex;
71 //this is used to avoid (re)constructing factory data from destructors of other global classes
72 static QBasicAtomicInt valid;
73};
74Q_GLOBAL_STATIC(QNetworkAccessBackendFactoryData, factoryData)
75QBasicAtomicInt QNetworkAccessBackendFactoryData::valid = Q_BASIC_ATOMIC_INITIALIZER(0);
76
77class QNetworkAccessBackendPrivate : public QObjectPrivate
78{
79public:
80 QNetworkAccessBackend::TargetTypes m_targetTypes;
81 QNetworkAccessBackend::SecurityFeatures m_securityFeatures;
82 QNetworkAccessBackend::IOFeatures m_ioFeatures;
83 QSharedPointer<QNonContiguousByteDevice> uploadByteDevice;
84 QIODevice *wrappedUploadByteDevice;
85 QNetworkReplyImplPrivate *m_reply = nullptr;
86 QNetworkAccessManagerPrivate *m_manager = nullptr;
87
88 bool m_canCache = false;
89 bool m_isSynchronous = false;
90};
91
92QNetworkAccessBackend *
93QNetworkAccessManagerPrivate::findBackend(QNetworkAccessManager::Operation op,
94 const QNetworkRequest &request)
95{
96 if (QNetworkAccessBackendFactoryData::valid.loadRelaxed()) {
97 QMutexLocker locker(&factoryData()->mutex);
98 QNetworkAccessBackendFactoryData::ConstIterator it = factoryData()->constBegin(),
99 end = factoryData()->constEnd();
100 while (it != end) {
101 QNetworkAccessBackend *backend = (*it)->create(op, request);
102 if (backend) {
103 backend->setManagerPrivate(this);
104 return backend; // found a factory that handled our request
105 }
106 ++it;
107 }
108 }
109 return nullptr;
110}
111
112QStringList QNetworkAccessManagerPrivate::backendSupportedSchemes() const
113{
114 if (QNetworkAccessBackendFactoryData::valid.loadRelaxed()) {
115 QMutexLocker locker(&factoryData()->mutex);
116 QNetworkAccessBackendFactoryData::ConstIterator it = factoryData()->constBegin();
117 QNetworkAccessBackendFactoryData::ConstIterator end = factoryData()->constEnd();
118 QStringList schemes;
119 while (it != end) {
120 schemes += (*it)->supportedSchemes();
121 ++it;
122 }
123 return schemes;
124 }
125 return QStringList();
126}
127
128/*!
129 \enum QNetworkAccessBackend::TargetType
130
131 Use the values in this enum to specify what type of target
132 the plugin supports. Setting the right type can be important,
133 for example: proxyList() is only available for a Networked
134 plugin.
135
136 \value Networked
137 The plugin supports and expect to connect to networked
138 resources. E.g. over TCP, UDP or similar.
139 \value Local
140 The plugin supports and expects to access local files,
141 generate data and/or locally connected devices.
142*/
143
144/*!
145 \enum QNetworkAccessBackend::SecurityFeature
146
147 Use the values in this enum to specify what type of security
148 features the plugin may utilize. Setting the right type(s)
149 can be important, for example: setSslConfiguration() may not
150 be called for any plugin that do not claim to support TLS.
151
152 \value None
153 No specific features are claimed to be supported.
154 \value TLS
155 The plugin supports and expects to use TLS.
156*/
157
158/*!
159 \enum QNetworkAccessBackend::IOFeature
160
161 Use the values in this enum to specify what type of IO
162 features the plugin may utilize.
163
164 \value None
165 No specific features are claimed to be supported.
166 \value ZeroCopy
167 The plugin will have raw data available in contiguous
168 segments and can return a pointer to the data at request.
169 Claiming to support this requires implementing readPointer()
170 and advanceReadPointer().
171 \value NeedResetableUpload
172 The plugin may encounter scenarios where data to upload that
173 has already been consumed needs to be restored and re-sent.
174 E.g. some data was consumed and sent before a redirect
175 response was received, and after the redirect the
176 previously-consumed data needs to be re-sent.
177 \omitvalue SupportsSynchronousMode
178*/
179
180/*!
181 Constructs the QNetworkAccessBackend.
182 You can opt in to specific backend behaviors with \a targetTypes,
183 \a securityFeatures and \a ioFeatures.
184 See their respective enums and values for more information.
185
186 \sa TargetType, SecurityFeature, IOFeature
187*/
188QNetworkAccessBackend::QNetworkAccessBackend(TargetTypes targetTypes,
189 SecurityFeatures securityFeatures,
190 IOFeatures ioFeatures)
191 : QObject(*(new QNetworkAccessBackendPrivate), nullptr)
192{
193 Q_D(QNetworkAccessBackend);
194 d->m_targetTypes = targetTypes;
195 d->m_securityFeatures = securityFeatures;
196 d->m_ioFeatures = ioFeatures;
197}
198
199/*!
200 \overload
201*/
202QNetworkAccessBackend::QNetworkAccessBackend(TargetTypes targetTypes)
203 : QNetworkAccessBackend(targetTypes, SecurityFeature::None, IOFeature::None)
204{
205}
206
207/*!
208 \overload
209*/
210QNetworkAccessBackend::QNetworkAccessBackend(TargetTypes targetTypes,
211 SecurityFeatures securityFeatures)
212 : QNetworkAccessBackend(targetTypes, securityFeatures, IOFeature::None)
213{
214}
215
216/*!
217 \overload
218*/
219QNetworkAccessBackend::QNetworkAccessBackend(TargetTypes targetTypes, IOFeatures ioFeatures)
220 : QNetworkAccessBackend(targetTypes, SecurityFeature::None, ioFeatures)
221{
222}
223
224/*!
225 Destructs the QNetworkAccessBackend base class.
226*/
227QNetworkAccessBackend::~QNetworkAccessBackend() { }
228
229/*!
230 Returns the security related features that the backend claims to
231 support.
232
233 \sa SecurityFeature
234*/
235QNetworkAccessBackend::SecurityFeatures QNetworkAccessBackend::securityFeatures() const noexcept
236{
237 return d_func()->m_securityFeatures;
238}
239
240/*!
241 Returns the TargetTypes that the backend claims to target.
242
243 \sa TargetType
244*/
245QNetworkAccessBackend::TargetTypes QNetworkAccessBackend::targetTypes() const noexcept
246{
247 return d_func()->m_targetTypes;
248}
249
250/*!
251 Returns the I/O features that the backend claims to support.
252
253 \sa IOFeature
254*/
255QNetworkAccessBackend::IOFeatures QNetworkAccessBackend::ioFeatures() const noexcept
256{
257 return d_func()->m_ioFeatures;
258}
259
260/*!
261 Prepares the backend and calls open().
262 E.g. for TargetType::Networked it will prepare proxyList().
263
264 \sa TargetType, targetTypes
265*/
266bool QNetworkAccessBackend::start()
267{
268 Q_D(QNetworkAccessBackend);
269#ifndef QT_NO_NETWORKPROXY
270 if (targetTypes() & QNetworkAccessBackend::TargetType::Networked)
271 d->m_reply->proxyList = d->m_manager->queryProxy(QNetworkProxyQuery(url()));
272#endif
273
274 // now start the request
275 open();
276 return true;
277}
278
279#if QT_CONFIG(ssl)
280/*!
281 Passes a \a configuration with the user's desired TLS
282 configuration. If you don't have the TLS security feature this
283 may not be called.
284
285 \sa SecurityFeature, securityFeatures
286*/
287void QNetworkAccessBackend::setSslConfiguration(const QSslConfiguration &configuration)
288{
289 Q_UNUSED(configuration);
290 if (securityFeatures() & SecurityFeature::TLS) {
291 qWarning("Backend (%s) claiming to use TLS hasn't overridden setSslConfiguration.",
292 metaObject()->className());
293 }
294}
295
296/*!
297 Override this and return the QSslConfiguration used if you
298 have the TLS security feature
299
300 \sa SecurityFeature, securityFeatures
301*/
302QSslConfiguration QNetworkAccessBackend::sslConfiguration() const
303{
304 if (securityFeatures() & SecurityFeature::TLS) {
305 qWarning("Backend (%s) claiming to use TLS hasn't overridden sslConfiguration.",
306 metaObject()->className());
307 }
308 return {};
309}
310#endif
311
312/*!
313 This function will be called when the user wants to ignore
314 all TLS handshake errors. Derive this function if TLS is
315 supported.
316
317 \sa SecurityFeature, securityFeatures
318*/
319void QNetworkAccessBackend::ignoreSslErrors()
320{
321 if (securityFeatures() & SecurityFeature::TLS) {
322 qWarning("Backend (%s) claiming to use TLS hasn't overridden ignoreSslErrors.",
323 metaObject()->className());
324 }
325}
326
327/*!
328 This function will be called when the user wants to ignore
329 specific \a errors. Derive this function if TLS is supported.
330
331 \sa SecurityFeature, securityFeatures
332*/
333void QNetworkAccessBackend::ignoreSslErrors(const QList<QSslError> &errors)
334{
335 Q_UNUSED(errors);
336 if (securityFeatures() & SecurityFeature::TLS) {
337 qWarning("Backend (%s) claiming to use TLS hasn't overridden ignoreSslErrors.",
338 metaObject()->className());
339 }
340}
341
342/*!
343 The data which the returned value views must stay valid until
344 at least the next call to a non-const function. advanceReadPointer
345 will be called if any of the data was used.
346
347 Note: This will only be called if IOFeature::ZeroCopy was
348 specified in the call to the constructor.
349
350 \sa advanceReadPointer, read
351*/
352QByteArrayView QNetworkAccessBackend::readPointer()
353{
354 if (ioFeatures() & IOFeature::ZeroCopy) {
355 qWarning("Backend (%s) claiming to support ZeroCopy hasn't overridden readPointer.",
356 metaObject()->className());
357 }
358 return {};
359}
360
361/*!
362 This function is to notify your class that \a distance
363 bytes have been read using readPointer and next time
364 readPointer() is called those bytes should not be included.
365
366 Note: This will only be called if IOFeature::ZeroCopy was
367 specified in the call to the constructor.
368
369 \sa readPointer
370*/
371void QNetworkAccessBackend::advanceReadPointer(qint64 distance)
372{
373 Q_UNUSED(distance);
374 if (ioFeatures() & IOFeature::ZeroCopy) {
375 qWarning("Backend (%s) claiming to support ZeroCopy hasn't overridden advanceReadPointer.",
376 metaObject()->className());
377 }
378}
379
380/*!
381 Implement this function to support reading from the resource
382 made available by your plugin.
383 Store data in \a data, up to a maximum of \a maxlen bytes.
384 Then return the total amount of bytes that was copied.
385
386 \sa readPointer, wantToRead
387*/
388qint64 QNetworkAccessBackend::read(char *data, qint64 maxlen)
389{
390 Q_UNUSED(data);
391 Q_UNUSED(maxlen);
392 if ((ioFeatures() & IOFeature::ZeroCopy) == 0) {
393 qWarning("Backend (%s) is not ZeroCopy and has not implemented read(...)!",
394 metaObject()->className());
395 }
396 return 0;
397}
398
399/*!
400 This is called before we read if there are no bytes available
401 and we are ready to read more. Return \c true if new data was
402 made available.
403
404 \sa read, readPointer
405*/
406bool QNetworkAccessBackend::wantToRead()
407{
408 // Base implementation does nothing
409 return false;
410}
411
412#if QT_CONFIG(networkproxy)
413/*!
414 Returns a list of proxies configured for the URL returned by
415 url().
416
417 It is only valid to call this function if TargetType::Networked
418 was specified in the call to the constructor.
419*/
420QList<QNetworkProxy> QNetworkAccessBackend::proxyList() const
421{
422 Q_ASSERT(targetTypes() & TargetType::Networked);
423 return d_func()->m_reply->proxyList;
424}
425#endif
426
427/*!
428 Returns the current URL of the reply
429*/
430QUrl QNetworkAccessBackend::url() const
431{
432 return d_func()->m_reply->url;
433}
434
435/*!
436 Sets the URL of the reply. This could e.g. be needed if a
437 redirect or similar was performed.
438*/
439void QNetworkAccessBackend::setUrl(const QUrl &url)
440{
441 d_func()->m_reply->url = url;
442}
443
444/*!
445 Returns the value of the \a header.
446 If no such header was known it returns a default-constructed
447 QVariant.
448
449 \sa setHeader, rawHeader, setRawHeader
450*/
451QVariant QNetworkAccessBackend::header(QNetworkRequest::KnownHeaders header) const
452{
453 return d_func()->m_reply->cookedHeaders.value(header);
454}
455
456/*!
457 Sets the value of the \a header to \a value.
458 This can be queried on the QNetworkReply instance which was
459 returned when calling one of the appropriate functions on
460 QNetworkAccessManager.
461
462 \sa header, rawHeader, setRawHeader
463*/
464void QNetworkAccessBackend::setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value)
465{
466 d_func()->m_reply->setCookedHeader(header, value);
467}
468
469/*!
470 Returns the value of the \a header.
471 If no such header was known it returns a default-constructed
472 QVariant.
473
474 \sa setHeader, rawHeader, setRawHeader
475*/
476QByteArray QNetworkAccessBackend::rawHeader(const QByteArray &header) const
477{
478 return d_func()->m_reply->q_func()->rawHeader(header);
479}
480
481/*!
482 Sets the value of the \a header to \a value.
483
484 This value is accessible on the QNetworkReply instance which was
485 returned when calling one of the appropriate functions on
486 QNetworkAccessManager.
487
488 \sa header, rawHeader, setRawHeader
489*/
490void QNetworkAccessBackend::setRawHeader(const QByteArray &header, const QByteArray &value)
491{
492 d_func()->m_reply->setRawHeader(header, value);
493}
494
495/*!
496 Returns the operation which was requested when calling
497 QNetworkAccessManager.
498*/
499QNetworkAccessManager::Operation QNetworkAccessBackend::operation() const
500{
501 return d_func()->m_reply->operation;
502}
503
504/*!
505 Returns \c true if setCachingEnabled was previously called with \c true.
506 Returns \c false otherwise, which is the default value.
507
508 \sa setCachingEnabled
509*/
510bool QNetworkAccessBackend::isCachingEnabled() const
511{
512 return d_func()->m_canCache;
513}
514
515/*!
516 If \a canCache is \c true then this hints to us that we can cache
517 the reply that is created.
518
519 \sa isCachingEnabled
520*/
521void QNetworkAccessBackend::setCachingEnabled(bool canCache)
522{
523 d_func()->m_canCache = canCache;
524}
525
526/*!
527 Set \a attribute to \a value. If \c{value.isValid()} returns
528 \c false then the attribute is unset.
529
530 This value is accessible on the QNetworkReply instance which was
531 returned when calling one of the appropriate functions on
532 QNetworkAccessManager.
533*/
534void QNetworkAccessBackend::setAttribute(QNetworkRequest::Attribute attribute,
535 const QVariant &value)
536{
537 Q_D(QNetworkAccessBackend);
538 if (value.isValid())
539 d->m_reply->attributes.insert(attribute, value);
540 else
541 d->m_reply->attributes.remove(attribute);
542}
543
544/*!
545 Creates a QIODevice for the data provided to upload, if any.
546
547 Emission of upload progress is handled internally as the device
548 gets read from.
549
550 Returns a pointer to a device with data or nullptr if there was
551 no data to upload.
552*/
553QIODevice *QNetworkAccessBackend::createUploadByteDevice()
554{
555 Q_D(QNetworkAccessBackend);
556
557 if (d->m_reply->outgoingDataBuffer)
558 d->uploadByteDevice =
559 QNonContiguousByteDeviceFactory::createShared(d->m_reply->outgoingDataBuffer);
560 else if (d->m_reply->outgoingData) {
561 d->uploadByteDevice =
562 QNonContiguousByteDeviceFactory::createShared(d->m_reply->outgoingData);
563 } else {
564 return nullptr;
565 }
566
567 // We want signal emissions only for normal asynchronous uploads
568 if (!isSynchronous()) {
569 connect(d->uploadByteDevice.data(), &QNonContiguousByteDevice::readProgress, this,
570 [this](qint64 a, qint64 b) {
571 Q_D(QNetworkAccessBackend);
572 if (!d->m_reply->isFinished)
573 d->m_reply->emitUploadProgress(a, b);
574 });
575 }
576
577 d->wrappedUploadByteDevice = QNonContiguousByteDeviceFactory::wrap(d->uploadByteDevice.data());
578 return d->wrappedUploadByteDevice;
579}
580
581/*!
582 Returns the upload byte device associated with the current
583 request. This does not create the request but simply returns
584 the pointer stored in this base class so it doesn't need to be
585 stored in the subclass too.
586*/
587QIODevice *QNetworkAccessBackend::uploadByteDevice()
588{
589 return d_func()->wrappedUploadByteDevice;
590}
591
592/*!
593 \internal
594 Returns \c true if synchronous mode is enabled.
595 If it is disabled or not supported it will return \c {false}.
596*/
597bool QNetworkAccessBackend::isSynchronous() const
598{
599 return d_func()->m_isSynchronous;
600}
601
602/*!
603 \internal
604 Enables or disables synchronous mode depending on \a synchronous
605 if the backend supports it. Otherwise it will always be disabled.
606*/
607void QNetworkAccessBackend::setSynchronous(bool synchronous)
608{
609 if ((ioFeatures() & IOFeature::SupportsSynchronousMode) == 0)
610 return;
611 d_func()->m_isSynchronous = synchronous;
612}
613
614/*!
615 Call this slot when you have more data available to notify
616 the backend that we can attempt to read again.
617*/
618void QNetworkAccessBackend::readyRead()
619{
620 d_func()->m_reply->backendNotify(QNetworkReplyImplPrivate::NotifyDownstreamReadyWrite);
621}
622
623/*!
624 Call this slot when there will be no more data available,
625 regardless of whether the transfer was successful or unsuccessful.
626 For unsuccessful transfers make sure to call error() first!
627*/
628void QNetworkAccessBackend::finished()
629{
630 d_func()->m_reply->finished();
631}
632
633/*!
634 Call this slot if an error occurs. An error would be something
635 you cannot recover from (e.g. the file requested is missing).
636 The \a code and \a errorString is transferred to and stored in
637 the QNetworkReply and the \a code is emitted through the
638 QNetworkReply::errorOccurred() signal.
639*/
640void QNetworkAccessBackend::error(QNetworkReply::NetworkError code, const QString &errorString)
641{
642 Q_ASSERT(!d_func()->m_reply->isFinished);
643 d_func()->m_reply->error(code, errorString);
644}
645
646#ifndef QT_NO_NETWORKPROXY
647/*!
648 Call this slot if, when connecting through a proxy, it requests
649 authentication. This may cause the
650 QNetworkAccessManager::proxyAuthenticationRequired() signal to be
651 emitted if the credentials are not already stored in an internal
652 cache.
653 To be able to make the lookup in the cache and potentially the
654 subsequent request the \a proxy needs to be known. The credentials
655 will be stored in \a authenticator. While \a authenticator is a
656 pointer, passing \c nullptr is invalid.
657*/
658void QNetworkAccessBackend::proxyAuthenticationRequired(const QNetworkProxy &proxy,
659 QAuthenticator *authenticator)
660{
661 Q_D(QNetworkAccessBackend);
662 Q_ASSERT(authenticator);
663 d->m_manager->proxyAuthenticationRequired(QUrl(), proxy, isSynchronous(), authenticator,
664 &d->m_reply->lastProxyAuthentication);
665}
666#endif
667
668/*!
669 Call this slot if the remote resource requests authentication.
670 This may cause the
671 QNetworkAccessManager::authenticationRequired() signal to be
672 emitted if the credentials are not already stored in an internal
673 cache.
674 The credentials will be stored in \a authenticator. While
675 \a authenticator is a pointer, passing \c nullptr is invalid.
676*/
677void QNetworkAccessBackend::authenticationRequired(QAuthenticator *authenticator)
678{
679 Q_D(QNetworkAccessBackend);
680 Q_ASSERT(authenticator);
681 d->m_manager->authenticationRequired(authenticator, d->m_reply->q_func(), isSynchronous(),
682 d->m_reply->url, &d->m_reply->urlForLastAuthentication);
683}
684
685/*!
686 Call this slot, if appropriate, after having processed and
687 updated metadata (e.g. headers).
688*/
689void QNetworkAccessBackend::metaDataChanged()
690{
691 d_func()->m_reply->metaDataChanged();
692}
693
694/*!
695 Call this slot if, when connecting to the resource, a redirect
696 to \a destination was requested.
697*/
698void QNetworkAccessBackend::redirectionRequested(const QUrl &destination)
699{
700 d_func()->m_reply->redirectionRequested(destination);
701}
702
703/*!
704 \internal
705*/
706void QNetworkAccessBackend::setReplyPrivate(QNetworkReplyImplPrivate *reply)
707{
708 d_func()->m_reply = reply;
709}
710
711/*!
712 \internal
713*/
714void QNetworkAccessBackend::setManagerPrivate(QNetworkAccessManagerPrivate *manager)
715{
716 d_func()->m_manager = manager;
717}
718
719/*!
720 Returns the network cache object that was available when the
721 request was started. Returns \c nullptr if none was available.
722*/
723QAbstractNetworkCache *QNetworkAccessBackend::networkCache() const
724{
725 return d_func()->m_manager->networkCache;
726}
727
728// -- QNetworkAccessBackendFactory
729/*!
730 Constructs QNetworkAccessBackendFactory
731*/
732QNetworkAccessBackendFactory::QNetworkAccessBackendFactory()
733{
734 if (factoryData())
735 factoryData->append(this);
736}
737
738/*!
739 Destructs QNetworkAccessBackendFactory
740*/
741QNetworkAccessBackendFactory::~QNetworkAccessBackendFactory() = default;
742
743QT_END_NAMESPACE
744