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#ifndef QHTTPTHREADDELEGATE_H
41#define QHTTPTHREADDELEGATE_H
42
43
44//
45// W A R N I N G
46// -------------
47//
48// This file is not part of the Qt API. It exists for the convenience
49// of the Network Access API. This header file may change from
50// version to version without notice, or even be removed.
51//
52// We mean it.
53//
54
55#include <QtNetwork/private/qtnetworkglobal_p.h>
56#include <QObject>
57#include <QThreadStorage>
58#include <QNetworkProxy>
59#include <QSslConfiguration>
60#include <QSslError>
61#include <QList>
62#include <QNetworkReply>
63#include "qhttpnetworkrequest_p.h"
64#include "qhttpnetworkconnection_p.h"
65#include "qhttp2configuration.h"
66#include <QSharedPointer>
67#include <QScopedPointer>
68#include "private/qnoncontiguousbytedevice_p.h"
69#include "qnetworkaccessauthenticationmanager_p.h"
70#include <QtNetwork/private/http2protocol_p.h>
71
72QT_REQUIRE_CONFIG(http);
73
74QT_BEGIN_NAMESPACE
75
76class QAuthenticator;
77class QHttpNetworkReply;
78class QEventLoop;
79class QNetworkAccessCache;
80class QNetworkAccessCachedHttpConnection;
81
82class QHttpThreadDelegate : public QObject
83{
84 Q_OBJECT
85public:
86 explicit QHttpThreadDelegate(QObject *parent = nullptr);
87
88 ~QHttpThreadDelegate();
89
90 // incoming
91 bool ssl;
92#ifndef QT_NO_SSL
93 QScopedPointer<QSslConfiguration> incomingSslConfiguration;
94#endif
95 QHttpNetworkRequest httpRequest;
96 qint64 downloadBufferMaximumSize;
97 qint64 readBufferMaxSize;
98 qint64 bytesEmitted;
99 // From backend, modified by us for signal compression
100 QSharedPointer<QAtomicInt> pendingDownloadData;
101 QSharedPointer<QAtomicInt> pendingDownloadProgress;
102#ifndef QT_NO_NETWORKPROXY
103 QNetworkProxy cacheProxy;
104 QNetworkProxy transparentProxy;
105#endif
106 QSharedPointer<QNetworkAccessAuthenticationManager> authenticationManager;
107 bool synchronous;
108
109 // outgoing, Retrieved in the synchronous HTTP case
110 QByteArray synchronousDownloadData;
111 QList<QPair<QByteArray,QByteArray> > incomingHeaders;
112 int incomingStatusCode;
113 QString incomingReasonPhrase;
114 bool isPipeliningUsed;
115 bool isSpdyUsed;
116 qint64 incomingContentLength;
117 qint64 removedContentLength;
118 QNetworkReply::NetworkError incomingErrorCode;
119 QString incomingErrorDetail;
120 QHttp2Configuration http2Parameters;
121#ifndef QT_NO_BEARERMANAGEMENT // ### Qt6: Remove section
122 QSharedPointer<QNetworkSession> networkSession;
123#endif
124
125protected:
126 // The zerocopy download buffer, if used:
127 QSharedPointer<char> downloadBuffer;
128 // The QHttpNetworkConnection that is used
129 QNetworkAccessCachedHttpConnection *httpConnection;
130 QByteArray cacheKey;
131 QHttpNetworkReply *httpReply;
132
133 // Used for implementing the synchronous HTTP, see startRequestSynchronously()
134 QEventLoop *synchronousRequestLoop;
135
136signals:
137 void authenticationRequired(const QHttpNetworkRequest &request, QAuthenticator *);
138#ifndef QT_NO_NETWORKPROXY
139 void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *);
140#endif
141#ifndef QT_NO_SSL
142 void encrypted();
143 void sslErrors(const QList<QSslError> &, bool *, QList<QSslError> *);
144 void sslConfigurationChanged(const QSslConfiguration &);
145 void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *);
146#endif
147 void downloadMetaData(const QList<QPair<QByteArray,QByteArray> > &, int, const QString &, bool,
148 QSharedPointer<char>, qint64, qint64, bool);
149 void downloadProgress(qint64, qint64);
150 void downloadData(const QByteArray &);
151 void error(QNetworkReply::NetworkError, const QString &);
152 void downloadFinished();
153 void redirected(const QUrl &url, int httpStatus, int maxRedirectsRemainig);
154
155public slots:
156 // This are called via QueuedConnection from user thread
157 void startRequest();
158 void abortRequest();
159 void readBufferSizeChanged(qint64 size);
160 void readBufferFreed(qint64 size);
161
162 // This is called with a BlockingQueuedConnection from user thread
163 void startRequestSynchronously();
164protected slots:
165 // From QHttp*
166 void readyReadSlot();
167 void finishedSlot();
168 void finishedWithErrorSlot(QNetworkReply::NetworkError errorCode, const QString &detail = QString());
169 void synchronousFinishedSlot();
170 void synchronousFinishedWithErrorSlot(QNetworkReply::NetworkError errorCode, const QString &detail = QString());
171 void headerChangedSlot();
172 void synchronousHeaderChangedSlot();
173 void dataReadProgressSlot(qint64 done, qint64 total);
174 void cacheCredentialsSlot(const QHttpNetworkRequest &request, QAuthenticator *authenticator);
175#ifndef QT_NO_SSL
176 void encryptedSlot();
177 void sslErrorsSlot(const QList<QSslError> &errors);
178 void preSharedKeyAuthenticationRequiredSlot(QSslPreSharedKeyAuthenticator *authenticator);
179#endif
180
181 void synchronousAuthenticationRequiredSlot(const QHttpNetworkRequest &request, QAuthenticator *);
182#ifndef QT_NO_NETWORKPROXY
183 void synchronousProxyAuthenticationRequiredSlot(const QNetworkProxy &, QAuthenticator *);
184#endif
185
186protected:
187 // Cache for all the QHttpNetworkConnection objects.
188 // This is per thread.
189 static QThreadStorage<QNetworkAccessCache *> connections;
190
191};
192
193// This QNonContiguousByteDevice is connected to the QNetworkAccessHttpBackend
194// and represents the PUT/POST data.
195class QNonContiguousByteDeviceThreadForwardImpl : public QNonContiguousByteDevice
196{
197 Q_OBJECT
198protected:
199 bool wantDataPending;
200 qint64 m_amount;
201 char *m_data;
202 QByteArray m_dataArray;
203 bool m_atEnd;
204 qint64 m_size;
205 qint64 m_pos; // to match calls of haveDataSlot with the expected position
206public:
207 QNonContiguousByteDeviceThreadForwardImpl(bool aE, qint64 s)
208 : QNonContiguousByteDevice(),
209 wantDataPending(false),
210 m_amount(0),
211 m_data(nullptr),
212 m_atEnd(aE),
213 m_size(s),
214 m_pos(0)
215 {
216 }
217
218 ~QNonContiguousByteDeviceThreadForwardImpl()
219 {
220 }
221
222 qint64 pos() const override
223 {
224 return m_pos;
225 }
226
227 const char* readPointer(qint64 maximumLength, qint64 &len) override
228 {
229 if (m_amount > 0) {
230 len = m_amount;
231 return m_data;
232 }
233
234 if (m_atEnd) {
235 len = -1;
236 } else if (!wantDataPending) {
237 len = 0;
238 wantDataPending = true;
239 emit wantData(maximumLength);
240 } else {
241 // Do nothing, we already sent a wantData signal and wait for results
242 len = 0;
243 }
244 return nullptr;
245 }
246
247 bool advanceReadPointer(qint64 a) override
248 {
249 if (m_data == nullptr)
250 return false;
251
252 m_amount -= a;
253 m_data += a;
254 m_pos += a;
255
256 // To main thread to inform about our state. The m_pos will be sent as a sanity check.
257 emit processedData(pos: m_pos, amount: a);
258
259 return true;
260 }
261
262 bool atEnd() const override
263 {
264 if (m_amount > 0)
265 return false;
266 else
267 return m_atEnd;
268 }
269
270 bool reset() override
271 {
272 m_amount = 0;
273 m_data = nullptr;
274 m_dataArray.clear();
275
276 if (wantDataPending) {
277 // had requested the user thread to send some data (only 1 in-flight at any moment)
278 wantDataPending = false;
279 }
280
281 // Communicate as BlockingQueuedConnection
282 bool b = false;
283 emit resetData(b: &b);
284 if (b) {
285 // the reset succeeded, we're at pos 0 again
286 m_pos = 0;
287 // the HTTP code will anyway abort the request if !b.
288 }
289 return b;
290 }
291
292 qint64 size() const override
293 {
294 return m_size;
295 }
296
297public slots:
298 // From user thread:
299 void haveDataSlot(qint64 pos, const QByteArray &dataArray, bool dataAtEnd, qint64 dataSize)
300 {
301 if (pos != m_pos) {
302 // Sometimes when re-sending a request in the qhttpnetwork* layer there is a pending haveData from the
303 // user thread on the way to us. We need to ignore it since it is the data for the wrong(later) chunk.
304 return;
305 }
306 wantDataPending = false;
307
308 m_dataArray = dataArray;
309 m_data = const_cast<char*>(m_dataArray.constData());
310 m_amount = dataArray.size();
311
312 m_atEnd = dataAtEnd;
313 m_size = dataSize;
314
315 // This will tell the HTTP code (QHttpNetworkConnectionChannel) that we have data available now
316 emit readyRead();
317 }
318
319signals:
320 // void readyRead(); in parent class
321 // void readProgress(qint64 current, qint64 total); happens in the main thread with the real bytedevice
322
323 // to main thread:
324 void wantData(qint64);
325 void processedData(qint64 pos, qint64 amount);
326 void resetData(bool *b);
327};
328
329QT_END_NAMESPACE
330
331#endif // QHTTPTHREADDELEGATE_H
332

source code of qtbase/src/network/access/qhttpthreaddelegate_p.h