choke uploadProgress signals
[profile/ivi/qtbase.git] / src / network / access / qnetworkaccessdebugpipebackend.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qnetworkaccessdebugpipebackend_p.h"
43 #include "QtCore/qdatastream.h"
44 #include <QCoreApplication>
45 #include <QUrlQuery>
46 #include "private/qnoncontiguousbytedevice_p.h"
47
48 QT_BEGIN_NAMESPACE
49
50 #ifdef QT_BUILD_INTERNAL
51
52 enum {
53     ReadBufferSize = 16384,
54     WriteBufferSize = ReadBufferSize
55 };
56
57 QNetworkAccessBackend *
58 QNetworkAccessDebugPipeBackendFactory::create(QNetworkAccessManager::Operation op,
59                                               const QNetworkRequest &request) const
60 {
61     // is it an operation we know of?
62     switch (op) {
63     case QNetworkAccessManager::GetOperation:
64     case QNetworkAccessManager::PutOperation:
65         break;
66
67     default:
68         // no, we can't handle this operation
69         return 0;
70     }
71
72     QUrl url = request.url();
73     if (url.scheme() == QLatin1String("debugpipe"))
74         return new QNetworkAccessDebugPipeBackend;
75     return 0;
76 }
77
78 QNetworkAccessDebugPipeBackend::QNetworkAccessDebugPipeBackend()
79     : bareProtocol(false), hasUploadFinished(false), hasDownloadFinished(false),
80     hasEverythingFinished(false), bytesDownloaded(0), bytesUploaded(0)
81 {
82 }
83
84 QNetworkAccessDebugPipeBackend::~QNetworkAccessDebugPipeBackend()
85 {
86     // this is signals disconnect, not network!
87     socket.disconnect(this);    // we're not interested in the signals at this point
88 }
89
90 void QNetworkAccessDebugPipeBackend::open()
91 {
92     socket.connectToHost(url().host(), url().port(12345));
93     socket.setReadBufferSize(ReadBufferSize);
94
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)));
102
103     bareProtocol = QUrlQuery(url()).queryItemValue(QLatin1String("bare")) == QLatin1String("1");
104
105     if (operation() == QNetworkAccessManager::PutOperation) {
106         uploadByteDevice = createUploadByteDevice();
107         QObject::connect(uploadByteDevice, SIGNAL(readyRead()), this, SLOT(uploadReadyReadSlot()));
108         QMetaObject::invokeMethod(this, "uploadReadyReadSlot", Qt::QueuedConnection);
109     }
110 }
111
112 void QNetworkAccessDebugPipeBackend::socketReadyRead()
113 {
114     pushFromSocketToDownstream();
115 }
116
117 void QNetworkAccessDebugPipeBackend::downstreamReadyWrite()
118 {
119     pushFromSocketToDownstream();
120 }
121
122 void QNetworkAccessDebugPipeBackend::socketBytesWritten(qint64)
123 {
124     pushFromUpstreamToSocket();
125 }
126
127 void QNetworkAccessDebugPipeBackend::uploadReadyReadSlot()
128 {
129     pushFromUpstreamToSocket();
130 }
131
132 void QNetworkAccessDebugPipeBackend::pushFromSocketToDownstream()
133 {
134     QByteArray buffer;
135
136     if (socket.state() == QAbstractSocket::ConnectingState) {
137         return;
138     }
139
140     forever {
141         if (hasDownloadFinished)
142             return;
143
144         buffer.resize(ReadBufferSize);
145         qint64 haveRead = socket.read(buffer.data(), ReadBufferSize);
146         
147         if (haveRead == -1) {
148             hasDownloadFinished = true;
149             // this ensures a good last downloadProgress is emitted
150             setHeader(QNetworkRequest::ContentLengthHeader, QVariant());
151             possiblyFinish();
152             break;
153         } else if (haveRead == 0) {
154             break;
155         } else {
156             // have read something
157             buffer.resize(haveRead);
158             bytesDownloaded += haveRead;
159
160             QByteDataBuffer list;
161             list.append(buffer);
162             buffer.clear(); // important because of implicit sharing!
163             writeDownstreamData(list);
164         }
165     }
166 }
167
168 void QNetworkAccessDebugPipeBackend::pushFromUpstreamToSocket()
169 {
170     // FIXME
171     if (operation() == QNetworkAccessManager::PutOperation) {
172         if (hasUploadFinished)
173             return;
174
175         forever {
176             if (socket.bytesToWrite() >= WriteBufferSize)
177                 return;
178
179             qint64 haveRead;
180             const char *readPointer = uploadByteDevice->readPointer(WriteBufferSize, haveRead);
181             if (haveRead == -1) {
182                 // EOF
183                 hasUploadFinished = true;
184                 emitReplyUploadProgress(bytesUploaded, bytesUploaded);
185                 possiblyFinish();
186                 break;
187             } else if (haveRead == 0 || readPointer == 0) {
188                 // nothing to read right now, we will be called again later
189                 break;
190             } else {
191                 qint64 haveWritten;
192                 haveWritten = socket.write(readPointer, haveRead);
193
194                 if (haveWritten < 0) {
195                     // write error!
196                     QString msg = QCoreApplication::translate("QNetworkAccessDebugPipeBackend", "Write error writing to %1: %2")
197                                   .arg(url().toString(), socket.errorString());
198                     error(QNetworkReply::ProtocolFailure, msg);
199                     finished();
200                     return;
201                 } else {
202                     uploadByteDevice->advanceReadPointer(haveWritten);
203                     bytesUploaded += haveWritten;
204                     emitReplyUploadProgress(bytesUploaded, -1);
205                 }
206
207                 //QCoreApplication::processEvents();
208
209             }
210         }
211     }
212 }
213
214 void QNetworkAccessDebugPipeBackend::possiblyFinish()
215 {
216     if (hasEverythingFinished)
217         return;
218     hasEverythingFinished = true;
219
220     if ((operation() == QNetworkAccessManager::GetOperation) && hasDownloadFinished) {
221         socket.close();
222         finished();
223     } else if ((operation() == QNetworkAccessManager::PutOperation) && hasUploadFinished) {
224         socket.close();
225         finished();
226     }
227
228
229 }
230
231 void QNetworkAccessDebugPipeBackend::closeDownstreamChannel()
232 {
233     qWarning("QNetworkAccessDebugPipeBackend::closeDownstreamChannel() %d",operation());;
234     //if (operation() == QNetworkAccessManager::GetOperation)
235     //    socket.disconnectFromHost();
236 }
237
238
239 void QNetworkAccessDebugPipeBackend::socketError()
240 {
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
246
247     case QAbstractSocket::NetworkError:
248         code = QNetworkReply::UnknownNetworkError;
249         break;
250
251     default:
252         code = QNetworkReply::ProtocolFailure;
253         break;
254     }
255
256     error(code, QNetworkAccessDebugPipeBackend::tr("Socket error on %1: %2")
257           .arg(url().toString(), socket.errorString()));
258     finished();
259     disconnect(&socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
260
261 }
262
263 void QNetworkAccessDebugPipeBackend::socketDisconnected()
264 {
265     pushFromSocketToDownstream();
266
267     if (socket.bytesToWrite() == 0) {
268         // normal close
269     } else {
270         // abnormal close
271         QString msg = QNetworkAccessDebugPipeBackend::tr("Remote host closed the connection prematurely on %1")
272                              .arg(url().toString());
273         error(QNetworkReply::RemoteHostClosedError, msg);
274         finished();
275     }
276 }
277
278 void QNetworkAccessDebugPipeBackend::socketConnected()
279 {
280 }
281
282
283 #endif
284
285 QT_END_NAMESPACE