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: |
61 | QNetworkAccessBackendFactoryData() |
62 | { |
63 | valid.ref(); |
64 | } |
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 | |
78 | QNetworkAccessBackendFactory::QNetworkAccessBackendFactory() |
79 | { |
80 | QMutexLocker locker(&factoryData()->mutex); |
81 | factoryData()->append(t: this); |
82 | } |
83 | |
84 | QNetworkAccessBackendFactory::~QNetworkAccessBackendFactory() |
85 | { |
86 | if (QNetworkAccessBackendFactoryData::valid.loadRelaxed()) { |
87 | QMutexLocker locker(&factoryData()->mutex); |
88 | factoryData()->removeAll(t: this); |
89 | } |
90 | } |
91 | |
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 | |
111 | 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 | |
127 | QNonContiguousByteDevice* QNetworkAccessBackend::createUploadByteDevice() |
128 | { |
129 | if (reply->outgoingDataBuffer) |
130 | uploadByteDevice = QNonContiguousByteDeviceFactory::createShared(ringBuffer: reply->outgoingDataBuffer); |
131 | else if (reply->outgoingData) { |
132 | uploadByteDevice = QNonContiguousByteDeviceFactory::createShared(device: reply->outgoingData); |
133 | } else { |
134 | return nullptr; |
135 | } |
136 | |
137 | // We want signal emissions only for normal asynchronous uploads |
138 | if (!isSynchronous()) |
139 | connect(sender: uploadByteDevice.data(), SIGNAL(readProgress(qint64,qint64)), receiver: 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. |
146 | void QNetworkAccessBackend::emitReplyUploadProgress(qint64 bytesSent, qint64 bytesTotal) |
147 | { |
148 | if (reply->isFinished) |
149 | return; |
150 | reply->emitUploadProgress(bytesSent, bytesTotal); |
151 | } |
152 | |
153 | QNetworkAccessBackend::QNetworkAccessBackend() |
154 | : manager(nullptr) |
155 | , reply(nullptr) |
156 | , synchronous(false) |
157 | { |
158 | } |
159 | |
160 | QNetworkAccessBackend::~QNetworkAccessBackend() |
161 | { |
162 | } |
163 | |
164 | void QNetworkAccessBackend::downstreamReadyWrite() |
165 | { |
166 | // do nothing |
167 | } |
168 | |
169 | void QNetworkAccessBackend::setDownstreamLimited(bool b) |
170 | { |
171 | Q_UNUSED(b); |
172 | // do nothing |
173 | } |
174 | |
175 | void QNetworkAccessBackend::copyFinished(QIODevice *) |
176 | { |
177 | // do nothing |
178 | } |
179 | |
180 | void QNetworkAccessBackend::ignoreSslErrors() |
181 | { |
182 | // do nothing |
183 | } |
184 | |
185 | void QNetworkAccessBackend::ignoreSslErrors(const QList<QSslError> &errors) |
186 | { |
187 | Q_UNUSED(errors); |
188 | // do nothing |
189 | } |
190 | |
191 | void QNetworkAccessBackend::fetchSslConfiguration(QSslConfiguration &) const |
192 | { |
193 | // do nothing |
194 | } |
195 | |
196 | void QNetworkAccessBackend::setSslConfiguration(const QSslConfiguration &) |
197 | { |
198 | // do nothing |
199 | } |
200 | |
201 | QNetworkCacheMetaData QNetworkAccessBackend::fetchCacheMetaData(const QNetworkCacheMetaData &) const |
202 | { |
203 | return QNetworkCacheMetaData(); |
204 | } |
205 | |
206 | QNetworkAccessManager::Operation QNetworkAccessBackend::operation() const |
207 | { |
208 | return reply->operation; |
209 | } |
210 | |
211 | QNetworkRequest QNetworkAccessBackend::request() const |
212 | { |
213 | return reply->request; |
214 | } |
215 | |
216 | #ifndef QT_NO_NETWORKPROXY |
217 | QList<QNetworkProxy> QNetworkAccessBackend::proxyList() const |
218 | { |
219 | return reply->proxyList; |
220 | } |
221 | #endif |
222 | |
223 | QAbstractNetworkCache *QNetworkAccessBackend::networkCache() const |
224 | { |
225 | if (!manager) |
226 | return nullptr; |
227 | return manager->networkCache; |
228 | } |
229 | |
230 | void QNetworkAccessBackend::setCachingEnabled(bool enable) |
231 | { |
232 | reply->setCachingEnabled(enable); |
233 | } |
234 | |
235 | bool QNetworkAccessBackend::isCachingEnabled() const |
236 | { |
237 | return reply->isCachingEnabled(); |
238 | } |
239 | |
240 | qint64 QNetworkAccessBackend::nextDownstreamBlockSize() const |
241 | { |
242 | return reply->nextDownstreamBlockSize(); |
243 | } |
244 | |
245 | void QNetworkAccessBackend::writeDownstreamData(QByteDataBuffer &list) |
246 | { |
247 | reply->appendDownstreamData(data&: list); |
248 | } |
249 | |
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 |
256 | void QNetworkAccessBackend::writeDownstreamDataDownloadBuffer(qint64 bytesReceived, qint64 bytesTotal) |
257 | { |
258 | reply->appendDownstreamDataDownloadBuffer(bytesReceived, bytesTotal); |
259 | } |
260 | |
261 | char* QNetworkAccessBackend::getDownloadBuffer(qint64 size) |
262 | { |
263 | return reply->getDownloadBuffer(size); |
264 | } |
265 | |
266 | QVariant QNetworkAccessBackend::(QNetworkRequest::KnownHeaders ) const |
267 | { |
268 | return reply->q_func()->header(header); |
269 | } |
270 | |
271 | void QNetworkAccessBackend::(QNetworkRequest::KnownHeaders , const QVariant &value) |
272 | { |
273 | reply->setCookedHeader(header, value); |
274 | } |
275 | |
276 | bool QNetworkAccessBackend::(const QByteArray &) const |
277 | { |
278 | return reply->q_func()->hasRawHeader(headerName); |
279 | } |
280 | |
281 | QByteArray QNetworkAccessBackend::(const QByteArray &) const |
282 | { |
283 | return reply->q_func()->rawHeader(headerName); |
284 | } |
285 | |
286 | QList<QByteArray> QNetworkAccessBackend::() const |
287 | { |
288 | return reply->q_func()->rawHeaderList(); |
289 | } |
290 | |
291 | void QNetworkAccessBackend::(const QByteArray &, const QByteArray &) |
292 | { |
293 | reply->setRawHeader(key: headerName, value: headerValue); |
294 | } |
295 | |
296 | QVariant QNetworkAccessBackend::attribute(QNetworkRequest::Attribute code) const |
297 | { |
298 | return reply->q_func()->attribute(code); |
299 | } |
300 | |
301 | void QNetworkAccessBackend::setAttribute(QNetworkRequest::Attribute code, const QVariant &value) |
302 | { |
303 | if (value.isValid()) |
304 | reply->attributes.insert(akey: code, avalue: value); |
305 | else |
306 | reply->attributes.remove(akey: code); |
307 | } |
308 | QUrl QNetworkAccessBackend::url() const |
309 | { |
310 | return reply->url; |
311 | } |
312 | |
313 | void QNetworkAccessBackend::setUrl(const QUrl &url) |
314 | { |
315 | reply->url = url; |
316 | } |
317 | |
318 | void QNetworkAccessBackend::finished() |
319 | { |
320 | reply->finished(); |
321 | } |
322 | |
323 | void QNetworkAccessBackend::error(QNetworkReply::NetworkError code, const QString &errorString) |
324 | { |
325 | reply->error(code, errorString); |
326 | } |
327 | |
328 | #ifndef QT_NO_NETWORKPROXY |
329 | void QNetworkAccessBackend::proxyAuthenticationRequired(const QNetworkProxy &proxy, |
330 | QAuthenticator *authenticator) |
331 | { |
332 | manager->proxyAuthenticationRequired(url: QUrl(), proxy, synchronous, authenticator, lastProxyAuthentication: &reply->lastProxyAuthentication); |
333 | } |
334 | #endif |
335 | |
336 | void QNetworkAccessBackend::authenticationRequired(QAuthenticator *authenticator) |
337 | { |
338 | manager->authenticationRequired(authenticator, reply: reply->q_func(), synchronous, url&: reply->url, urlForLastAuthentication: &reply->urlForLastAuthentication); |
339 | } |
340 | |
341 | void QNetworkAccessBackend::metaDataChanged() |
342 | { |
343 | reply->metaDataChanged(); |
344 | } |
345 | |
346 | void QNetworkAccessBackend::redirectionRequested(const QUrl &target) |
347 | { |
348 | reply->redirectionRequested(target); |
349 | } |
350 | |
351 | void QNetworkAccessBackend::encrypted() |
352 | { |
353 | #ifndef QT_NO_SSL |
354 | reply->encrypted(); |
355 | #endif |
356 | } |
357 | |
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 | */ |
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(name: "_q_networksession" , value: QVariant::fromValue(value: 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(query: QNetworkProxyQuery(url())); |
400 | #endif |
401 | |
402 | // now start the request |
403 | open(); |
404 | return true; |
405 | } |
406 | |
407 | QT_END_NAMESPACE |
408 | |