Qt 4.8
qnetworkaccessdebugpipebackend.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
43 #include "QtCore/qdatastream.h"
44 #include <QCoreApplication>
45 #include "private/qnoncontiguousbytedevice_p.h"
46 
48 
49 #ifdef QT_BUILD_INTERNAL
50 
51 enum {
52  ReadBufferSize = 16384,
53  WriteBufferSize = ReadBufferSize
54 };
55 
58  const QNetworkRequest &request) const
59 {
60  // is it an operation we know of?
61  switch (op) {
64  break;
65 
66  default:
67  // no, we can't handle this operation
68  return 0;
69  }
70 
71  QUrl url = request.url();
72  if (url.scheme() == QLatin1String("debugpipe"))
73  return new QNetworkAccessDebugPipeBackend;
74  return 0;
75 }
76 
77 QNetworkAccessDebugPipeBackend::QNetworkAccessDebugPipeBackend()
78  : bareProtocol(false), hasUploadFinished(false), hasDownloadFinished(false),
79  hasEverythingFinished(false), bytesDownloaded(0), bytesUploaded(0)
80 {
81 }
82 
83 QNetworkAccessDebugPipeBackend::~QNetworkAccessDebugPipeBackend()
84 {
85  // this is signals disconnect, not network!
86  socket.disconnect(this); // we're not interested in the signals at this point
87 }
88 
90 {
91  socket.connectToHost(url().host(), url().port(12345));
92  socket.setReadBufferSize(ReadBufferSize);
93 
94  // socket ready read -> we can push from socket to downstream
95  connect(&socket, SIGNAL(readyRead()), SLOT(socketReadyRead()));
96  connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketError()));
97  connect(&socket, SIGNAL(disconnected()), SLOT(socketDisconnected()));
98  connect(&socket, SIGNAL(connected()), SLOT(socketConnected()));
99  // socket bytes written -> we can push more from upstream to socket
100  connect(&socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64)));
101 
102  bareProtocol = url().queryItemValue(QLatin1String("bare")) == QLatin1String("1");
103 
106  QObject::connect(uploadByteDevice, SIGNAL(readyRead()), this, SLOT(uploadReadyReadSlot()));
107  QMetaObject::invokeMethod(this, "uploadReadyReadSlot", Qt::QueuedConnection);
108  }
109 }
110 
111 void QNetworkAccessDebugPipeBackend::socketReadyRead()
112 {
113  pushFromSocketToDownstream();
114 }
115 
116 void QNetworkAccessDebugPipeBackend::downstreamReadyWrite()
117 {
118  pushFromSocketToDownstream();
119 }
120 
121 void QNetworkAccessDebugPipeBackend::socketBytesWritten(qint64)
122 {
123  pushFromUpstreamToSocket();
124 }
125 
126 void QNetworkAccessDebugPipeBackend::uploadReadyReadSlot()
127 {
128  pushFromUpstreamToSocket();
129 }
130 
131 void QNetworkAccessDebugPipeBackend::pushFromSocketToDownstream()
132 {
133  QByteArray buffer;
134 
135  if (socket.state() == QAbstractSocket::ConnectingState) {
136  return;
137  }
138 
139  forever {
140  if (hasDownloadFinished)
141  return;
142 
143  buffer.resize(ReadBufferSize);
144  qint64 haveRead = socket.read(buffer.data(), ReadBufferSize);
145 
146  if (haveRead == -1) {
147  hasDownloadFinished = true;
148  // this ensures a good last downloadProgress is emitted
150  possiblyFinish();
151  break;
152  } else if (haveRead == 0) {
153  break;
154  } else {
155  // have read something
156  buffer.resize(haveRead);
157  bytesDownloaded += haveRead;
158 
159  QByteDataBuffer list;
160  list.append(buffer);
161  buffer.clear(); // important because of implicit sharing!
162  writeDownstreamData(list);
163  }
164  }
165 }
166 
167 void QNetworkAccessDebugPipeBackend::pushFromUpstreamToSocket()
168 {
169  // FIXME
171  if (hasUploadFinished)
172  return;
173 
174  forever {
175  if (socket.bytesToWrite() >= WriteBufferSize)
176  return;
177 
178  qint64 haveRead;
179  const char *readPointer = uploadByteDevice->readPointer(WriteBufferSize, haveRead);
180  if (haveRead == -1) {
181  // EOF
182  hasUploadFinished = true;
183  emitReplyUploadProgress(bytesUploaded, bytesUploaded);
184  possiblyFinish();
185  break;
186  } else if (haveRead == 0 || readPointer == 0) {
187  // nothing to read right now, we will be called again later
188  break;
189  } else {
190  qint64 haveWritten;
191  haveWritten = socket.write(readPointer, haveRead);
192 
193  if (haveWritten < 0) {
194  // write error!
195  QString msg = QCoreApplication::translate("QNetworkAccessDebugPipeBackend", "Write error writing to %1: %2")
196  .arg(url().toString(), socket.errorString());
198  finished();
199  return;
200  } else {
201  uploadByteDevice->advanceReadPointer(haveWritten);
202  bytesUploaded += haveWritten;
203  emitReplyUploadProgress(bytesUploaded, -1);
204  }
205 
206  //QCoreApplication::processEvents();
207 
208  }
209  }
210  }
211 }
212 
213 void QNetworkAccessDebugPipeBackend::possiblyFinish()
214 {
215  if (hasEverythingFinished)
216  return;
217  hasEverythingFinished = true;
218 
219  if ((operation() == QNetworkAccessManager::GetOperation) && hasDownloadFinished) {
220  socket.close();
221  finished();
222  } else if ((operation() == QNetworkAccessManager::PutOperation) && hasUploadFinished) {
223  socket.close();
224  finished();
225  }
226 
227 
228 }
229 
230 void QNetworkAccessDebugPipeBackend::closeDownstreamChannel()
231 {
232  qWarning("QNetworkAccessDebugPipeBackend::closeDownstreamChannel() %d",operation());;
233  //if (operation() == QNetworkAccessManager::GetOperation)
234  // socket.disconnectFromHost();
235 }
236 
237 
238 void QNetworkAccessDebugPipeBackend::socketError()
239 {
240  qWarning("QNetworkAccessDebugPipeBackend::socketError() %d",socket.error());
242  switch (socket.error()) {
244  return; // socketDisconnected will be called
245 
248  break;
249 
250  default:
252  break;
253  }
254 
255  error(code, QNetworkAccessDebugPipeBackend::tr("Socket error on %1: %2")
256  .arg(url().toString(), socket.errorString()));
257  finished();
258  disconnect(&socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
259 
260 }
261 
262 void QNetworkAccessDebugPipeBackend::socketDisconnected()
263 {
264  pushFromSocketToDownstream();
265 
266  if (socket.bytesToWrite() == 0) {
267  // normal close
268  } else {
269  // abnormal close
270  QString msg = QNetworkAccessDebugPipeBackend::tr("Remote host closed the connection prematurely on %1")
271  .arg(url().toString());
273  finished();
274  }
275 }
276 
277 void QNetworkAccessDebugPipeBackend::socketConnected()
278 {
279 }
280 
281 
282 #endif
283 
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
char * data()
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:429
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
static Expression::Ptr create(Expression *const expr, const YYLTYPE &sourceLocator, const ParserContext *const parseInfo)
#define SLOT(a)
Definition: qobjectdefs.h:226
NetworkError
Indicates all possible error conditions found during the processing of the request.
Definition: qnetworkreply.h:70
Operation
Indicates the operation this reply is processing.
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
void append(QByteDataBuffer &other)
Definition: qbytedata_p.h:77
The QUrl class provides a convenient interface for working with URLs.
Definition: qurl.h:61
The QString class provides a Unicode character string.
Definition: qstring.h:83
QUrl url() const
Returns the URL this network request is referring to.
static QString translate(const char *context, const char *key, const char *disambiguation=0, Encoding encoding=CodecForTr)
virtual const char * readPointer(qint64 maximumLength, qint64 &len)=0
Return a byte pointer for at most maximumLength bytes of that device.
#define SIGNAL(a)
Definition: qobjectdefs.h:227
static QString toString(Register *reg, int type, bool *ok=0)
QNonContiguousByteDevice * createUploadByteDevice()
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
static QIntfbScreen * connected
void emitReplyUploadProgress(qint64 bytesSent, qint64 bytesTotal)
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Definition: qobject.cpp:2580
SocketError
This enum describes the socket errors that can occur.
Q_CORE_EXPORT void qWarning(const char *,...)
void setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value)
__int64 qint64
Definition: qglobal.h:942
QNetworkAccessManager::Operation operation() const
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
Disconnects signal in object sender from method in object receiver.
Definition: qobject.cpp:2895
QSharedPointer< QNonContiguousByteDevice > uploadByteDevice
QString scheme() const
Returns the scheme of the URL.
Definition: qurl.cpp:4550
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
void error(QNetworkReply::NetworkError code, const QString &errorString)
virtual bool advanceReadPointer(qint64 amount)=0
The old readPointer is invalid after this call.
void resize(int size)
Sets the size of the byte array to size bytes.
QString queryItemValue(const QString &key) const
Returns the first query string value whose key is equal to key from the URL.
Definition: qurl.cpp:5422
void writeDownstreamData(QByteDataBuffer &list)
The QNetworkRequest class holds a request to be sent with QNetworkAccessManager.
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(0), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
Invokes the member (a signal or a slot name) on the object obj.
void clear()
Clears the contents of the byte array and makes it empty.
int open(const char *, int,...)
#define forever
This macro is provided for convenience for writing infinite loops.
Definition: qglobal.h:2452