src/network/access/qnetworkaccessdebugpipebackend.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtNetwork module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    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 "private/qnoncontiguousbytedevice_p.h"
       
    46 
       
    47 QT_BEGIN_NAMESPACE
       
    48 
       
    49 #ifdef QT_BUILD_INTERNAL
       
    50 
       
    51 enum {
       
    52     ReadBufferSize = 16384,
       
    53     WriteBufferSize = ReadBufferSize
       
    54 };
       
    55 
       
    56 QNetworkAccessBackend *
       
    57 QNetworkAccessDebugPipeBackendFactory::create(QNetworkAccessManager::Operation op,
       
    58                                               const QNetworkRequest &request) const
       
    59 {
       
    60     // is it an operation we know of?
       
    61     switch (op) {
       
    62     case QNetworkAccessManager::GetOperation:
       
    63     case QNetworkAccessManager::PutOperation:
       
    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 
       
    89 void QNetworkAccessDebugPipeBackend::open()
       
    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 
       
   104     if (operation() == QNetworkAccessManager::PutOperation) {
       
   105         uploadByteDevice = createUploadByteDevice();
       
   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
       
   149             setHeader(QNetworkRequest::ContentLengthHeader, QVariant());
       
   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
       
   170     if (operation() == QNetworkAccessManager::PutOperation) {
       
   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());
       
   197                     error(QNetworkReply::ProtocolFailure, msg);
       
   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()" << operation();
       
   233     //if (operation() == QNetworkAccessManager::GetOperation)
       
   234     //    socket.disconnectFromHost();
       
   235 }
       
   236 
       
   237 
       
   238 void QNetworkAccessDebugPipeBackend::socketError()
       
   239 {
       
   240     qWarning() << "QNetworkAccessDebugPipeBackend::socketError()" << socket.error();
       
   241     QNetworkReply::NetworkError code;
       
   242     switch (socket.error()) {
       
   243     case QAbstractSocket::RemoteHostClosedError:
       
   244         return;                 // socketDisconnected will be called
       
   245 
       
   246     case QAbstractSocket::NetworkError:
       
   247         code = QNetworkReply::UnknownNetworkError;
       
   248         break;
       
   249 
       
   250     default:
       
   251         code = QNetworkReply::ProtocolFailure;
       
   252         break;
       
   253     }
       
   254 
       
   255     error(code, QObject::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 = QObject::tr("Remote host closed the connection prematurely on %1")
       
   271                              .arg(url().toString());
       
   272         error(QNetworkReply::RemoteHostClosedError, msg);
       
   273         finished();
       
   274     }
       
   275 }
       
   276 
       
   277 void QNetworkAccessDebugPipeBackend::socketConnected()
       
   278 {
       
   279 }
       
   280 
       
   281 bool QNetworkAccessDebugPipeBackend::waitForDownstreamReadyRead(int ms)
       
   282 {
       
   283     Q_UNUSED(ms);
       
   284     qCritical("QNetworkAccess: Debug pipe backend does not support waitForReadyRead()");
       
   285     return false;
       
   286 }
       
   287 
       
   288 #endif
       
   289 
       
   290 QT_END_NAMESPACE