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
37QT_REQUIRE_CONFIG(http);
38
39QT_BEGIN_NAMESPACE
40
41class QAuthenticator;
42class QHttpNetworkReply;
43class QEventLoop;
44class QNetworkAccessCache;
45class QNetworkAccessCachedHttpConnection;
46
47class QHttpThreadDelegate : public QObject
48{
49 Q_OBJECT
50public:
51 explicit QHttpThreadDelegate(QObject *parent = nullptr);
52
53 ~QHttpThreadDelegate();
54
55 // incoming
56 bool ssl;
57#ifndef QT_NO_SSL
58 QScopedPointer<QSslConfiguration> incomingSslConfiguration;
59#endif
60 QHttpNetworkRequest httpRequest;
61 qint64 downloadBufferMaximumSize;
62 qint64 readBufferMaxSize;
63 qint64 bytesEmitted;
64 // From backend, modified by us for signal compression
65 std::shared_ptr<QAtomicInt> pendingDownloadData;
66 std::shared_ptr<QAtomicInt> pendingDownloadProgress;
67#ifndef QT_NO_NETWORKPROXY
68 QNetworkProxy cacheProxy;
69 QNetworkProxy transparentProxy;
70#endif
71 std::shared_ptr<QNetworkAccessAuthenticationManager> authenticationManager;
72 bool synchronous;
73 qint64 connectionCacheExpiryTimeoutSeconds;
74
75 // outgoing, Retrieved in the synchronous HTTP case
76 QByteArray synchronousDownloadData;
77 QList<QPair<QByteArray,QByteArray> > incomingHeaders;
78 int incomingStatusCode;
79 QString incomingReasonPhrase;
80 bool isPipeliningUsed;
81 bool isHttp2Used;
82 qint64 incomingContentLength;
83 qint64 removedContentLength;
84 QNetworkReply::NetworkError incomingErrorCode;
85 QString incomingErrorDetail;
86 QHttp1Configuration http1Parameters;
87 QHttp2Configuration http2Parameters;
88
89 bool isCompressed;
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 QList<QPair<QByteArray,QByteArray> > &, 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;
168 qint64 m_amount;
169 char *m_data;
170 QByteArray m_dataArray;
171 bool m_atEnd;
172 qint64 m_size;
173 qint64 m_pos; // to match calls of haveDataSlot with the expected position
174public:
175 QNonContiguousByteDeviceThreadForwardImpl(bool aE, qint64 s)
176 : QNonContiguousByteDevice(),
177 wantDataPending(false),
178 m_amount(0),
179 m_data(nullptr),
180 m_atEnd(aE),
181 m_size(s),
182 m_pos(0)
183 {
184 }
185
186 ~QNonContiguousByteDeviceThreadForwardImpl()
187 {
188 }
189
190 qint64 pos() const override
191 {
192 return m_pos;
193 }
194
195 const char* readPointer(qint64 maximumLength, qint64 &len) override
196 {
197 if (m_amount > 0) {
198 len = m_amount;
199 return m_data;
200 }
201
202 if (m_atEnd) {
203 len = -1;
204 } else if (!wantDataPending) {
205 len = 0;
206 wantDataPending = true;
207 emit wantData(maximumLength);
208 } else {
209 // Do nothing, we already sent a wantData signal and wait for results
210 len = 0;
211 }
212 return nullptr;
213 }
214
215 bool advanceReadPointer(qint64 a) override
216 {
217 if (m_data == nullptr)
218 return false;
219
220 m_amount -= a;
221 m_data += a;
222 m_pos += a;
223
224 // To main thread to inform about our state. The m_pos will be sent as a sanity check.
225 emit processedData(pos: m_pos, amount: a);
226
227 return true;
228 }
229
230 bool atEnd() const override
231 {
232 if (m_amount > 0)
233 return false;
234 else
235 return m_atEnd;
236 }
237
238 bool reset() override
239 {
240 m_amount = 0;
241 m_data = nullptr;
242 m_dataArray.clear();
243
244 if (wantDataPending) {
245 // had requested the user thread to send some data (only 1 in-flight at any moment)
246 wantDataPending = false;
247 }
248
249 // Communicate as BlockingQueuedConnection
250 bool b = false;
251 emit resetData(b: &b);
252 if (b) {
253 // the reset succeeded, we're at pos 0 again
254 m_pos = 0;
255 // the HTTP code will anyway abort the request if !b.
256 }
257 return b;
258 }
259
260 qint64 size() const override
261 {
262 return m_size;
263 }
264
265public slots:
266 // From user thread:
267 void haveDataSlot(qint64 pos, const QByteArray &dataArray, bool dataAtEnd, qint64 dataSize)
268 {
269 if (pos != m_pos) {
270 // Sometimes when re-sending a request in the qhttpnetwork* layer there is a pending haveData from the
271 // user thread on the way to us. We need to ignore it since it is the data for the wrong(later) chunk.
272 return;
273 }
274 wantDataPending = false;
275
276 m_dataArray = dataArray;
277 m_data = const_cast<char*>(m_dataArray.constData());
278 m_amount = dataArray.size();
279
280 m_atEnd = dataAtEnd;
281 m_size = dataSize;
282
283 // This will tell the HTTP code (QHttpNetworkConnectionChannel) that we have data available now
284 emit readyRead();
285 }
286
287signals:
288 // void readyRead(); in parent class
289 // void readProgress(qint64 current, qint64 total); happens in the main thread with the real bytedevice
290
291 // to main thread:
292 void wantData(qint64);
293 void processedData(qint64 pos, qint64 amount);
294 void resetData(bool *b);
295};
296
297QT_END_NAMESPACE
298
299#endif // QHTTPTHREADDELEGATE_H
300

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