1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qnetworkaccessdebugpipebackend_p.h"
43 #include "QtCore/qdatastream.h"
44 #include <QCoreApplication>
46 #include "private/qnoncontiguousbytedevice_p.h"
50 #ifdef QT_BUILD_INTERNAL
53 ReadBufferSize = 16384,
54 WriteBufferSize = ReadBufferSize
57 QNetworkAccessBackend *
58 QNetworkAccessDebugPipeBackendFactory::create(QNetworkAccessManager::Operation op,
59 const QNetworkRequest &request) const
61 // is it an operation we know of?
63 case QNetworkAccessManager::GetOperation:
64 case QNetworkAccessManager::PutOperation:
68 // no, we can't handle this operation
72 QUrl url = request.url();
73 if (url.scheme() == QLatin1String("debugpipe"))
74 return new QNetworkAccessDebugPipeBackend;
78 QNetworkAccessDebugPipeBackend::QNetworkAccessDebugPipeBackend()
79 : bareProtocol(false), hasUploadFinished(false), hasDownloadFinished(false),
80 hasEverythingFinished(false), bytesDownloaded(0), bytesUploaded(0)
84 QNetworkAccessDebugPipeBackend::~QNetworkAccessDebugPipeBackend()
86 // this is signals disconnect, not network!
87 socket.disconnect(this); // we're not interested in the signals at this point
90 void QNetworkAccessDebugPipeBackend::open()
92 socket.connectToHost(url().host(), url().port(12345));
93 socket.setReadBufferSize(ReadBufferSize);
95 // socket ready read -> we can push from socket to downstream
96 connect(&socket, SIGNAL(readyRead()), SLOT(socketReadyRead()));
97 connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketError()));
98 connect(&socket, SIGNAL(disconnected()), SLOT(socketDisconnected()));
99 connect(&socket, SIGNAL(connected()), SLOT(socketConnected()));
100 // socket bytes written -> we can push more from upstream to socket
101 connect(&socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64)));
103 bareProtocol = QUrlQuery(url()).queryItemValue(QLatin1String("bare")) == QLatin1String("1");
105 if (operation() == QNetworkAccessManager::PutOperation) {
106 uploadByteDevice = createUploadByteDevice();
107 QObject::connect(uploadByteDevice, SIGNAL(readyRead()), this, SLOT(uploadReadyReadSlot()));
108 QMetaObject::invokeMethod(this, "uploadReadyReadSlot", Qt::QueuedConnection);
112 void QNetworkAccessDebugPipeBackend::socketReadyRead()
114 pushFromSocketToDownstream();
117 void QNetworkAccessDebugPipeBackend::downstreamReadyWrite()
119 pushFromSocketToDownstream();
122 void QNetworkAccessDebugPipeBackend::socketBytesWritten(qint64)
124 pushFromUpstreamToSocket();
127 void QNetworkAccessDebugPipeBackend::uploadReadyReadSlot()
129 pushFromUpstreamToSocket();
132 void QNetworkAccessDebugPipeBackend::pushFromSocketToDownstream()
136 if (socket.state() == QAbstractSocket::ConnectingState) {
141 if (hasDownloadFinished)
144 buffer.resize(ReadBufferSize);
145 qint64 haveRead = socket.read(buffer.data(), ReadBufferSize);
147 if (haveRead == -1) {
148 hasDownloadFinished = true;
149 // this ensures a good last downloadProgress is emitted
150 setHeader(QNetworkRequest::ContentLengthHeader, QVariant());
153 } else if (haveRead == 0) {
156 // have read something
157 buffer.resize(haveRead);
158 bytesDownloaded += haveRead;
160 QByteDataBuffer list;
162 buffer.clear(); // important because of implicit sharing!
163 writeDownstreamData(list);
168 void QNetworkAccessDebugPipeBackend::pushFromUpstreamToSocket()
171 if (operation() == QNetworkAccessManager::PutOperation) {
172 if (hasUploadFinished)
176 if (socket.bytesToWrite() >= WriteBufferSize)
180 const char *readPointer = uploadByteDevice->readPointer(WriteBufferSize, haveRead);
181 if (haveRead == -1) {
183 hasUploadFinished = true;
184 emitReplyUploadProgress(bytesUploaded, bytesUploaded);
187 } else if (haveRead == 0 || readPointer == 0) {
188 // nothing to read right now, we will be called again later
192 haveWritten = socket.write(readPointer, haveRead);
194 if (haveWritten < 0) {
196 QString msg = QCoreApplication::translate("QNetworkAccessDebugPipeBackend", "Write error writing to %1: %2")
197 .arg(url().toString(), socket.errorString());
198 error(QNetworkReply::ProtocolFailure, msg);
202 uploadByteDevice->advanceReadPointer(haveWritten);
203 bytesUploaded += haveWritten;
204 emitReplyUploadProgress(bytesUploaded, -1);
207 //QCoreApplication::processEvents();
214 void QNetworkAccessDebugPipeBackend::possiblyFinish()
216 if (hasEverythingFinished)
218 hasEverythingFinished = true;
220 if ((operation() == QNetworkAccessManager::GetOperation) && hasDownloadFinished) {
223 } else if ((operation() == QNetworkAccessManager::PutOperation) && hasUploadFinished) {
231 void QNetworkAccessDebugPipeBackend::closeDownstreamChannel()
233 qWarning("QNetworkAccessDebugPipeBackend::closeDownstreamChannel() %d",operation());;
234 //if (operation() == QNetworkAccessManager::GetOperation)
235 // socket.disconnectFromHost();
239 void QNetworkAccessDebugPipeBackend::socketError()
241 qWarning("QNetworkAccessDebugPipeBackend::socketError() %d",socket.error());
242 QNetworkReply::NetworkError code;
243 switch (socket.error()) {
244 case QAbstractSocket::RemoteHostClosedError:
245 return; // socketDisconnected will be called
247 case QAbstractSocket::NetworkError:
248 code = QNetworkReply::UnknownNetworkError;
252 code = QNetworkReply::ProtocolFailure;
256 error(code, QNetworkAccessDebugPipeBackend::tr("Socket error on %1: %2")
257 .arg(url().toString(), socket.errorString()));
259 disconnect(&socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
263 void QNetworkAccessDebugPipeBackend::socketDisconnected()
265 pushFromSocketToDownstream();
267 if (socket.bytesToWrite() == 0) {
271 QString msg = QNetworkAccessDebugPipeBackend::tr("Remote host closed the connection prematurely on %1")
272 .arg(url().toString());
273 error(QNetworkReply::RemoteHostClosedError, msg);
278 void QNetworkAccessDebugPipeBackend::socketConnected()