diff -r 000000000000 -r 1918ee327afb src/network/access/qnetworkaccessdebugpipebackend.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/network/access/qnetworkaccessdebugpipebackend.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,290 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnetworkaccessdebugpipebackend_p.h" +#include "QtCore/qdatastream.h" +#include +#include "private/qnoncontiguousbytedevice_p.h" + +QT_BEGIN_NAMESPACE + +#ifdef QT_BUILD_INTERNAL + +enum { + ReadBufferSize = 16384, + WriteBufferSize = ReadBufferSize +}; + +QNetworkAccessBackend * +QNetworkAccessDebugPipeBackendFactory::create(QNetworkAccessManager::Operation op, + const QNetworkRequest &request) const +{ + // is it an operation we know of? + switch (op) { + case QNetworkAccessManager::GetOperation: + case QNetworkAccessManager::PutOperation: + break; + + default: + // no, we can't handle this operation + return 0; + } + + QUrl url = request.url(); + if (url.scheme() == QLatin1String("debugpipe")) + return new QNetworkAccessDebugPipeBackend; + return 0; +} + +QNetworkAccessDebugPipeBackend::QNetworkAccessDebugPipeBackend() + : bareProtocol(false), hasUploadFinished(false), hasDownloadFinished(false), + hasEverythingFinished(false), bytesDownloaded(0), bytesUploaded(0) +{ +} + +QNetworkAccessDebugPipeBackend::~QNetworkAccessDebugPipeBackend() +{ + // this is signals disconnect, not network! + socket.disconnect(this); // we're not interested in the signals at this point +} + +void QNetworkAccessDebugPipeBackend::open() +{ + socket.connectToHost(url().host(), url().port(12345)); + socket.setReadBufferSize(ReadBufferSize); + + // socket ready read -> we can push from socket to downstream + connect(&socket, SIGNAL(readyRead()), SLOT(socketReadyRead())); + connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketError())); + connect(&socket, SIGNAL(disconnected()), SLOT(socketDisconnected())); + connect(&socket, SIGNAL(connected()), SLOT(socketConnected())); + // socket bytes written -> we can push more from upstream to socket + connect(&socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64))); + + bareProtocol = url().queryItemValue(QLatin1String("bare")) == QLatin1String("1"); + + if (operation() == QNetworkAccessManager::PutOperation) { + uploadByteDevice = createUploadByteDevice(); + QObject::connect(uploadByteDevice, SIGNAL(readyRead()), this, SLOT(uploadReadyReadSlot())); + QMetaObject::invokeMethod(this, "uploadReadyReadSlot", Qt::QueuedConnection); + } +} + +void QNetworkAccessDebugPipeBackend::socketReadyRead() +{ + pushFromSocketToDownstream(); +} + +void QNetworkAccessDebugPipeBackend::downstreamReadyWrite() +{ + pushFromSocketToDownstream(); +} + +void QNetworkAccessDebugPipeBackend::socketBytesWritten(qint64) +{ + pushFromUpstreamToSocket(); +} + +void QNetworkAccessDebugPipeBackend::uploadReadyReadSlot() +{ + pushFromUpstreamToSocket(); +} + +void QNetworkAccessDebugPipeBackend::pushFromSocketToDownstream() +{ + QByteArray buffer; + + if (socket.state() == QAbstractSocket::ConnectingState) { + return; + } + + forever { + if (hasDownloadFinished) + return; + + buffer.resize(ReadBufferSize); + qint64 haveRead = socket.read(buffer.data(), ReadBufferSize); + + if (haveRead == -1) { + hasDownloadFinished = true; + // this ensures a good last downloadProgress is emitted + setHeader(QNetworkRequest::ContentLengthHeader, QVariant()); + possiblyFinish(); + break; + } else if (haveRead == 0) { + break; + } else { + // have read something + buffer.resize(haveRead); + bytesDownloaded += haveRead; + + QByteDataBuffer list; + list.append(buffer); + buffer.clear(); // important because of implicit sharing! + writeDownstreamData(list); + } + } +} + +void QNetworkAccessDebugPipeBackend::pushFromUpstreamToSocket() +{ + // FIXME + if (operation() == QNetworkAccessManager::PutOperation) { + if (hasUploadFinished) + return; + + forever { + if (socket.bytesToWrite() >= WriteBufferSize) + return; + + qint64 haveRead; + const char *readPointer = uploadByteDevice->readPointer(WriteBufferSize, haveRead); + if (haveRead == -1) { + // EOF + hasUploadFinished = true; + emitReplyUploadProgress(bytesUploaded, bytesUploaded); + possiblyFinish(); + break; + } else if (haveRead == 0 || readPointer == 0) { + // nothing to read right now, we will be called again later + break; + } else { + qint64 haveWritten; + haveWritten = socket.write(readPointer, haveRead); + + if (haveWritten < 0) { + // write error! + QString msg = QCoreApplication::translate("QNetworkAccessDebugPipeBackend", "Write error writing to %1: %2") + .arg(url().toString(), socket.errorString()); + error(QNetworkReply::ProtocolFailure, msg); + finished(); + return; + } else { + uploadByteDevice->advanceReadPointer(haveWritten); + bytesUploaded += haveWritten; + emitReplyUploadProgress(bytesUploaded, -1); + } + + //QCoreApplication::processEvents(); + + } + } + } +} + +void QNetworkAccessDebugPipeBackend::possiblyFinish() +{ + if (hasEverythingFinished) + return; + hasEverythingFinished = true; + + if ((operation() == QNetworkAccessManager::GetOperation) && hasDownloadFinished) { + socket.close(); + finished(); + } else if ((operation() == QNetworkAccessManager::PutOperation) && hasUploadFinished) { + socket.close(); + finished(); + } + + +} + +void QNetworkAccessDebugPipeBackend::closeDownstreamChannel() +{ + qWarning() << "QNetworkAccessDebugPipeBackend::closeDownstreamChannel()" << operation(); + //if (operation() == QNetworkAccessManager::GetOperation) + // socket.disconnectFromHost(); +} + + +void QNetworkAccessDebugPipeBackend::socketError() +{ + qWarning() << "QNetworkAccessDebugPipeBackend::socketError()" << socket.error(); + QNetworkReply::NetworkError code; + switch (socket.error()) { + case QAbstractSocket::RemoteHostClosedError: + return; // socketDisconnected will be called + + case QAbstractSocket::NetworkError: + code = QNetworkReply::UnknownNetworkError; + break; + + default: + code = QNetworkReply::ProtocolFailure; + break; + } + + error(code, QObject::tr("Socket error on %1: %2") + .arg(url().toString(), socket.errorString())); + finished(); + disconnect(&socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected())); + +} + +void QNetworkAccessDebugPipeBackend::socketDisconnected() +{ + pushFromSocketToDownstream(); + + if (socket.bytesToWrite() == 0) { + // normal close + } else { + // abnormal close + QString msg = QObject::tr("Remote host closed the connection prematurely on %1") + .arg(url().toString()); + error(QNetworkReply::RemoteHostClosedError, msg); + finished(); + } +} + +void QNetworkAccessDebugPipeBackend::socketConnected() +{ +} + +bool QNetworkAccessDebugPipeBackend::waitForDownstreamReadyRead(int ms) +{ + Q_UNUSED(ms); + qCritical("QNetworkAccess: Debug pipe backend does not support waitForReadyRead()"); + return false; +} + +#endif + +QT_END_NAMESPACE