QtFileDownloader.cpp [plain text]
#include "config.h"
#include "QtFileDownloader.h"
#include "DataReference.h"
#include "Download.h"
#include "HTTPParsers.h"
#include "MIMETypeRegistry.h"
#include <QCoreApplication>
#include <QFile>
#include <QFileInfo>
#include <QNetworkAccessManager>
#include <WebCore/QNetworkReplyHandler.h>
#include <WebCore/ResourceError.h>
#include <WebCore/ResourceResponse.h>
using namespace WebCore;
using namespace WTF;
namespace WebKit {
QtFileDownloader::QtFileDownloader(Download* download, PassOwnPtr<QNetworkReply> reply)
: m_download(download)
, m_reply(reply)
, m_error(QNetworkReply::NoError)
, m_headersRead(false)
{
}
QtFileDownloader::~QtFileDownloader()
{
if (!m_destinationFile)
return;
abortDownloadWritingAndEmitError(QtFileDownloader::DownloadErrorAborted);
}
void QtFileDownloader::init()
{
connect(m_reply.get(), SIGNAL(readyRead()), SLOT(onReadyRead()));
connect(m_reply.get(), SIGNAL(finished()), SLOT(onFinished()));
connect(m_reply.get(), SIGNAL(error(QNetworkReply::NetworkError)), SLOT(onError(QNetworkReply::NetworkError)));
}
QString QtFileDownloader::determineFilename()
{
ASSERT(!m_destinationFile);
QString filenameCandidate = filenameFromHTTPContentDisposition(QString::fromLatin1(m_reply->rawHeader("Content-Disposition")));
if (filenameCandidate.isEmpty()) {
KURL kurl = m_reply->url();
filenameCandidate = decodeURLEscapeSequences(kurl.lastPathComponent());
}
if (filenameCandidate.isEmpty()) {
abortDownloadWritingAndEmitError(QtFileDownloader::DownloadErrorCannotDetermineFilename);
return QString();
}
QFileInfo filenameFilter(filenameCandidate);
QString filename = filenameFilter.fileName();
if (filename.isEmpty()) {
abortDownloadWritingAndEmitError(QtFileDownloader::DownloadErrorCannotDetermineFilename);
return QString();
}
return filename;
}
void QtFileDownloader::startTransfer(const QString& decidedFilePath)
{
ASSERT(!m_destinationFile);
if (m_error != QNetworkReply::NoError) {
abortDownloadWritingAndEmitError(QtFileDownloader::DownloadErrorNetworkFailure);
return;
}
if (decidedFilePath.isEmpty()) {
abortDownloadWritingAndEmitError(QtFileDownloader::DownloadErrorCancelled);
return;
}
OwnPtr<QFile> downloadFile = adoptPtr(new QFile(decidedFilePath));
if (!downloadFile->open(QIODevice::WriteOnly | QIODevice::Truncate)) {
abortDownloadWritingAndEmitError(QtFileDownloader::DownloadErrorCannotOpenFile);
return;
}
m_destinationFile = downloadFile.release();
m_download->didCreateDestination(m_destinationFile->fileName());
if (m_reply->bytesAvailable())
onReadyRead();
if (m_reply->isFinished())
onFinished();
}
void QtFileDownloader::abortDownloadWritingAndEmitError(QtFileDownloader::DownloadError errorCode)
{
m_reply->abort();
if (errorCode == QtFileDownloader::DownloadErrorNetworkFailure) {
m_download->didFail(QNetworkReplyHandler::errorForReply(m_reply.get()), CoreIPC::DataReference(0, 0));
return;
}
QString translatedErrorMessage;
switch (errorCode) {
case QtFileDownloader::DownloadErrorAborted:
translatedErrorMessage = QCoreApplication::translate("QtFileDownloader", "Download aborted");
break;
case QtFileDownloader::DownloadErrorCannotWriteToFile:
translatedErrorMessage = QCoreApplication::translate("QtFileDownloader", "Cannot write to file");
break;
case QtFileDownloader::DownloadErrorCannotOpenFile:
translatedErrorMessage = QCoreApplication::translate("QtFileDownloader", "Cannot open file for writing");
break;
case QtFileDownloader::DownloadErrorDestinationAlreadyExists:
translatedErrorMessage = QCoreApplication::translate("QtFileDownloader", "Destination already exists");
break;
case QtFileDownloader::DownloadErrorCancelled:
translatedErrorMessage = QCoreApplication::translate("QtFileDownloader", "Download cancelled by caller");
break;
case QtFileDownloader::DownloadErrorCannotDetermineFilename:
translatedErrorMessage = QCoreApplication::translate("QtFileDownloader", "Cannot determine filename");
break;
default:
ASSERT_NOT_REACHED();
}
ResourceError downloadError("Download", errorCode, m_reply->url().toString(), translatedErrorMessage);
m_download->didFail(downloadError, CoreIPC::DataReference(0, 0));
}
void QtFileDownloader::handleDownloadResponse()
{
String contentType = m_reply->header(QNetworkRequest::ContentTypeHeader).toString();
String encoding = extractCharsetFromMediaType(contentType);
String mimeType = extractMIMETypeFromMediaType(contentType);
String filename = determineFilename();
if (filename.isEmpty())
return;
if (mimeType.isEmpty())
mimeType = MIMETypeRegistry::getMIMETypeForPath(m_reply->url().path());
ResourceResponse response(m_reply->url(), mimeType, m_reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), encoding, filename);
m_download->didReceiveResponse(response);
}
void QtFileDownloader::onReadyRead()
{
if (m_destinationFile) {
QByteArray content = m_reply->readAll();
if (content.size() <= 0)
return;
qint64 bytesWritten = m_destinationFile->write(content);
if (bytesWritten == -1) {
abortDownloadWritingAndEmitError(QtFileDownloader::DownloadErrorCannotWriteToFile);
return;
}
ASSERT(bytesWritten == content.size());
m_download->didReceiveData(bytesWritten);
} else if (!m_headersRead) {
handleDownloadResponse();
m_headersRead = true;
}
}
void QtFileDownloader::onFinished()
{
if (!m_headersRead) {
handleDownloadResponse();
m_headersRead = true;
return;
}
if (!m_destinationFile)
return;
m_destinationFile.clear();
if (m_error == QNetworkReply::NoError)
m_download->didFinish();
else if (m_error == QNetworkReply::OperationCanceledError)
abortDownloadWritingAndEmitError(QtFileDownloader::DownloadErrorCancelled);
else
abortDownloadWritingAndEmitError(QtFileDownloader::DownloadErrorNetworkFailure);
}
void QtFileDownloader::onError(QNetworkReply::NetworkError code)
{
m_error = code;
}
void QtFileDownloader::cancel()
{
m_reply->abort();
}
} #include "moc_QtFileDownloader.cpp"