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 |