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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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