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 "qnetworkaccessbackend_p.h"
41 #include "qnetworkaccessmanager_p.h"
42 #include "qnetworkconfigmanager.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 #include "QtNetwork/private/qnetworksession_p.h"
49
50 #include "qnetworkaccesscachebackend_p.h"
51 #include "qabstractnetworkcache.h"
52 #include "qhostinfo.h"
53
54 #include "private/qnoncontiguousbytedevice_p.h"
55
56 QT_BEGIN_NAMESPACE
57
58 class QNetworkAccessBackendFactoryData: public QList<QNetworkAccessBackendFactory *>
59 {
60 public:
QNetworkAccessBackendFactoryData()61 QNetworkAccessBackendFactoryData()
62 {
63 valid.ref();
64 }
~QNetworkAccessBackendFactoryData()65 ~QNetworkAccessBackendFactoryData()
66 {
67 QMutexLocker locker(&mutex); // why do we need to lock?
68 valid.deref();
69 }
70
71 QRecursiveMutex mutex;
72 //this is used to avoid (re)constructing factory data from destructors of other global classes
73 static QBasicAtomicInt valid;
74 };
75 Q_GLOBAL_STATIC(QNetworkAccessBackendFactoryData, factoryData)
76 QBasicAtomicInt QNetworkAccessBackendFactoryData::valid = Q_BASIC_ATOMIC_INITIALIZER(0);
77
QNetworkAccessBackendFactory()78 QNetworkAccessBackendFactory::QNetworkAccessBackendFactory()
79 {
80 QMutexLocker locker(&factoryData()->mutex);
81 factoryData()->append(this);
82 }
83
~QNetworkAccessBackendFactory()84 QNetworkAccessBackendFactory::~QNetworkAccessBackendFactory()
85 {
86 if (QNetworkAccessBackendFactoryData::valid.loadRelaxed()) {
87 QMutexLocker locker(&factoryData()->mutex);
88 factoryData()->removeAll(this);
89 }
90 }
91
findBackend(QNetworkAccessManager::Operation op,const QNetworkRequest & request)92 QNetworkAccessBackend *QNetworkAccessManagerPrivate::findBackend(QNetworkAccessManager::Operation op,
93 const QNetworkRequest &request)
94 {
95 if (QNetworkAccessBackendFactoryData::valid.loadRelaxed()) {
96 QMutexLocker locker(&factoryData()->mutex);
97 QNetworkAccessBackendFactoryData::ConstIterator it = factoryData()->constBegin(),
98 end = factoryData()->constEnd();
99 while (it != end) {
100 QNetworkAccessBackend *backend = (*it)->create(op, request);
101 if (backend) {
102 backend->manager = this;
103 return backend; // found a factory that handled our request
104 }
105 ++it;
106 }
107 }
108 return nullptr;
109 }
110
backendSupportedSchemes() const111 QStringList QNetworkAccessManagerPrivate::backendSupportedSchemes() const
112 {
113 if (QNetworkAccessBackendFactoryData::valid.loadRelaxed()) {
114 QMutexLocker locker(&factoryData()->mutex);
115 QNetworkAccessBackendFactoryData::ConstIterator it = factoryData()->constBegin();
116 QNetworkAccessBackendFactoryData::ConstIterator end = factoryData()->constEnd();
117 QStringList schemes;
118 while (it != end) {
119 schemes += (*it)->supportedSchemes();
120 ++it;
121 }
122 return schemes;
123 }
124 return QStringList();
125 }
126
createUploadByteDevice()127 QNonContiguousByteDevice* QNetworkAccessBackend::createUploadByteDevice()
128 {
129 if (reply->outgoingDataBuffer)
130 uploadByteDevice = QNonContiguousByteDeviceFactory::createShared(reply->outgoingDataBuffer);
131 else if (reply->outgoingData) {
132 uploadByteDevice = QNonContiguousByteDeviceFactory::createShared(reply->outgoingData);
133 } else {
134 return nullptr;
135 }
136
137 // We want signal emissions only for normal asynchronous uploads
138 if (!isSynchronous())
139 connect(uploadByteDevice.data(), SIGNAL(readProgress(qint64,qint64)), this, SLOT(emitReplyUploadProgress(qint64,qint64)));
140
141 return uploadByteDevice.data();
142 }
143
144 // need to have this function since the reply is a private member variable
145 // and the special backends need to access this.
emitReplyUploadProgress(qint64 bytesSent,qint64 bytesTotal)146 void QNetworkAccessBackend::emitReplyUploadProgress(qint64 bytesSent, qint64 bytesTotal)
147 {
148 if (reply->isFinished)
149 return;
150 reply->emitUploadProgress(bytesSent, bytesTotal);
151 }
152
QNetworkAccessBackend()153 QNetworkAccessBackend::QNetworkAccessBackend()
154 : manager(nullptr)
155 , reply(nullptr)
156 , synchronous(false)
157 {
158 }
159
~QNetworkAccessBackend()160 QNetworkAccessBackend::~QNetworkAccessBackend()
161 {
162 }
163
downstreamReadyWrite()164 void QNetworkAccessBackend::downstreamReadyWrite()
165 {
166 // do nothing
167 }
168
setDownstreamLimited(bool b)169 void QNetworkAccessBackend::setDownstreamLimited(bool b)
170 {
171 Q_UNUSED(b);
172 // do nothing
173 }
174
copyFinished(QIODevice *)175 void QNetworkAccessBackend::copyFinished(QIODevice *)
176 {
177 // do nothing
178 }
179
ignoreSslErrors()180 void QNetworkAccessBackend::ignoreSslErrors()
181 {
182 // do nothing
183 }
184
ignoreSslErrors(const QList<QSslError> & errors)185 void QNetworkAccessBackend::ignoreSslErrors(const QList<QSslError> &errors)
186 {
187 Q_UNUSED(errors);
188 // do nothing
189 }
190
fetchSslConfiguration(QSslConfiguration &) const191 void QNetworkAccessBackend::fetchSslConfiguration(QSslConfiguration &) const
192 {
193 // do nothing
194 }
195
setSslConfiguration(const QSslConfiguration &)196 void QNetworkAccessBackend::setSslConfiguration(const QSslConfiguration &)
197 {
198 // do nothing
199 }
200
fetchCacheMetaData(const QNetworkCacheMetaData &) const201 QNetworkCacheMetaData QNetworkAccessBackend::fetchCacheMetaData(const QNetworkCacheMetaData &) const
202 {
203 return QNetworkCacheMetaData();
204 }
205
operation() const206 QNetworkAccessManager::Operation QNetworkAccessBackend::operation() const
207 {
208 return reply->operation;
209 }
210
request() const211 QNetworkRequest QNetworkAccessBackend::request() const
212 {
213 return reply->request;
214 }
215
216 #ifndef QT_NO_NETWORKPROXY
proxyList() const217 QList<QNetworkProxy> QNetworkAccessBackend::proxyList() const
218 {
219 return reply->proxyList;
220 }
221 #endif
222
networkCache() const223 QAbstractNetworkCache *QNetworkAccessBackend::networkCache() const
224 {
225 if (!manager)
226 return nullptr;
227 return manager->networkCache;
228 }
229
setCachingEnabled(bool enable)230 void QNetworkAccessBackend::setCachingEnabled(bool enable)
231 {
232 reply->setCachingEnabled(enable);
233 }
234
isCachingEnabled() const235 bool QNetworkAccessBackend::isCachingEnabled() const
236 {
237 return reply->isCachingEnabled();
238 }
239
nextDownstreamBlockSize() const240 qint64 QNetworkAccessBackend::nextDownstreamBlockSize() const
241 {
242 return reply->nextDownstreamBlockSize();
243 }
244
writeDownstreamData(QByteDataBuffer & list)245 void QNetworkAccessBackend::writeDownstreamData(QByteDataBuffer &list)
246 {
247 reply->appendDownstreamData(list);
248 }
249
writeDownstreamData(QIODevice * data)250 void QNetworkAccessBackend::writeDownstreamData(QIODevice *data)
251 {
252 reply->appendDownstreamData(data);
253 }
254
255 // not actually appending data, it was already written to the user buffer
writeDownstreamDataDownloadBuffer(qint64 bytesReceived,qint64 bytesTotal)256 void QNetworkAccessBackend::writeDownstreamDataDownloadBuffer(qint64 bytesReceived, qint64 bytesTotal)
257 {
258 reply->appendDownstreamDataDownloadBuffer(bytesReceived, bytesTotal);
259 }
260
getDownloadBuffer(qint64 size)261 char* QNetworkAccessBackend::getDownloadBuffer(qint64 size)
262 {
263 return reply->getDownloadBuffer(size);
264 }
265
header(QNetworkRequest::KnownHeaders header) const266 QVariant QNetworkAccessBackend::header(QNetworkRequest::KnownHeaders header) const
267 {
268 return reply->q_func()->header(header);
269 }
270
setHeader(QNetworkRequest::KnownHeaders header,const QVariant & value)271 void QNetworkAccessBackend::setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value)
272 {
273 reply->setCookedHeader(header, value);
274 }
275
hasRawHeader(const QByteArray & headerName) const276 bool QNetworkAccessBackend::hasRawHeader(const QByteArray &headerName) const
277 {
278 return reply->q_func()->hasRawHeader(headerName);
279 }
280
rawHeader(const QByteArray & headerName) const281 QByteArray QNetworkAccessBackend::rawHeader(const QByteArray &headerName) const
282 {
283 return reply->q_func()->rawHeader(headerName);
284 }
285
rawHeaderList() const286 QList<QByteArray> QNetworkAccessBackend::rawHeaderList() const
287 {
288 return reply->q_func()->rawHeaderList();
289 }
290
setRawHeader(const QByteArray & headerName,const QByteArray & headerValue)291 void QNetworkAccessBackend::setRawHeader(const QByteArray &headerName, const QByteArray &headerValue)
292 {
293 reply->setRawHeader(headerName, headerValue);
294 }
295
attribute(QNetworkRequest::Attribute code) const296 QVariant QNetworkAccessBackend::attribute(QNetworkRequest::Attribute code) const
297 {
298 return reply->q_func()->attribute(code);
299 }
300
setAttribute(QNetworkRequest::Attribute code,const QVariant & value)301 void QNetworkAccessBackend::setAttribute(QNetworkRequest::Attribute code, const QVariant &value)
302 {
303 if (value.isValid())
304 reply->attributes.insert(code, value);
305 else
306 reply->attributes.remove(code);
307 }
url() const308 QUrl QNetworkAccessBackend::url() const
309 {
310 return reply->url;
311 }
312
setUrl(const QUrl & url)313 void QNetworkAccessBackend::setUrl(const QUrl &url)
314 {
315 reply->url = url;
316 }
317
finished()318 void QNetworkAccessBackend::finished()
319 {
320 reply->finished();
321 }
322
error(QNetworkReply::NetworkError code,const QString & errorString)323 void QNetworkAccessBackend::error(QNetworkReply::NetworkError code, const QString &errorString)
324 {
325 reply->error(code, errorString);
326 }
327
328 #ifndef QT_NO_NETWORKPROXY
proxyAuthenticationRequired(const QNetworkProxy & proxy,QAuthenticator * authenticator)329 void QNetworkAccessBackend::proxyAuthenticationRequired(const QNetworkProxy &proxy,
330 QAuthenticator *authenticator)
331 {
332 manager->proxyAuthenticationRequired(QUrl(), proxy, synchronous, authenticator, &reply->lastProxyAuthentication);
333 }
334 #endif
335
authenticationRequired(QAuthenticator * authenticator)336 void QNetworkAccessBackend::authenticationRequired(QAuthenticator *authenticator)
337 {
338 manager->authenticationRequired(authenticator, reply->q_func(), synchronous, reply->url, &reply->urlForLastAuthentication);
339 }
340
metaDataChanged()341 void QNetworkAccessBackend::metaDataChanged()
342 {
343 reply->metaDataChanged();
344 }
345
redirectionRequested(const QUrl & target)346 void QNetworkAccessBackend::redirectionRequested(const QUrl &target)
347 {
348 reply->redirectionRequested(target);
349 }
350
encrypted()351 void QNetworkAccessBackend::encrypted()
352 {
353 #ifndef QT_NO_SSL
354 reply->encrypted();
355 #endif
356 }
357
sslErrors(const QList<QSslError> & errors)358 void QNetworkAccessBackend::sslErrors(const QList<QSslError> &errors)
359 {
360 #ifndef QT_NO_SSL
361 reply->sslErrors(errors);
362 #else
363 Q_UNUSED(errors);
364 #endif
365 }
366
367 /*!
368 Starts the backend. Returns \c true if the backend is started. Returns \c false if the backend
369 could not be started due to an unopened or roaming session. The caller should recall this
370 function once the session has been opened or the roaming process has finished.
371 */
start()372 bool QNetworkAccessBackend::start()
373 {
374 #ifndef QT_NO_BEARERMANAGEMENT // ### Qt6: Remove section
375 // For bearer, check if session start is required
376 QSharedPointer<QNetworkSession> networkSession(manager->getNetworkSession());
377 if (networkSession) {
378 // session required
379 if (networkSession->isOpen() &&
380 networkSession->state() == QNetworkSession::Connected) {
381 // Session is already open and ready to use.
382 // copy network session down to the backend
383 setProperty("_q_networksession", QVariant::fromValue(networkSession));
384 } else {
385 // Session not ready, but can skip for loopback connections
386
387 // This is not ideal.
388 // Don't need an open session for localhost access.
389 if (!reply->url.isLocalFile()) {
390 const QString host = reply->url.host();
391 if (host != QLatin1String("localhost") && !QHostAddress(host).isLoopback())
392 return false; // need to wait for session to be opened
393 }
394 }
395 }
396 #endif
397
398 #ifndef QT_NO_NETWORKPROXY
399 reply->proxyList = manager->queryProxy(QNetworkProxyQuery(url()));
400 #endif
401
402 // now start the request
403 open();
404 return true;
405 }
406
407 QT_END_NAMESPACE
408