Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qnetworkaccessdebugpipebackend.cpp
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
4
6#include "QtCore/qdatastream.h"
7#include <QCoreApplication>
8#include <QStringList>
9#include <QUrlQuery>
10#include "private/qnoncontiguousbytedevice_p.h"
11
12QT_BEGIN_NAMESPACE
13
14using namespace Qt::StringLiterals;
15
16#ifdef QT_BUILD_INTERNAL
17
18enum {
19 ReadBufferSize = 16384,
20 WriteBufferSize = ReadBufferSize
21};
22
23QStringList QNetworkAccessDebugPipeBackendFactory::supportedSchemes() const
24{
25 return QStringList(QStringLiteral("debugpipe"));
26}
27
28QNetworkAccessBackend *
29QNetworkAccessDebugPipeBackendFactory::create(QNetworkAccessManager::Operation op,
30 const QNetworkRequest &request) const
31{
32 // is it an operation we know of?
33 switch (op) {
34 case QNetworkAccessManager::GetOperation:
35 case QNetworkAccessManager::PutOperation:
36 break;
37
38 default:
39 // no, we can't handle this operation
40 return nullptr;
41 }
42
43 QUrl url = request.url();
44 if (url.scheme() == "debugpipe"_L1)
45 return new QNetworkAccessDebugPipeBackend;
46 return nullptr;
47}
48
49QNetworkAccessDebugPipeBackend::QNetworkAccessDebugPipeBackend()
50 : QNetworkAccessBackend(QNetworkAccessBackend::TargetType::Networked),
51 bareProtocol(false),
52 hasUploadFinished(false),
53 hasDownloadFinished(false),
54 hasEverythingFinished(false),
55 bytesDownloaded(0),
56 bytesUploaded(0)
57{
58}
59
60QNetworkAccessDebugPipeBackend::~QNetworkAccessDebugPipeBackend()
61{
62 // this is signals disconnect, not network!
63 socket.disconnect(this); // we're not interested in the signals at this point
64}
65
66void QNetworkAccessDebugPipeBackend::open()
67{
68 socket.connectToHost(url().host(), url().port(12345));
69 socket.setReadBufferSize(ReadBufferSize);
70
71 // socket ready read -> we can push from socket to downstream
72 connect(&socket, SIGNAL(readyRead()), SLOT(socketReadyRead()));
73 connect(&socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), SLOT(socketError()));
74 connect(&socket, SIGNAL(disconnected()), SLOT(socketDisconnected()));
75 connect(&socket, SIGNAL(connected()), SLOT(socketConnected()));
76 // socket bytes written -> we can push more from upstream to socket
77 connect(&socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64)));
78
79 bareProtocol = QUrlQuery(url()).queryItemValue("bare"_L1) == "1"_L1;
80
81 if (operation() == QNetworkAccessManager::PutOperation) {
82 createUploadByteDevice();
83 QObject::connect(uploadByteDevice(), SIGNAL(readyRead()), this,
84 SLOT(uploadReadyReadSlot()));
85 QMetaObject::invokeMethod(this, "uploadReadyReadSlot", Qt::QueuedConnection);
86 }
87}
88
89void QNetworkAccessDebugPipeBackend::socketReadyRead()
90{
91 readyRead();
92}
93
94qint64 QNetworkAccessDebugPipeBackend::read(char *data, qint64 maxlen)
95{
96 qint64 haveRead = socket.read(data, maxlen);
97
98 if (haveRead == -1) {
99 hasDownloadFinished = true;
100 // this ensures a good last downloadProgress is emitted
101 auto h = headers();
102 h.removeAll(QHttpHeaders::WellKnownHeader::ContentLength);
103 setHeaders(std::move(h));
104 possiblyFinish();
105 return haveRead;
106 }
107
108 bytesDownloaded += haveRead;
109 return haveRead;
110}
111
112qint64 QNetworkAccessDebugPipeBackend::bytesAvailable() const
113{
114 return socket.bytesAvailable();
115}
116
117void QNetworkAccessDebugPipeBackend::socketBytesWritten(qint64)
118{
119 pushFromUpstreamToSocket();
120}
121
122void QNetworkAccessDebugPipeBackend::uploadReadyReadSlot()
123{
124 pushFromUpstreamToSocket();
125}
126
127void QNetworkAccessDebugPipeBackend::pushFromUpstreamToSocket()
128{
129 // FIXME
130 if (operation() == QNetworkAccessManager::PutOperation) {
131 if (hasUploadFinished)
132 return;
133
134 forever {
135 if (socket.bytesToWrite() >= WriteBufferSize)
136 return;
137
138 QByteArray data(WriteBufferSize, Qt::Uninitialized);
139 qint64 haveRead = uploadByteDevice()->peek(data.data(), data.size());
140 if (haveRead == -1) {
141 // EOF
142 hasUploadFinished = true;
143 possiblyFinish();
144 break;
145 } else if (haveRead == 0) {
146 // nothing to read right now, we will be called again later
147 break;
148 } else {
149 qint64 haveWritten;
150 data.truncate(haveRead);
151 haveWritten = socket.write(std::move(data));
152
153 if (haveWritten < 0) {
154 // write error!
155 QString msg = QCoreApplication::translate("QNetworkAccessDebugPipeBackend", "Write error writing to %1: %2")
156 .arg(url().toString(), socket.errorString());
157 error(QNetworkReply::ProtocolFailure, msg);
158 finished();
159 return;
160 } else {
161 uploadByteDevice()->skip(haveWritten);
162 bytesUploaded += haveWritten;
163 }
164
165 //QCoreApplication::processEvents();
166 }
167 }
168 }
169}
170
171void QNetworkAccessDebugPipeBackend::possiblyFinish()
172{
173 if (hasEverythingFinished)
174 return;
175 hasEverythingFinished = true;
176
177 if ((operation() == QNetworkAccessManager::GetOperation) && hasDownloadFinished) {
178 socket.close();
179 finished();
180 } else if ((operation() == QNetworkAccessManager::PutOperation) && hasUploadFinished) {
181 socket.close();
182 finished();
183 }
184
185
186}
187
188void QNetworkAccessDebugPipeBackend::close()
189{
190 qWarning("QNetworkAccessDebugPipeBackend::closeDownstreamChannel() %d",operation());
191 //if (operation() == QNetworkAccessManager::GetOperation)
192 // socket.disconnectFromHost();
193}
194
195
196void QNetworkAccessDebugPipeBackend::socketError()
197{
198 qWarning("QNetworkAccessDebugPipeBackend::socketError() %d",socket.error());
199 QNetworkReply::NetworkError code;
200 switch (socket.error()) {
201 case QAbstractSocket::RemoteHostClosedError:
202 return; // socketDisconnected will be called
203
204 case QAbstractSocket::NetworkError:
205 code = QNetworkReply::UnknownNetworkError;
206 break;
207
208 default:
209 code = QNetworkReply::ProtocolFailure;
210 break;
211 }
212
213 error(code, QNetworkAccessDebugPipeBackend::tr("Socket error on %1: %2")
214 .arg(url().toString(), socket.errorString()));
215 finished();
216 disconnect(&socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
217
218}
219
220void QNetworkAccessDebugPipeBackend::socketDisconnected()
221{
222 if (socket.bytesToWrite() == 0) {
223 // normal close
224 } else {
225 readyRead(); // @todo this is odd
226 // abnormal close
227 QString msg = QNetworkAccessDebugPipeBackend::tr("Remote host closed the connection prematurely on %1")
228 .arg(url().toString());
229 error(QNetworkReply::RemoteHostClosedError, msg);
230 finished();
231 }
232}
233
234void QNetworkAccessDebugPipeBackend::socketConnected()
235{
236}
237
238
239#endif
240
241QT_END_NAMESPACE
242
243#include "moc_qnetworkaccessdebugpipebackend_p.cpp"