src/network/access/qfilenetworkreply.cpp
changeset 7 f7bc934e204c
parent 3 41300fa6a67c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
     1 /****************************************************************************
     1 /****************************************************************************
     2 **
     2 **
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     4 ** All rights reserved.
     4 ** All rights reserved.
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     6 **
     6 **
     7 ** This file is part of the QtNetwork module of the Qt Toolkit.
     7 ** This file is part of the QtNetwork module of the Qt Toolkit.
     8 **
     8 **
    42 #include "qfilenetworkreply_p.h"
    42 #include "qfilenetworkreply_p.h"
    43 
    43 
    44 #include "QtCore/qdatetime.h"
    44 #include "QtCore/qdatetime.h"
    45 #include <QtCore/QCoreApplication>
    45 #include <QtCore/QCoreApplication>
    46 #include <QtCore/QFileInfo>
    46 #include <QtCore/QFileInfo>
       
    47 #include <QDebug>
    47 
    48 
    48 QT_BEGIN_NAMESPACE
    49 QT_BEGIN_NAMESPACE
    49 
    50 
    50 QFileNetworkReplyPrivate::QFileNetworkReplyPrivate()
    51 QFileNetworkReplyPrivate::QFileNetworkReplyPrivate()
    51     : QNetworkReplyPrivate(), realFileSize(0), finished(false)
    52     : QNetworkReplyPrivate(), fileEngine(0), fileSize(0), filePos(0)
    52 {
    53 {
    53 }
    54 }
    54 
    55 
    55 QFileNetworkReply::QFileNetworkReply(QObject *parent, const QNetworkRequest &req)
    56 QFileNetworkReplyPrivate::~QFileNetworkReplyPrivate()
       
    57 {
       
    58     delete fileEngine;
       
    59 }
       
    60 
       
    61 QFileNetworkReply::~QFileNetworkReply()
       
    62 {
       
    63 }
       
    64 
       
    65 QFileNetworkReply::QFileNetworkReply(QObject *parent, const QNetworkRequest &req, const QNetworkAccessManager::Operation op)
    56     : QNetworkReply(*new QFileNetworkReplyPrivate(), parent)
    66     : QNetworkReply(*new QFileNetworkReplyPrivate(), parent)
    57 {
    67 {
    58     setRequest(req);
    68     setRequest(req);
    59     setUrl(req.url());
    69     setUrl(req.url());
    60     setOperation(QNetworkAccessManager::GetOperation);
    70     setOperation(op);
    61     QMetaObject::invokeMethod(this, "_q_startOperation", Qt::QueuedConnection);
       
    62     QNetworkReply::open(QIODevice::ReadOnly);
    71     QNetworkReply::open(QIODevice::ReadOnly);
    63 }
    72 
    64 
    73     qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
    65 QFileNetworkReply::~QFileNetworkReply()
    74 
    66 {
    75     QFileNetworkReplyPrivate *d = (QFileNetworkReplyPrivate*) d_func();
    67 }
    76 
    68 
    77     QUrl url = req.url();
    69 // This code is mostly inspired by QNetworkAccessFileBackend
       
    70 // We also use its translation context for error messages
       
    71 void QFileNetworkReplyPrivate::_q_startOperation()
       
    72 {
       
    73     Q_Q(QFileNetworkReply);
       
    74 
       
    75     QUrl url = q->url();
       
    76     if (url.host() == QLatin1String("localhost"))
    78     if (url.host() == QLatin1String("localhost"))
    77         url.setHost(QString());
    79         url.setHost(QString());
    78 
    80 
    79 #if !defined(Q_OS_WIN)
    81 #if !defined(Q_OS_WIN)
    80     // do not allow UNC paths on Unix
    82     // do not allow UNC paths on Unix
    81     if (!url.host().isEmpty()) {
    83     if (!url.host().isEmpty()) {
    82         // we handle only local files
    84         // we handle only local files
    83         QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Request for opening non-local file %1").arg(url.toString());
    85         QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Request for opening non-local file %1").arg(url.toString());
    84         q->setError(QNetworkReply::ProtocolInvalidOperationError, msg);
    86         setError(QNetworkReply::ProtocolInvalidOperationError, msg);
    85         emit q->error(QNetworkReply::ProtocolInvalidOperationError);
    87         QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
    86         doFinished();
    88             Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ProtocolInvalidOperationError));
       
    89         QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
    87         return;
    90         return;
    88     }
    91     }
    89 #endif
    92 #endif
    90     if (url.path().isEmpty())
    93     if (url.path().isEmpty())
    91         url.setPath(QLatin1String("/"));
    94         url.setPath(QLatin1String("/"));
    92     q->setUrl(url);
    95     setUrl(url);
    93 
    96 
    94 
    97 
    95     QString fileName = url.toLocalFile();
    98     QString fileName = url.toLocalFile();
    96     if (fileName.isEmpty()) {
    99     if (fileName.isEmpty()) {
    97         fileName = url.toString(QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemoveQuery);
   100         fileName = url.toString(QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemoveQuery);
    98     }
   101     }
    99     realFile.setFileName(fileName);
   102 
   100 
   103     QFileInfo fi(fileName);
   101     QFileInfo fi(realFile);
       
   102     if (fi.isDir()) {
   104     if (fi.isDir()) {
   103         QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Cannot open %1: Path is a directory").arg(url.toString());
   105         QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Cannot open %1: Path is a directory").arg(url.toString());
   104         q->setError(QNetworkReply::ContentOperationNotPermittedError, msg);
   106         setError(QNetworkReply::ContentOperationNotPermittedError, msg);
   105         emit q->error(QNetworkReply::ContentOperationNotPermittedError);
   107         QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
   106         doFinished();
   108             Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ContentOperationNotPermittedError));
       
   109         QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
   107         return;
   110         return;
   108     }
   111     }
   109 
   112 
   110     bool opened = realFile.open(QIODevice::ReadOnly | QIODevice::Unbuffered);
   113     d->fileEngine = QAbstractFileEngine::create(fileName);
       
   114     bool opened = d->fileEngine->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
   111 
   115 
   112     // could we open the file?
   116     // could we open the file?
   113     if (!opened) {
   117     if (!opened) {
   114         QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Error opening %1: %2")
   118         QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Error opening %1: %2")
   115                       .arg(realFile.fileName(), realFile.errorString());
   119                       .arg(fileName, d->fileEngine->errorString());
   116 
   120 
   117         if (realFile.exists()) {
   121         if (fi.exists()) {
   118             q->setError(QNetworkReply::ContentAccessDenied, msg);
   122             setError(QNetworkReply::ContentAccessDenied, msg);
   119             emit q->error(QNetworkReply::ContentAccessDenied);
   123             QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
       
   124                 Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ContentAccessDenied));
   120         } else {
   125         } else {
   121             q->setError(QNetworkReply::ContentNotFoundError, msg);
   126             setError(QNetworkReply::ContentNotFoundError, msg);
   122             emit q->error(QNetworkReply::ContentNotFoundError);
   127             QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
       
   128                 Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ContentNotFoundError));
   123         }
   129         }
   124         doFinished();
   130         QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
   125         return;
   131         return;
   126     }
   132     }
   127 
   133 
   128     realFileSize = fi.size();
   134     d->fileSize = fi.size();
   129     q->setHeader(QNetworkRequest::LastModifiedHeader, fi.lastModified());
   135     setHeader(QNetworkRequest::LastModifiedHeader, fi.lastModified());
   130     q->setHeader(QNetworkRequest::ContentLengthHeader, realFileSize);
   136     setHeader(QNetworkRequest::ContentLengthHeader, d->fileSize);
   131 
   137 
   132     emit q->metaDataChanged();
   138     QMetaObject::invokeMethod(this, "metaDataChanged", Qt::QueuedConnection);
   133     emit q->downloadProgress(realFileSize, realFileSize);
   139     QMetaObject::invokeMethod(this, "downloadProgress", Qt::QueuedConnection,
   134     emit q->readyRead();
   140         Q_ARG(qint64, d->fileSize), Q_ARG(qint64, d->fileSize));
   135     doFinished();
   141     QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection);
       
   142     QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
   136 }
   143 }
   137 
   144 
   138 bool QFileNetworkReplyPrivate::isFinished() const
   145 bool QFileNetworkReplyPrivate::isFinished() const
   139 {
   146 {
   140     return finished;
   147     return true;
   141 }
   148 }
   142 
       
   143 void QFileNetworkReplyPrivate::doFinished()
       
   144 {
       
   145     Q_Q(QFileNetworkReply);
       
   146     finished = true;
       
   147     emit q->finished();
       
   148 }
       
   149 
       
   150 
   149 
   151 void QFileNetworkReply::close()
   150 void QFileNetworkReply::close()
   152 {
   151 {
   153     Q_D(QFileNetworkReply);
   152     Q_D(QFileNetworkReply);
   154     QNetworkReply::close();
   153     QNetworkReply::close();
   155     d->realFile.close();
   154     if (d->fileEngine)
   156 
   155         d->fileEngine->close();
   157     if (!d->finished)
       
   158         d->doFinished();
       
   159 }
   156 }
   160 
   157 
   161 void QFileNetworkReply::abort()
   158 void QFileNetworkReply::abort()
   162 {
   159 {
   163     Q_D(QFileNetworkReply);
   160     Q_D(QFileNetworkReply);
   164     QNetworkReply::close();
   161     QNetworkReply::close();
   165     d->realFile.close();
   162     if (d->fileEngine)
   166 
   163         d->fileEngine->close();
   167     if (!d->finished)
       
   168         d->doFinished();
       
   169 }
   164 }
   170 
   165 
   171 qint64 QFileNetworkReply::bytesAvailable() const
   166 qint64 QFileNetworkReply::bytesAvailable() const
   172 {
   167 {
   173     Q_D(const QFileNetworkReply);
   168     Q_D(const QFileNetworkReply);
   174     return QNetworkReply::bytesAvailable() + d->realFile.bytesAvailable();
   169     if (!d->fileEngine)
       
   170         return 0;
       
   171 
       
   172     return QNetworkReply::bytesAvailable() + d->fileSize - d->filePos;
   175 }
   173 }
   176 
   174 
   177 bool QFileNetworkReply::isSequential () const
   175 bool QFileNetworkReply::isSequential () const
   178 {
   176 {
   179     return true;
   177     return true;
   180 }
   178 }
   181 
   179 
   182 qint64 QFileNetworkReply::size() const
   180 qint64 QFileNetworkReply::size() const
   183 {
   181 {
   184     Q_D(const QFileNetworkReply);
   182     Q_D(const QFileNetworkReply);
   185     return d->realFileSize;
   183     return d->fileSize;
   186 }
   184 }
   187 
   185 
   188 /*!
   186 /*!
   189     \internal
   187     \internal
   190 */
   188 */
   191 qint64 QFileNetworkReply::readData(char *data, qint64 maxlen)
   189 qint64 QFileNetworkReply::readData(char *data, qint64 maxlen)
   192 {
   190 {
   193     Q_D(QFileNetworkReply);
   191     Q_D(QFileNetworkReply);
   194     qint64 ret = d->realFile.read(data, maxlen);
   192     if (!d->fileEngine)
   195     if (ret == 0 && bytesAvailable() == 0)
   193         return -1;
       
   194 
       
   195     qint64 ret = d->fileEngine->read(data, maxlen);
       
   196     if (ret == 0 && bytesAvailable() == 0) {
   196         return -1; // everything had been read
   197         return -1; // everything had been read
   197     else
   198     } else if (ret > 0) {
   198         return ret;
   199         d->filePos += ret;
       
   200     }
       
   201 
       
   202     return ret;
   199 }
   203 }
   200 
   204 
   201 
   205 
   202 QT_END_NAMESPACE
   206 QT_END_NAMESPACE
   203 
   207