--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/browsercore/appfw/Api/Managers/downloadcontroller.cpp Tue May 04 12:39:35 2010 +0300
@@ -0,0 +1,735 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+
+#include "downloadcontroller.h"
+#include "downloadcontroller_p.h"
+
+#include <QNetworkProxy>
+#include <QNetworkReply>
+#include <QNetworkRequest>
+#include <QString>
+#include <QUrl>
+#include <QWebPage>
+
+#ifdef USE_DOWNLOAD_MANAGER
+#include "download.h"
+#include "downloadmanager.h"
+
+static const char * downloadErrorToString(QNetworkReply::NetworkError error)
+{
+ switch (error) {
+ case QNetworkReply::NoError:
+ return "QNetworkReply::NoError";
+ case QNetworkReply::ConnectionRefusedError:
+ return "QNetworkReply::ConnectionRefusedError";
+ case QNetworkReply::RemoteHostClosedError:
+ return "QNetworkReply::RemoteHostClosedError";
+ case QNetworkReply::HostNotFoundError:
+ return "QNetworkReply::HostNotFoundError";
+ case QNetworkReply::TimeoutError:
+ return "QNetworkReply::TimeoutError";
+ case QNetworkReply::OperationCanceledError:
+ return "QNetworkReply::OperationCanceledError";
+ case QNetworkReply::SslHandshakeFailedError:
+ return "QNetworkReply::SslHandshakeFailedError";
+ case QNetworkReply::ProxyConnectionRefusedError:
+ return "QNetworkReply::ProxyConnectionRefusedError";
+ case QNetworkReply::ProxyConnectionClosedError:
+ return "QNetworkReply::ProxyConnectionClosedError";
+ case QNetworkReply::ProxyNotFoundError:
+ return "QNetworkReply::ProxyNotFoundError";
+ case QNetworkReply::ProxyTimeoutError:
+ return "QNetworkReply::ProxyTimeoutError";
+ case QNetworkReply::ProxyAuthenticationRequiredError:
+ return "QNetworkReply::ProxyAuthenticationRequiredError";
+ case QNetworkReply::ContentAccessDenied:
+ return "QNetworkReply::ContentAccessDenied";
+ case QNetworkReply::ContentOperationNotPermittedError:
+ return "QNetworkReply::ContentOperationNotPermittedError";
+ case QNetworkReply::ContentNotFoundError:
+ return "QNetworkReply::ContentNotFoundError";
+ case QNetworkReply::AuthenticationRequiredError:
+ return "QNetworkReply::AuthenticationRequiredError";
+ case QNetworkReply::ContentReSendError:
+ return "QNetworkReply::ContentReSendError";
+ case QNetworkReply::ProtocolUnknownError:
+ return "QNetworkReply::ProtocolUnknownError";
+ case QNetworkReply::ProtocolInvalidOperationError:
+ return "QNetworkReply::ProtocolInvalidOperationError";
+ case QNetworkReply::UnknownNetworkError:
+ return "QNetworkReply::UnknownNetworkError";
+ case QNetworkReply::UnknownProxyError:
+ return "QNetworkReply::UnknownProxyError";
+ case QNetworkReply::UnknownContentError:
+ return "QNetworkReply::UnknownContentError";
+ case QNetworkReply::ProtocolFailure:
+ return "QNetworkReply::ProtocolFailure";
+ default:
+ return 0;
+ }
+}
+
+static const char * downloadEventToString(DEventType type)
+{
+ switch (type) {
+ case DownloadCreated:
+ return "DownloadManager:DownloadCreated";
+ case DownloadsCleared:
+ return "DownloadManager:DownloadsCleared";
+ case ConnectedToServer:
+ return "DownloadManager:ConnectedToServer";
+ case DisconnectedFromServer:
+ return "DownloadManager:DisconnectedFromServer";
+ case ServerError:
+ return "DownloadManager:ServerError";
+ case Started:
+ return "Download:Started";
+ case HeaderReceived:
+ return "Download:HeaderReceived";
+ case Progress:
+ return "Download:Progress";
+ case Completed:
+ return "Download:Completed";
+ case Paused:
+ return "Download:Paused";
+ case Cancelled:
+ return "Download:Cancelled";
+ case Failed:
+ return "Download:Failed";
+ case DescriptorUpdated:
+ return "Download:DescriptorUpdated";
+ case NetworkLoss:
+ return "Download:NetworkLoss";
+ case Error:
+ return "Download:Error";
+ case OMADownloadDescriptorReady:
+ return "Download:OMADownloadDescriptorReady";
+ case WMDRMLicenseAcquiring:
+ return "Download:WMDRMLicenseAcquiring";
+ default:
+ return 0;
+ }
+}
+
+static const char * downloadPriorityToString(DownloadPriority priority)
+{
+ switch (priority) {
+ case High:
+ return "High";
+ case Low:
+ return "Low";
+ default:
+ return 0;
+ }
+}
+
+static const char * downloadScopeToString(DownloadScope scope)
+{
+ switch (scope) {
+ case Normal:
+ return "Normal";
+ case Background:
+ return "Background";
+ default:
+ return 0;
+ }
+}
+
+static const char * downloadStateToString(DownloadState state)
+{
+ switch (state) {
+ case DlNone:
+ return "DlNone";
+ case DlCreated:
+ return "DlCreated";
+ case DlStarted:
+ return "DlStarted";
+ case DlInprogress:
+ return "DlInprogress";
+ case DlPaused:
+ return "DlPaused";
+ case DlCompleted:
+ return "DlCompleted";
+ case DlFailed:
+ return "DlFailed";
+ case DlCancelled:
+ return "DlCancelled";
+ case DlDescriptorUpdated:
+ return "DlDescriptorUpdated";
+ default:
+ return 0;
+ }
+}
+
+static const char * downloadTypeToString(DownloadType type)
+{
+ switch (type) {
+ case Parallel:
+ return "Parallel";
+ case Sequential:
+ return "Sequential";
+ default:
+ return 0;
+ }
+}
+
+static void debugDownloadStr(
+ Download * download,
+ DownloadAttribute attribute,
+ const char * name)
+{
+ QString value = download->getAttribute(attribute).toString();
+ if (value.length() == 0) {
+ return;
+ }
+
+ qDebug() << "DL" << download->id() << name << value;
+}
+
+static void debugDownloadInt(
+ Download * download,
+ DownloadAttribute attribute,
+ const char * name)
+{
+ int value = download->getAttribute(attribute).toInt();
+ if (value == 0) {
+ return;
+ }
+
+ qDebug() << "DL" << download->id() << name << value;
+}
+
+static void debugDownloadUInt(
+ Download * download,
+ DownloadAttribute attribute,
+ const char * name)
+{
+ uint value = download->getAttribute(attribute).toUInt();
+ if (value == 0) {
+ return;
+ }
+
+ qDebug() << "DL" << download->id() << name << value;
+}
+
+static void debugDownloadError(
+ Download * download,
+ DownloadAttribute attribute,
+ const char * name)
+{
+ int num = download->getAttribute(attribute).toInt();
+
+ const char * str = downloadErrorToString(static_cast<QNetworkReply::NetworkError>(num));
+ if (str == 0) {
+ str = "???";
+ }
+
+ qDebug() << "DL" << download->id() << name << num << str;
+}
+
+static void debugDownloadPriority(
+ Download * download,
+ DownloadAttribute attribute,
+ const char * name)
+{
+ int num = download->getAttribute(attribute).toInt();
+
+ const char * str = downloadPriorityToString(static_cast<DownloadPriority>(num));
+ if (str == 0) {
+ str = "???";
+ }
+
+ qDebug() << "DL" << download->id() << name << num << str;
+}
+
+static void debugDownloadScope(
+ Download * download,
+ DownloadAttribute attribute,
+ const char * name)
+{
+ int num = download->getAttribute(attribute).toInt();
+
+ const char * str = downloadScopeToString(static_cast<DownloadScope>(num));
+ if (str == 0) {
+ str = "???";
+ }
+
+ qDebug() << "DL" << download->id() << name << num << str;
+}
+
+static void debugDownloadState(
+ Download * download,
+ DownloadAttribute attribute,
+ const char * name)
+{
+ int num = download->getAttribute(attribute).toInt();
+
+ const char * str = downloadStateToString(static_cast<DownloadState>(num));
+ if (str == 0) {
+ str = "???";
+ }
+
+ qDebug() << "DL" << download->id() << name << num << str;
+}
+
+static void debugDownloadType(
+ Download * download,
+ DownloadAttribute attribute,
+ const char * name)
+{
+ int num = download->getAttribute(attribute).toInt();
+
+ const char * str = downloadTypeToString(static_cast<DownloadType>(num));
+ if (str == 0) {
+ str = "???";
+ }
+
+ qDebug() << "DL" << download->id() << name << num << str;
+}
+
+void DownloadController::debugDownload(Download * download)
+{
+ debugDownloadState(download,
+ DlDownloadState,
+ "DlDownloadState");
+
+ debugDownloadError(download,
+ DlLastError,
+ "DlLastError");
+
+ debugDownloadStr(download,
+ DlLastErrorString,
+ "DlLastErrorString");
+
+ debugDownloadStr(download,
+ DlSourceUrl,
+ "DlSourceUrl");
+
+ debugDownloadStr(download,
+ DlContentType,
+ "DlContentType");
+
+ debugDownloadStr(download,
+ DlDestPath,
+ "DlDestPath");
+
+ debugDownloadStr(download,
+ DlFileName,
+ "DlFileName");
+
+ debugDownloadInt(download,
+ DlDownloadedSize,
+ "DlDownloadedSize");
+
+ debugDownloadInt(download,
+ DlTotalSize,
+ "DlTotalSize");
+
+ debugDownloadInt(download,
+ DlLastPausedSize,
+ "DlLastPausedSize");
+
+ debugDownloadInt(download,
+ DlPercentage,
+ "DlPercentage");
+
+ debugDownloadStr(download,
+ DlStartTime,
+ "DlStartTime");
+
+ debugDownloadStr(download,
+ DlEndTime,
+ "DlEndTime");
+
+ debugDownloadUInt(download,
+ DlElapsedTime,
+ "DlElapsedTime");
+
+ debugDownloadStr(download,
+ DlRemainingTime,
+ "DlRemainingTime");
+
+ debugDownloadStr(download,
+ DlSpeed,
+ "DlSpeed");
+
+ debugDownloadScope(download,
+ DlDownloadScope,
+ "DlDownloadScope");
+
+ debugDownloadType(download,
+ DlDownloadType,
+ "DlDownloadType");
+
+ debugDownloadPriority(download,
+ DlPriority,
+ "DlPriority");
+
+ debugDownloadInt(download,
+ DlProgressInterval,
+ "DlProgressInterval");
+
+ debugDownloadStr(download,
+ OMADownloadDescriptorName,
+ "OMADownloadDescriptorName");
+
+ debugDownloadStr(download,
+ OMADownloadDescriptorVersion,
+ "OMADownloadDescriptorVersion");
+
+ debugDownloadStr(download,
+ OMADownloadDescriptorType,
+ "OMADownloadDescriptorType");
+
+ debugDownloadStr(download,
+ OMADownloadDescriptorSize,
+ "OMADownloadDescriptorSize");
+
+ debugDownloadStr(download,
+ OMADownloadDescriptorVendor,
+ "OMADownloadDescriptorVendor");
+
+ debugDownloadStr(download,
+ OMADownloadDescriptorDescription,
+ "OMADownloadDescriptorDescription");
+
+ debugDownloadStr(download,
+ OMADownloadDescriptorNextURL,
+ "OMADownloadDescriptorNextURL");
+}
+
+static void debugDownloadEvent(DEventType type)
+{
+ const char * name = downloadEventToString(type);
+ if (name == 0) {
+ return;
+ }
+
+ qDebug() << "Received event" << name;
+}
+
+// DownloadControllerPrivate implementation
+
+DownloadControllerPrivate::DownloadControllerPrivate(
+ DownloadController * downloadController,
+ const QString & client,
+ const QNetworkProxy & proxy)
+{
+ m_downloadController = downloadController;
+
+ m_downloadManager = new DownloadManager(client);
+ m_downloadManager->registerEventReceiver(this);
+ if (proxy.type() != QNetworkProxy::NoProxy)
+ m_downloadManager->setProxy(proxy.hostName(), proxy.port());
+}
+
+DownloadControllerPrivate::~DownloadControllerPrivate()
+{
+ delete m_downloadManager;
+}
+
+static QString downloadFileName(QUrl url)
+{
+ QString scheme = url.scheme();
+
+ // For http and https, let the download manager determine the filename.
+
+ if (scheme == "http" || scheme == "https")
+ return QString();
+
+ // For data scheme (see http://en.wikipedia.org/wiki/Data_URI_scheme)
+ // we don't have a file name per-se, so construct one from the content
+ // type.
+
+ if (scheme == "data") {
+ // Typical example: data:image/png;base64,...
+
+ QString path = url.path();
+ QString type = path.section('/', 0, 0);
+ QString subtype = path.section('/', 1, 1).section(';', 0, 0);
+
+ // For now we just use type as base name and subtype
+ // as extension. For the common case of image/jpg
+ // and stuff like that this works fine.
+
+ return type + "." + subtype;
+ }
+
+ // For all other schemes, let the download manager determine the filename.
+
+ return QString();
+}
+
+void DownloadControllerPrivate::startDownload(QNetworkReply * reply)
+{
+ QUrl url = reply->url();
+
+ Download * download = m_downloadManager->createDownload(reply);
+
+ startDownload(download, url);
+}
+
+void DownloadControllerPrivate::startDownload(const QNetworkRequest & request)
+{
+ QUrl url = request.url();
+
+ Download * download = m_downloadManager->createDownload(url.toString());
+
+ startDownload(download, url);
+}
+
+void DownloadControllerPrivate::startDownload(Download * download, const QUrl & url)
+{
+ // If necessary suggest an alternate file name.
+ // The download manager will adjust the file name for us to handle
+ // duplicates in the destination directory.
+
+ QString file = downloadFileName(url);
+
+ if (file.length() > 0) {
+ QVariant value(file);
+ download->setAttribute(DlFileName, value);
+ }
+
+ // Start download.
+
+ emit m_downloadController->downloadCreated(download);
+
+ download->registerEventReceiver(this);
+ download->start();
+}
+
+bool DownloadControllerPrivate::handleDownloadManagerEvent(DownloadEvent * event)
+{
+ DEventType type = static_cast<DEventType>(event->type());
+
+ switch (type) {
+ case DownloadCreated:
+ // Instead of waiting for the DownloadManager DownloadCreated event
+ // we emit downloadCreated in startDownload above so that we can add
+ // a pointer to the download created as a parameter.
+ return true;
+
+ case DownloadsCleared:
+ emit m_downloadController->downloadsCleared();
+ return true;
+
+ case ConnectedToServer:
+ case DisconnectedFromServer:
+ case ServerError:
+ return true;
+
+ default:
+ qDebug() << "Unexpected download manager event:" << type;
+ return false;
+ }
+}
+
+bool DownloadControllerPrivate::handleDownloadEvent(DownloadEvent * event)
+{
+ DEventType type = static_cast<DEventType>(event->type());
+
+ DownloadEvent * dlEvent = static_cast<DownloadEvent*>(event);
+
+ int dlId = dlEvent->getId();
+
+ Download * download = m_downloadManager->findDownload(dlId);
+
+ if (!download) {
+ qDebug() << "Cannot found download with id" << dlId;
+ return false;
+ }
+
+ int errorNum = download->getAttribute(DlLastError).toInt();
+
+ const char * errorStr = downloadErrorToString(
+ static_cast<QNetworkReply::NetworkError>(errorNum));
+
+ QString error;
+ if (errorStr != 0)
+ error = errorStr;
+
+ switch (type)
+ {
+ case Started:
+ emit m_downloadController->downloadStarted(download);
+ return true;
+
+ case HeaderReceived:
+ emit m_downloadController->downloadHeaderReceived(download);
+ return true;
+
+ case Progress:
+ emit m_downloadController->downloadProgress(download);
+ return true;
+
+ case Completed:
+ emit m_downloadController->downloadFinished(download);
+ return true;
+
+ case Paused:
+ emit m_downloadController->downloadPaused(download, error);
+ return true;
+
+ case Cancelled:
+ emit m_downloadController->downloadCancelled(download, error);
+ return true;
+
+ case Failed:
+ emit m_downloadController->downloadFailed(download, error);
+ return true;
+
+ case DescriptorUpdated:
+ // FIXME ;;; Update to support OMA and DRM.
+ return true;
+
+ case NetworkLoss:
+ emit m_downloadController->downloadNetworkLoss(download, error);
+ return true;
+
+ case Error:
+ emit m_downloadController->downloadError(download, error);
+ return true;
+
+ case OMADownloadDescriptorReady:
+ // FIXME ;;; Update to support OMA and DRM.
+ return true;
+
+ case WMDRMLicenseAcquiring:
+ // FIXME ;;; Update to support OMA and DRM.
+ return true;
+
+ default:
+ qDebug() << "Unexpected download event:" << type;
+ break;
+ }
+
+ return false;
+}
+
+bool DownloadControllerPrivate::event(QEvent * e)
+{
+ DownloadEvent * event = static_cast<DownloadEvent *>(e);
+
+ DEventType type = static_cast<DEventType>(event->type());
+
+ debugDownloadEvent(type);
+
+ switch (type) {
+ case DownloadCreated:
+ case DownloadsCleared:
+ case ConnectedToServer:
+ case DisconnectedFromServer:
+ case ServerError:
+ return handleDownloadManagerEvent(event);
+
+ case Started:
+ case HeaderReceived:
+ case Progress:
+ case Completed:
+ case Paused:
+ case Cancelled:
+ case Failed:
+ case DescriptorUpdated:
+ case NetworkLoss:
+ case Error:
+ case OMADownloadDescriptorReady:
+ case WMDRMLicenseAcquiring:
+ return handleDownloadEvent(event);
+
+ default:
+ return false;
+ }
+}
+
+// DownloadController implementation
+
+DownloadController::DownloadController(
+ const QString & client,
+ const QNetworkProxy & proxy)
+{
+ d = new DownloadControllerPrivate(this, client, proxy);
+}
+
+DownloadController::~DownloadController()
+{
+ delete d;
+}
+
+bool DownloadController::handlePage(QWebPage * page)
+{
+ bool succeeded = true;
+
+ // Handle click on link when the link type is not supported.
+ page->setForwardUnsupportedContent(true);
+ if (!connect(page, SIGNAL(unsupportedContent(QNetworkReply *)),
+ this, SLOT(startDownload(QNetworkReply *)))) {
+ succeeded = false;
+ };
+
+ // Handle Save Link and Save Image requests from the context menu.
+ if (!connect(page, SIGNAL(downloadRequested(const QNetworkRequest &)),
+ this, SLOT(startDownload(const QNetworkRequest &)))) {
+ succeeded = false;
+ }
+
+ return succeeded;
+}
+
+void DownloadController::startDownload(QNetworkReply * reply)
+{
+ QUrl url = reply->url();
+
+ qDebug() << "Download unsupported content" << url;
+
+ d->startDownload(reply);
+}
+
+void DownloadController::startDownload(const QNetworkRequest & request)
+{
+ QUrl url = request.url();
+
+ qDebug() << "Save link or image" << url;
+
+ d->startDownload(request);
+}
+
+#else // USE_DOWNLOAD_MANAGER
+
+// Empty implementation for when DownloadManager is unsupported.
+
+DownloadController::DownloadController(
+ const QString & client,
+ const QNetworkProxy & proxy)
+{}
+
+DownloadController::~DownloadController()
+{}
+
+bool DownloadController::handlePage(QWebPage * page)
+{
+ return true;
+}
+
+void DownloadController::startDownload(QNetworkReply * reply)
+{}
+
+void DownloadController::startDownload(const QNetworkRequest & request)
+{}
+
+#endif // USE_DOWNLOAD_MANAGER