/*! @file @id $Id$ */ // 1 2 3 4 5 6 7 8 // 45678901234567890123456789012345678901234567890123456789012345678901234567890 #ifndef __DOWNLOAD_MANAGER_HXX #define __DOWNLOAD_MANAGER_HXX #include #include #include #include #include #include #include //! @addtogroup qbrowserlib //! @{ namespace qbrowserlib { class DownloadManager: public QObject { Q_OBJECT; public: //! Append a Network Manager DownloadManager& operator+=(QNetworkAccessManager* n) { TRC; SslClientAuthNetworkAccessManager* n2 (dynamic_cast(n)); return operator+=(n2); } //! Append a Network Manager DownloadManager& operator+=(SslClientAuthNetworkAccessManager* n) { TRC; assert(connect(n, SIGNAL(created(QNetworkReply*)), SLOT(add(QNetworkReply*)))); return *this; } //! Append a Network Reply DownloadManager& operator+=(QNetworkReply* reply) { TRC; add(reply); return *this; } static QString networkError(QNetworkReply::NetworkError err) { TRC_FN; LOG_FN<url().toString(); LOG<&)), SLOT(sslErrors(const QList&)))); assert(connect(reply, SIGNAL(uploadProgress(qint64, qint64)), SLOT(uploadProgress(qint64, qint64)))); if (_downloads.size()==1) started(); } void abort() { while (_downloads.size()) _downloads.begin()->first->abort(); } private: void calcProgress() { //TRC; qint64 done(0); qint64 total(0); for (Downloads::iterator it(_downloads.begin()); it!=_downloads.end(); ++it) { done += it->second.progress.first; total += it->second.progress.second; } progress(done, total); } private Q_SLOTS: void downloadProgress(qint64 bytesReceived, qint64 bytesTotal) { //TRC; LOG<(sender())].progress.first = bytesReceived; _downloads[qobject_cast(sender())].progress.second = bytesTotal; calcProgress(); } void error(QNetworkReply::NetworkError code) { TRC; LOG<<"Status:"<(sender())); _downloads[reply].error += tr("

Network Error

" "
URL:
%1
" "
Error Code:
%3
" "
Error Details:
%2
") .arg(reply->url().toString()) .arg(networkError(code)) .arg(code); } void slotDestroyed(QObject* obj) { TRC; LOG<<_downloads.size(); _downloads.erase((QNetworkReply*)obj); } void slotFinished() { TRC; LOG<<_downloads.size(); QNetworkReply* reply(qobject_cast(sender())); if (_downloads[reply].error.size()) error(_downloads[reply].error); _downloads.erase(reply); if (_downloads.size()==0) finished(); } void slotMetaDataChanged() { TRC; QNetworkReply* reply(qobject_cast(sender())); if (!reply) return; LOG<<"Location:"<header(QNetworkRequest::LocationHeader) .toString(); LOG<<"Content-Type:"<header(QNetworkRequest::ContentTypeHeader) .toString(); LOG<<"Content-Disposition:"<rawHeader("Content-Disposition"); LOG<<"Status:"<error()); LOG<<"URL:"<url().toString(); LOG<<"File:"<url().toLocalFile(); LOG<<"Path:"<url().path(); metaDataChanged(reply); } void sslErrors(const QList & errors) { TRC; QNetworkReply* reply(qobject_cast(sender())); for (QList::const_iterator err(errors.begin()); err!=errors.end(); ++err) { LOG<<"SSL-Error: "<<(int)err->error()<<": "<errorString(); LOG<<"Certificate Issuer: " <<"O=" <certificate().issuerInfo(QSslCertificate::Organization) <<"CN="<certificate().issuerInfo(QSslCertificate::CommonName) <<"L=" <certificate().issuerInfo(QSslCertificate::LocalityName) <<"OU=" <certificate() .issuerInfo(QSslCertificate::OrganizationalUnitName) <<"C="<certificate().issuerInfo(QSslCertificate::CountryName) <<"ST=" <certificate() .issuerInfo(QSslCertificate::StateOrProvinceName); LOG<<"Certificate Subject: " <<"O=" <certificate().subjectInfo(QSslCertificate::Organization) <<"CN=" <certificate().subjectInfo(QSslCertificate::CommonName) <<"L=" <certificate().subjectInfo(QSslCertificate::LocalityName) <<"OU=" <certificate() .subjectInfo(QSslCertificate::OrganizationalUnitName) <<"C=" <certificate().subjectInfo(QSslCertificate::CountryName) <<"ST=" <certificate() .subjectInfo(QSslCertificate::StateOrProvinceName); LOG<<"Certificate:\n"<certificate().toPem(); switch (err->error()) { case QSslError::SelfSignedCertificate: case QSslError::SelfSignedCertificateInChain: { QSslConfiguration sslConfig (QSslConfiguration::defaultConfiguration()); QList certs(sslConfig.caCertificates()); for (QList::iterator cert(certs.begin()); cert!=certs.end(); ++cert) { if (err->certificate().subjectInfo(QSslCertificate::CommonName) == cert->subjectInfo(QSslCertificate::CommonName)) { LOG<<"Found matching CN:" <subjectInfo(QSslCertificate::CommonName); if (err->certificate()==*cert) { LOG<<"QT-BUG! Certificate matches known certificate"; //! @bug work around qt bug (Qt Mac 4.8.2) reply->ignoreSslErrors(errors); } else { LOG<<"CERTIFICATE ERROR! Certificates are different"; } } } } break; default:; // ignore } _downloads[reply].error += tr("

SSL Error

" "
URL:
%1
" "
Error Code:
%3
" "
Error Details:
%2
" "" "" "" "" "" "" "" "" "
Certificate Issuer
Organization:%4
Common Name:%5
Location:%6
Organizational Unit:%7
Country:%8
State or Provive:%9
" "" "" "" "" "" "" "" "" "
Certificate Subject
Organization:%10
Common Name:%11
Location:%12
Organizational Unit:%13
Country:%14
State or Province:%15
") .arg(reply->url().toString()) .arg(err->errorString()) .arg(err->error()) .arg(err->certificate().issuerInfo(QSslCertificate::Organization) #if QT_VERSION >= 0x050000 .join("
") #endif ) .arg(err->certificate().issuerInfo(QSslCertificate::CommonName) #if QT_VERSION >= 0x050000 .join("
") #endif ) .arg(err->certificate().issuerInfo(QSslCertificate::LocalityName) #if QT_VERSION >= 0x050000 .join("
") #endif ) .arg(err->certificate() .issuerInfo(QSslCertificate::OrganizationalUnitName) #if QT_VERSION >= 0x050000 .join("
") #endif ) .arg(err->certificate().issuerInfo(QSslCertificate::CountryName) #if QT_VERSION >= 0x050000 .join("
") #endif ) .arg(err->certificate() .issuerInfo(QSslCertificate::StateOrProvinceName) #if QT_VERSION >= 0x050000 .join("
") #endif ) .arg(err->certificate().subjectInfo(QSslCertificate::Organization) #if QT_VERSION >= 0x050000 .join("
") #endif ) .arg(err->certificate().subjectInfo(QSslCertificate::CommonName) #if QT_VERSION >= 0x050000 .join("
") #endif ) .arg(err->certificate().subjectInfo(QSslCertificate::LocalityName) #if QT_VERSION >= 0x050000 .join("
") #endif ) .arg(err->certificate() .subjectInfo(QSslCertificate::OrganizationalUnitName) #if QT_VERSION >= 0x050000 .join("
") #endif ) .arg(err->certificate().subjectInfo(QSslCertificate::CountryName) #if QT_VERSION >= 0x050000 .join("
") #endif ) .arg(err->certificate() .subjectInfo(QSslCertificate::StateOrProvinceName) #if QT_VERSION >= 0x050000 .join("
") #endif ); } } void uploadProgress(qint64 bytesSent, qint64 bytesTotal) { //TRC; LOG<(sender())].progress.first = bytesSent; _downloads[qobject_cast(sender())].progress.second = bytesTotal; calcProgress(); } private: typedef std::pair Progress; struct Download { Progress progress; QString error; }; typedef std::map Downloads; Downloads _downloads; }; } //! @} #endif