moved more to qbrowserlib, added download manager functions; refs #167
parent
9d50e35895
commit
99bafe0aac
17 changed files with 1066 additions and 812 deletions
@ -1,304 +0,0 @@ |
|||||||
/*! @file
|
|
||||||
|
|
||||||
@id $Id$ |
|
||||||
*/ |
|
||||||
// 1 2 3 4 5 6 7 8
|
|
||||||
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
|
||||||
|
|
||||||
#ifndef __DOWNLOAD_MANAGER_HXX |
|
||||||
#define __DOWNLOAD_MANAGER_HXX |
|
||||||
|
|
||||||
#include <qbrowserlib/log.hxx> |
|
||||||
#include <QtNetwork/QNetworkReply> |
|
||||||
#include <QtNetwork/QSslError> |
|
||||||
#include <QtNetwork/QSslConfiguration> |
|
||||||
#include <map> |
|
||||||
|
|
||||||
#include <cassert> |
|
||||||
|
|
||||||
class DownloadManager: public QObject { |
|
||||||
Q_OBJECT; |
|
||||||
public: |
|
||||||
|
|
||||||
DownloadManager& operator+=(QNetworkReply* reply) { |
|
||||||
TRC; |
|
||||||
add(reply); |
|
||||||
return *this; |
|
||||||
} |
|
||||||
|
|
||||||
static QString networkError(QNetworkReply::NetworkError err) { |
|
||||||
TRC_FN; LOG<<err; |
|
||||||
switch (err) { |
|
||||||
case QNetworkReply::NoError: |
|
||||||
return tr("Network connection successful, remote host can be" |
|
||||||
" reached."); |
|
||||||
case QNetworkReply::ConnectionRefusedError: |
|
||||||
return tr("The remote server refused the connection (the server is" |
|
||||||
" not accepting requests)."); |
|
||||||
case QNetworkReply::RemoteHostClosedError: |
|
||||||
return tr("The remote server closed the connection prematurely," |
|
||||||
" before the entire reply was received and processed."); |
|
||||||
case QNetworkReply::HostNotFoundError: |
|
||||||
return tr("The remote host name was not found (invalid hostname)."); |
|
||||||
case QNetworkReply::TimeoutError: |
|
||||||
return tr("The connection to the remote server timed out."); |
|
||||||
case QNetworkReply::OperationCanceledError: |
|
||||||
return tr("The operation was canceled via calls to abort() or" |
|
||||||
" close() before it was finished."); |
|
||||||
case QNetworkReply::SslHandshakeFailedError: |
|
||||||
return tr("The SSL/TLS handshake failed and the encrypted channel" |
|
||||||
" could not be established. See SSL-Errors above."); |
|
||||||
case QNetworkReply::ProxyConnectionRefusedError: |
|
||||||
return tr("The connection to the proxy server was refused (the" |
|
||||||
" proxy server is not accepting requests)."); |
|
||||||
case QNetworkReply::ProxyConnectionClosedError: |
|
||||||
return tr("The proxy server closed the connection prematurely," |
|
||||||
" before the entire reply was received and processed."); |
|
||||||
case QNetworkReply::ProxyNotFoundError: |
|
||||||
return tr("The proxy host name was not found (invalid proxy" |
|
||||||
" hostname)."); |
|
||||||
case QNetworkReply::ProxyTimeoutError: |
|
||||||
return tr("The connection to the proxy timed out or the proxy did" |
|
||||||
" not reply in time to the request sent."); |
|
||||||
case QNetworkReply::ProxyAuthenticationRequiredError: |
|
||||||
return tr("The proxy requires authentication in order to honour the" |
|
||||||
" request but did not accept any credentials offered" |
|
||||||
" (if any)."); |
|
||||||
case QNetworkReply::ContentAccessDenied: |
|
||||||
return tr("The access to the remote content was denied (similar to" |
|
||||||
" HTTP error 401)."); |
|
||||||
case QNetworkReply::ContentOperationNotPermittedError: |
|
||||||
return tr("The operation requested on the remote content is not" |
|
||||||
" permitted."); |
|
||||||
case QNetworkReply::ContentNotFoundError: |
|
||||||
return tr("The remote content was not found at the server (similar" |
|
||||||
" to HTTP error 404)."); |
|
||||||
case QNetworkReply::AuthenticationRequiredError: |
|
||||||
return tr("The remote server requires authentication to serve the" |
|
||||||
" content but the credentials provided were not accepted" |
|
||||||
" (if any)."); |
|
||||||
case QNetworkReply::ProtocolUnknownError: |
|
||||||
return tr("The Network Access API cannot honor the request because" |
|
||||||
" the protocol is not known."); |
|
||||||
case QNetworkReply::ProtocolInvalidOperationError: |
|
||||||
return tr("The requested operation is invalid for this protocol."); |
|
||||||
case QNetworkReply::UnknownNetworkError: |
|
||||||
return tr("An unknown network-related error was detected."); |
|
||||||
case QNetworkReply::UnknownProxyError: |
|
||||||
return tr("An unknown proxy-related error was detected."); |
|
||||||
case QNetworkReply::UnknownContentError: |
|
||||||
return tr("An unknonwn error related to the remote content was" |
|
||||||
" detected."); |
|
||||||
case QNetworkReply::ProtocolFailure: |
|
||||||
return tr("A breakdown in protocol was detected (parsing error," |
|
||||||
" invalid or unexpected responses, etc.)."); |
|
||||||
default: |
|
||||||
return tr("Unknown network error (code: %1).").arg(err); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
Q_SIGNALS: |
|
||||||
|
|
||||||
void progress(qint64 done, qint64 total); |
|
||||||
void started(); |
|
||||||
void finished(); |
|
||||||
void error(QString); |
|
||||||
void metaDataChanged(QNetworkReply*); |
|
||||||
|
|
||||||
public Q_SLOTS: |
|
||||||
|
|
||||||
void add(QNetworkReply* reply) { |
|
||||||
TRC; LOG<<_downloads.size()<<reply->url().toString(); |
|
||||||
LOG<<reply; |
|
||||||
_downloads[reply].progress = Progress(0, 0); |
|
||||||
assert(connect(reply, SIGNAL(downloadProgress(qint64, qint64)), |
|
||||||
SLOT(downloadProgress(qint64, qint64)))); |
|
||||||
assert(connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), |
|
||||||
SLOT(error(QNetworkReply::NetworkError)))); |
|
||||||
assert(connect(reply, SIGNAL(destroyed(QObject*)), |
|
||||||
SLOT(slotDestroyed(QObject*)))); |
|
||||||
assert(connect(reply, SIGNAL(finished()), |
|
||||||
SLOT(slotFinished()))); |
|
||||||
assert(connect(reply, SIGNAL(metaDataChanged()), |
|
||||||
SLOT(slotMetaDataChanged()))); |
|
||||||
assert(connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), |
|
||||||
SLOT(sslErrors(const QList<QSslError>&)))); |
|
||||||
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<<bytesReceived<<bytesTotal;
|
|
||||||
_downloads[qobject_cast<QNetworkReply*>(sender())].progress.first |
|
||||||
= bytesReceived; |
|
||||||
_downloads[qobject_cast<QNetworkReply*>(sender())].progress.second |
|
||||||
= bytesTotal; |
|
||||||
calcProgress(); |
|
||||||
} |
|
||||||
void error(QNetworkReply::NetworkError code) { |
|
||||||
TRC; LOG<<"Status:"<<networkError(code); |
|
||||||
QNetworkReply* reply(qobject_cast<QNetworkReply*>(sender())); |
|
||||||
_downloads[reply].error += |
|
||||||
tr("<h1>Network Error</h1>" |
|
||||||
"<dl><dt>URL:</dt><dd>%1</dd>" |
|
||||||
"<dt>Error Code:</dt><dd>%3</dd>" |
|
||||||
"<dt>Error Details:</dt><dd>%2</dd></dl>") |
|
||||||
.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<QNetworkReply*>(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<QNetworkReply*>(sender())); |
|
||||||
if (!reply) return; |
|
||||||
LOG<<"Location:"<<reply->header(QNetworkRequest::LocationHeader) |
|
||||||
.toString(); |
|
||||||
LOG<<"Content-Type:"<<reply->header(QNetworkRequest::ContentTypeHeader) |
|
||||||
.toString(); |
|
||||||
LOG<<"Content-Disposition:"<<reply->rawHeader("Content-Disposition"); |
|
||||||
LOG<<"Status:"<<networkError(reply->error()); |
|
||||||
LOG<<"URL:"<<reply->url().toString(); |
|
||||||
LOG<<"File:"<<reply->url().toLocalFile(); |
|
||||||
LOG<<"Path:"<<reply->url().path(); |
|
||||||
metaDataChanged(reply); |
|
||||||
} |
|
||||||
void sslErrors(const QList<QSslError> & errors) { |
|
||||||
TRC; |
|
||||||
QNetworkReply* reply(qobject_cast<QNetworkReply*>(sender())); |
|
||||||
for (QList<QSslError>::const_iterator err(errors.begin()); |
|
||||||
err!=errors.end(); ++err) { |
|
||||||
LOG<<"SSL-Error: "<<(int)err->error()<<": "<<err->errorString(); |
|
||||||
LOG<<"Certificate Issuer: " |
|
||||||
<<"O="<<err->certificate().issuerInfo(QSslCertificate::Organization) |
|
||||||
<<"CN="<<err->certificate().issuerInfo(QSslCertificate::CommonName) |
|
||||||
<<"L="<<err->certificate().issuerInfo(QSslCertificate::LocalityName) |
|
||||||
<<"OU="<<err->certificate().issuerInfo(QSslCertificate::OrganizationalUnitName) |
|
||||||
<<"C="<<err->certificate().issuerInfo(QSslCertificate::CountryName) |
|
||||||
<<"ST="<<err->certificate().issuerInfo(QSslCertificate::StateOrProvinceName); |
|
||||||
LOG<<"Certificate Subject: " |
|
||||||
<<"O="<<err->certificate().subjectInfo(QSslCertificate::Organization) |
|
||||||
<<"CN="<<err->certificate().subjectInfo(QSslCertificate::CommonName) |
|
||||||
<<"L="<<err->certificate().subjectInfo(QSslCertificate::LocalityName) |
|
||||||
<<"OU="<<err->certificate().subjectInfo(QSslCertificate::OrganizationalUnitName) |
|
||||||
<<"C="<<err->certificate().subjectInfo(QSslCertificate::CountryName) |
|
||||||
<<"ST="<<err->certificate().subjectInfo(QSslCertificate::StateOrProvinceName); |
|
||||||
LOG<<"Certificate:\n"<<err->certificate().toPem(); |
|
||||||
switch (err->error()) { |
|
||||||
case QSslError::SelfSignedCertificate: |
|
||||||
case QSslError::SelfSignedCertificateInChain: { |
|
||||||
QSslConfiguration sslConfig |
|
||||||
(QSslConfiguration::defaultConfiguration()); |
|
||||||
QList<QSslCertificate> certs(sslConfig.caCertificates()); |
|
||||||
for (QList<QSslCertificate>::iterator cert(certs.begin()); |
|
||||||
cert!=certs.end(); ++cert) { |
|
||||||
if (err->certificate().subjectInfo(QSslCertificate::CommonName) == |
|
||||||
cert->subjectInfo(QSslCertificate::CommonName)) { |
|
||||||
LOG<<"Found matching CN:" |
|
||||||
<<cert->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("<h1>SSL Error</h1>" |
|
||||||
"<dl><dt>URL:</dt><dd>%1</dd>" |
|
||||||
"<dt>Error Code:</dt><dd>%3</dd>" |
|
||||||
"<dt>Error Details:</dt><dd>%2</dd></dl>" |
|
||||||
"<table>" |
|
||||||
"<caption>Certificate Issuer</caption>" |
|
||||||
"<tr><th>Organization:</th><td>%4</td></tr>" |
|
||||||
"<tr><th>Common Name:</th><td>%5</td></tr>" |
|
||||||
"<tr><th>Location:</th><td>%6</td></tr>" |
|
||||||
"<tr><th>Organizational Unit:</th><td>%7</td></tr>" |
|
||||||
"<tr><th>Country:</th><td>%8</td></tr>" |
|
||||||
"<tr><th>State or Provive:</th><td>%9</td></tr>" |
|
||||||
"</table>" |
|
||||||
"<table>" |
|
||||||
"<caption>Certificate Subject</caption>" |
|
||||||
"<tr><th>Organization:</th><td>%10</td></tr>" |
|
||||||
"<tr><th>Common Name:</th><td>%11</td></tr>" |
|
||||||
"<tr><th>Location:</th><td>%12</td></tr>" |
|
||||||
"<tr><th>Organizational Unit:</th><td>%13</td></tr>" |
|
||||||
"<tr><th>Country:</th><td>%14</td></tr>" |
|
||||||
"<tr><th>State or Province:</th><td>%15</td></tr>" |
|
||||||
"</table>") |
|
||||||
.arg(reply->url().toString()) |
|
||||||
.arg(err->errorString()) |
|
||||||
.arg(err->error()) |
|
||||||
.arg(err->certificate().issuerInfo(QSslCertificate::Organization)) |
|
||||||
.arg(err->certificate().issuerInfo(QSslCertificate::CommonName)) |
|
||||||
.arg(err->certificate().issuerInfo(QSslCertificate::LocalityName)) |
|
||||||
.arg(err->certificate().issuerInfo(QSslCertificate::OrganizationalUnitName)) |
|
||||||
.arg(err->certificate().issuerInfo(QSslCertificate::CountryName)) |
|
||||||
.arg(err->certificate().issuerInfo(QSslCertificate::StateOrProvinceName)) |
|
||||||
.arg(err->certificate().subjectInfo(QSslCertificate::Organization)) |
|
||||||
.arg(err->certificate().subjectInfo(QSslCertificate::CommonName)) |
|
||||||
.arg(err->certificate().subjectInfo(QSslCertificate::LocalityName)) |
|
||||||
.arg(err->certificate().subjectInfo(QSslCertificate::OrganizationalUnitName)) |
|
||||||
.arg(err->certificate().subjectInfo(QSslCertificate::CountryName)) |
|
||||||
.arg(err->certificate().subjectInfo(QSslCertificate::StateOrProvinceName)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void uploadProgress(qint64 bytesSent, qint64 bytesTotal) { |
|
||||||
//TRC; LOG<<bytesSent<<bytesTotal;
|
|
||||||
_downloads[qobject_cast<QNetworkReply*>(sender())].progress.first |
|
||||||
= bytesSent; |
|
||||||
_downloads[qobject_cast<QNetworkReply*>(sender())].progress.second |
|
||||||
= bytesTotal; |
|
||||||
calcProgress(); |
|
||||||
} |
|
||||||
|
|
||||||
private: |
|
||||||
|
|
||||||
typedef std::pair<qint64, qint64> Progress; |
|
||||||
struct Download { |
|
||||||
Progress progress; |
|
||||||
QString error; |
|
||||||
}; |
|
||||||
typedef std::map<QNetworkReply*, Download> Downloads; |
|
||||||
|
|
||||||
Downloads _downloads; |
|
||||||
}; |
|
||||||
#endif |
|
@ -1,42 +0,0 @@ |
|||||||
/*! @file
|
|
||||||
|
|
||||||
@id $Id$ |
|
||||||
*/ |
|
||||||
// 1 2 3 4 5 6 7 8
|
|
||||||
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
|
||||||
|
|
||||||
#ifndef ERRORLOG_HXX |
|
||||||
#define ERRORLOG_HXX |
|
||||||
|
|
||||||
#include <qbrowserlib/log.hxx> |
|
||||||
#include <ui_errorlog.h> |
|
||||||
#include <QtGui/QDialog> |
|
||||||
|
|
||||||
class ErrorLog: public QDialog, protected Ui::ErrorLog { |
|
||||||
public: |
|
||||||
Q_OBJECT; |
|
||||||
Q_SIGNALS: |
|
||||||
void reset(); |
|
||||||
public: |
|
||||||
ErrorLog(QWidget* p): QDialog(p) { |
|
||||||
TRC; |
|
||||||
setupUi(this); |
|
||||||
} |
|
||||||
void append(QString text) { |
|
||||||
TRC; LOG<<text; |
|
||||||
_errors->append(text); |
|
||||||
} |
|
||||||
protected Q_SLOTS: |
|
||||||
void on__buttons_clicked(QAbstractButton* button) { |
|
||||||
TRC; |
|
||||||
switch (_buttons->buttonRole(button)) { |
|
||||||
case QDialogButtonBox::ResetRole: { |
|
||||||
_errors->clear(); |
|
||||||
reset(); |
|
||||||
} break; |
|
||||||
default:; |
|
||||||
} |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
#endif |
|
@ -0,0 +1,341 @@ |
|||||||
|
/*! @file
|
||||||
|
|
||||||
|
@id $Id$ |
||||||
|
*/ |
||||||
|
// 1 2 3 4 5 6 7 8
|
||||||
|
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||||
|
|
||||||
|
#ifndef __DOWNLOAD_MANAGER_HXX |
||||||
|
#define __DOWNLOAD_MANAGER_HXX |
||||||
|
|
||||||
|
#include <qbrowserlib/log.hxx> |
||||||
|
#include <QtNetwork/QNetworkReply> |
||||||
|
#include <QtNetwork/QSslError> |
||||||
|
#include <QtNetwork/QSslConfiguration> |
||||||
|
#include <map> |
||||||
|
|
||||||
|
#include <cassert> |
||||||
|
|
||||||
|
//! @addtogroup qbrowserlib
|
||||||
|
//! @{
|
||||||
|
namespace qbrowserlib { |
||||||
|
|
||||||
|
class DownloadManager: public QObject { |
||||||
|
|
||||||
|
Q_OBJECT; |
||||||
|
|
||||||
|
public: |
||||||
|
|
||||||
|
//! Append a Network Manager
|
||||||
|
DownloadManager& operator+=(QNetworkAccessManager* 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<<err; |
||||||
|
switch (err) { |
||||||
|
case QNetworkReply::NoError: |
||||||
|
return tr("Network connection successful, remote host can be" |
||||||
|
" reached."); |
||||||
|
case QNetworkReply::ConnectionRefusedError: |
||||||
|
return tr("The remote server refused the connection (the server is" |
||||||
|
" not accepting requests)."); |
||||||
|
case QNetworkReply::RemoteHostClosedError: |
||||||
|
return tr("The remote server closed the connection prematurely," |
||||||
|
" before the entire reply was received and processed."); |
||||||
|
case QNetworkReply::HostNotFoundError: |
||||||
|
return tr("The remote host name was not found (invalid hostname)."); |
||||||
|
case QNetworkReply::TimeoutError: |
||||||
|
return tr("The connection to the remote server timed out."); |
||||||
|
case QNetworkReply::OperationCanceledError: |
||||||
|
return tr("The operation was canceled via calls to abort() or" |
||||||
|
" close() before it was finished."); |
||||||
|
case QNetworkReply::SslHandshakeFailedError: |
||||||
|
return tr("The SSL/TLS handshake failed and the encrypted channel" |
||||||
|
" could not be established. See SSL-Errors above."); |
||||||
|
case QNetworkReply::ProxyConnectionRefusedError: |
||||||
|
return tr("The connection to the proxy server was refused (the" |
||||||
|
" proxy server is not accepting requests)."); |
||||||
|
case QNetworkReply::ProxyConnectionClosedError: |
||||||
|
return tr("The proxy server closed the connection prematurely," |
||||||
|
" before the entire reply was received and processed."); |
||||||
|
case QNetworkReply::ProxyNotFoundError: |
||||||
|
return tr("The proxy host name was not found (invalid proxy" |
||||||
|
" hostname)."); |
||||||
|
case QNetworkReply::ProxyTimeoutError: |
||||||
|
return tr("The connection to the proxy timed out or the proxy did" |
||||||
|
" not reply in time to the request sent."); |
||||||
|
case QNetworkReply::ProxyAuthenticationRequiredError: |
||||||
|
return tr("The proxy requires authentication in order to honour the" |
||||||
|
" request but did not accept any credentials offered" |
||||||
|
" (if any)."); |
||||||
|
case QNetworkReply::ContentAccessDenied: |
||||||
|
return tr("The access to the remote content was denied (similar to" |
||||||
|
" HTTP error 401)."); |
||||||
|
case QNetworkReply::ContentOperationNotPermittedError: |
||||||
|
return tr("The operation requested on the remote content is not" |
||||||
|
" permitted."); |
||||||
|
case QNetworkReply::ContentNotFoundError: |
||||||
|
return tr("The remote content was not found at the server (similar" |
||||||
|
" to HTTP error 404)."); |
||||||
|
case QNetworkReply::AuthenticationRequiredError: |
||||||
|
return tr("The remote server requires authentication to serve the" |
||||||
|
" content but the credentials provided were not accepted" |
||||||
|
" (if any)."); |
||||||
|
case QNetworkReply::ProtocolUnknownError: |
||||||
|
return tr("The Network Access API cannot honor the request because" |
||||||
|
" the protocol is not known."); |
||||||
|
case QNetworkReply::ProtocolInvalidOperationError: |
||||||
|
return tr("The requested operation is invalid for this protocol."); |
||||||
|
case QNetworkReply::UnknownNetworkError: |
||||||
|
return tr("An unknown network-related error was detected."); |
||||||
|
case QNetworkReply::UnknownProxyError: |
||||||
|
return tr("An unknown proxy-related error was detected."); |
||||||
|
case QNetworkReply::UnknownContentError: |
||||||
|
return tr("An unknonwn error related to the remote content was" |
||||||
|
" detected."); |
||||||
|
case QNetworkReply::ProtocolFailure: |
||||||
|
return tr("A breakdown in protocol was detected (parsing error," |
||||||
|
" invalid or unexpected responses, etc.)."); |
||||||
|
default: |
||||||
|
return tr("Unknown network error (code: %1).").arg(err); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Q_SIGNALS: |
||||||
|
|
||||||
|
void progress(qint64 done, qint64 total); |
||||||
|
void started(); |
||||||
|
void finished(); |
||||||
|
void error(QString); |
||||||
|
void metaDataChanged(QNetworkReply*); |
||||||
|
|
||||||
|
public Q_SLOTS: |
||||||
|
|
||||||
|
void add(QNetworkReply* reply) { |
||||||
|
TRC; LOG<<_downloads.size()<<reply->url().toString(); |
||||||
|
LOG<<reply; |
||||||
|
_downloads[reply].progress = Progress(0, 0); |
||||||
|
assert(connect(reply, SIGNAL(downloadProgress(qint64, qint64)), |
||||||
|
SLOT(downloadProgress(qint64, qint64)))); |
||||||
|
assert(connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), |
||||||
|
SLOT(error(QNetworkReply::NetworkError)))); |
||||||
|
assert(connect(reply, SIGNAL(destroyed(QObject*)), |
||||||
|
SLOT(slotDestroyed(QObject*)))); |
||||||
|
assert(connect(reply, SIGNAL(finished()), |
||||||
|
SLOT(slotFinished()))); |
||||||
|
assert(connect(reply, SIGNAL(metaDataChanged()), |
||||||
|
SLOT(slotMetaDataChanged()))); |
||||||
|
assert(connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), |
||||||
|
SLOT(sslErrors(const QList<QSslError>&)))); |
||||||
|
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<<bytesReceived<<bytesTotal;
|
||||||
|
_downloads[qobject_cast<QNetworkReply*>(sender())].progress.first |
||||||
|
= bytesReceived; |
||||||
|
_downloads[qobject_cast<QNetworkReply*>(sender())].progress.second |
||||||
|
= bytesTotal; |
||||||
|
calcProgress(); |
||||||
|
} |
||||||
|
void error(QNetworkReply::NetworkError code) { |
||||||
|
TRC; LOG<<"Status:"<<networkError(code); |
||||||
|
QNetworkReply* reply(qobject_cast<QNetworkReply*>(sender())); |
||||||
|
_downloads[reply].error += |
||||||
|
tr("<h1>Network Error</h1>" |
||||||
|
"<dl><dt>URL:</dt><dd>%1</dd>" |
||||||
|
"<dt>Error Code:</dt><dd>%3</dd>" |
||||||
|
"<dt>Error Details:</dt><dd>%2</dd></dl>") |
||||||
|
.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<QNetworkReply*>(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<QNetworkReply*>(sender())); |
||||||
|
if (!reply) return; |
||||||
|
LOG<<"Location:"<<reply->header(QNetworkRequest::LocationHeader) |
||||||
|
.toString(); |
||||||
|
LOG<<"Content-Type:"<<reply->header(QNetworkRequest::ContentTypeHeader) |
||||||
|
.toString(); |
||||||
|
LOG<<"Content-Disposition:"<<reply->rawHeader("Content-Disposition"); |
||||||
|
LOG<<"Status:"<<networkError(reply->error()); |
||||||
|
LOG<<"URL:"<<reply->url().toString(); |
||||||
|
LOG<<"File:"<<reply->url().toLocalFile(); |
||||||
|
LOG<<"Path:"<<reply->url().path(); |
||||||
|
metaDataChanged(reply); |
||||||
|
} |
||||||
|
void sslErrors(const QList<QSslError> & errors) { |
||||||
|
TRC; |
||||||
|
QNetworkReply* reply(qobject_cast<QNetworkReply*>(sender())); |
||||||
|
for (QList<QSslError>::const_iterator err(errors.begin()); |
||||||
|
err!=errors.end(); ++err) { |
||||||
|
LOG<<"SSL-Error: "<<(int)err->error()<<": "<<err->errorString(); |
||||||
|
LOG<<"Certificate Issuer: " |
||||||
|
<<"O=" |
||||||
|
<<err->certificate().issuerInfo(QSslCertificate::Organization) |
||||||
|
<<"CN="<<err->certificate().issuerInfo(QSslCertificate::CommonName) |
||||||
|
<<"L=" |
||||||
|
<<err->certificate().issuerInfo(QSslCertificate::LocalityName) |
||||||
|
<<"OU=" |
||||||
|
<<err->certificate() |
||||||
|
.issuerInfo(QSslCertificate::OrganizationalUnitName) |
||||||
|
<<"C="<<err->certificate().issuerInfo(QSslCertificate::CountryName) |
||||||
|
<<"ST=" |
||||||
|
<<err->certificate() |
||||||
|
.issuerInfo(QSslCertificate::StateOrProvinceName); |
||||||
|
LOG<<"Certificate Subject: " |
||||||
|
<<"O=" |
||||||
|
<<err->certificate().subjectInfo(QSslCertificate::Organization) |
||||||
|
<<"CN=" |
||||||
|
<<err->certificate().subjectInfo(QSslCertificate::CommonName) |
||||||
|
<<"L=" |
||||||
|
<<err->certificate().subjectInfo(QSslCertificate::LocalityName) |
||||||
|
<<"OU=" |
||||||
|
<<err->certificate() |
||||||
|
.subjectInfo(QSslCertificate::OrganizationalUnitName) |
||||||
|
<<"C=" |
||||||
|
<<err->certificate().subjectInfo(QSslCertificate::CountryName) |
||||||
|
<<"ST=" |
||||||
|
<<err->certificate() |
||||||
|
.subjectInfo(QSslCertificate::StateOrProvinceName); |
||||||
|
LOG<<"Certificate:\n"<<err->certificate().toPem(); |
||||||
|
switch (err->error()) { |
||||||
|
case QSslError::SelfSignedCertificate: |
||||||
|
case QSslError::SelfSignedCertificateInChain: { |
||||||
|
QSslConfiguration sslConfig |
||||||
|
(QSslConfiguration::defaultConfiguration()); |
||||||
|
QList<QSslCertificate> certs(sslConfig.caCertificates()); |
||||||
|
for (QList<QSslCertificate>::iterator cert(certs.begin()); |
||||||
|
cert!=certs.end(); ++cert) { |
||||||
|
if (err->certificate().subjectInfo(QSslCertificate::CommonName) |
||||||
|
== cert->subjectInfo(QSslCertificate::CommonName)) { |
||||||
|
LOG<<"Found matching CN:" |
||||||
|
<<cert->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("<h1>SSL Error</h1>" |
||||||
|
"<dl><dt>URL:</dt><dd>%1</dd>" |
||||||
|
"<dt>Error Code:</dt><dd>%3</dd>" |
||||||
|
"<dt>Error Details:</dt><dd>%2</dd></dl>" |
||||||
|
"<table>" |
||||||
|
"<caption>Certificate Issuer</caption>" |
||||||
|
"<tr><th>Organization:</th><td>%4</td></tr>" |
||||||
|
"<tr><th>Common Name:</th><td>%5</td></tr>" |
||||||
|
"<tr><th>Location:</th><td>%6</td></tr>" |
||||||
|
"<tr><th>Organizational Unit:</th><td>%7</td></tr>" |
||||||
|
"<tr><th>Country:</th><td>%8</td></tr>" |
||||||
|
"<tr><th>State or Provive:</th><td>%9</td></tr>" |
||||||
|
"</table>" |
||||||
|
"<table>" |
||||||
|
"<caption>Certificate Subject</caption>" |
||||||
|
"<tr><th>Organization:</th><td>%10</td></tr>" |
||||||
|
"<tr><th>Common Name:</th><td>%11</td></tr>" |
||||||
|
"<tr><th>Location:</th><td>%12</td></tr>" |
||||||
|
"<tr><th>Organizational Unit:</th><td>%13</td></tr>" |
||||||
|
"<tr><th>Country:</th><td>%14</td></tr>" |
||||||
|
"<tr><th>State or Province:</th><td>%15</td></tr>" |
||||||
|
"</table>") |
||||||
|
.arg(reply->url().toString()) |
||||||
|
.arg(err->errorString()) |
||||||
|
.arg(err->error()) |
||||||
|
.arg(err->certificate().issuerInfo(QSslCertificate::Organization)) |
||||||
|
.arg(err->certificate().issuerInfo(QSslCertificate::CommonName)) |
||||||
|
.arg(err->certificate().issuerInfo(QSslCertificate::LocalityName)) |
||||||
|
.arg(err->certificate() |
||||||
|
.issuerInfo(QSslCertificate::OrganizationalUnitName)) |
||||||
|
.arg(err->certificate().issuerInfo(QSslCertificate::CountryName)) |
||||||
|
.arg(err->certificate() |
||||||
|
.issuerInfo(QSslCertificate::StateOrProvinceName)) |
||||||
|
.arg(err->certificate().subjectInfo(QSslCertificate::Organization)) |
||||||
|
.arg(err->certificate().subjectInfo(QSslCertificate::CommonName)) |
||||||
|
.arg(err->certificate().subjectInfo(QSslCertificate::LocalityName)) |
||||||
|
.arg(err->certificate() |
||||||
|
.subjectInfo(QSslCertificate::OrganizationalUnitName)) |
||||||
|
.arg(err->certificate().subjectInfo(QSslCertificate::CountryName)) |
||||||
|
.arg(err->certificate() |
||||||
|
.subjectInfo(QSslCertificate::StateOrProvinceName)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void uploadProgress(qint64 bytesSent, qint64 bytesTotal) { |
||||||
|
//TRC; LOG<<bytesSent<<bytesTotal;
|
||||||
|
_downloads[qobject_cast<QNetworkReply*>(sender())].progress.first |
||||||
|
= bytesSent; |
||||||
|
_downloads[qobject_cast<QNetworkReply*>(sender())].progress.second |
||||||
|
= bytesTotal; |
||||||
|
calcProgress(); |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
|
||||||
|
typedef std::pair<qint64, qint64> Progress; |
||||||
|
struct Download { |
||||||
|
Progress progress; |
||||||
|
QString error; |
||||||
|
}; |
||||||
|
typedef std::map<QNetworkReply*, Download> Downloads; |
||||||
|
|
||||||
|
Downloads _downloads; |
||||||
|
}; |
||||||
|
|
||||||
|
}
|
||||||
|
//! @}
|
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,59 @@ |
|||||||
|
/*! @file
|
||||||
|
|
||||||
|
@id $Id$ |
||||||
|
*/ |
||||||
|
// 1 2 3 4 5 6 7 8
|
||||||
|
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||||
|
|
||||||
|
#ifndef ERRORLOG_HXX |
||||||
|
#define ERRORLOG_HXX |
||||||
|
|
||||||
|
#include <qbrowserlib/log.hxx> |
||||||
|
#include <qbrowserlib/ui_errorlog.h> |
||||||
|
#include <QtGui/QDialog> |
||||||
|
|
||||||
|
//! @addtogroup qbrowserlib
|
||||||
|
//! @{
|
||||||
|
|
||||||
|
namespace qbrowserlib { |
||||||
|
|
||||||
|
//! Collect and Show Errors
|
||||||
|
/*! Singleton */ |
||||||
|
class ErrorLog: public QDialog, protected Ui::ErrorLog { |
||||||
|
Q_OBJECT; |
||||||
|
Q_SIGNALS: |
||||||
|
void reset(); |
||||||
|
public: |
||||||
|
//! Singleton
|
||||||
|
static ErrorLog& instance(QWidget* p=0) { |
||||||
|
static ErrorLog _instance(p); |
||||||
|
return _instance; |
||||||
|
} |
||||||
|
private: // singleton
|
||||||
|
ErrorLog(const ErrorLog&); |
||||||
|
ErrorLog(QWidget* p): QDialog(p) { |
||||||
|
TRC; |
||||||
|
setupUi(this); |
||||||
|
} |
||||||
|
public: |
||||||
|
void append(QString text) { |
||||||
|
TRC; LOG<<text; |
||||||
|
_errors->append(text); |
||||||
|
} |
||||||
|
protected Q_SLOTS: |
||||||
|
void on__buttons_clicked(QAbstractButton* button) { |
||||||
|
TRC; |
||||||
|
switch (_buttons->buttonRole(button)) { |
||||||
|
case QDialogButtonBox::ResetRole: { |
||||||
|
_errors->clear(); |
||||||
|
reset(); |
||||||
|
} break; |
||||||
|
default:; |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
//! @}
|
||||||
|
|
||||||
|
#endif |
Loading…
Reference in new issue