diff options
| author | Felix (xq) Queißner <git@mq32.de> | 2020-06-16 23:01:16 +0200 |
|---|---|---|
| committer | Felix (xq) Queißner <git@mq32.de> | 2020-06-16 23:01:16 +0200 |
| commit | 94dbe30902e36cedb30cb89ea3bd7ecd6c5a03f2 (patch) | |
| tree | 98b32b834960a59102118630f4d936671081f6c7 | |
| parent | a3f3e3933c4a2522e233917a6795c6e9d677e65c (diff) | |
| download | kristall-94dbe30902e36cedb30cb89ea3bd7ecd6c5a03f2.tar.gz | |
Adds improved error handling.
| -rw-r--r-- | src/browsertab.cpp | 44 | ||||
| -rw-r--r-- | src/builtins.qrc | 14 | ||||
| -rw-r--r-- | src/error_page/BadRequest.gemini | 5 | ||||
| -rw-r--r-- | src/error_page/ConnectionRefused.gemini | 5 | ||||
| -rw-r--r-- | src/error_page/HostNotFound.gemini | 5 | ||||
| -rw-r--r-- | src/error_page/InternalServerError.gemini | 5 | ||||
| -rw-r--r-- | src/error_page/InvalidClientCertificate.gemini | 5 | ||||
| -rw-r--r-- | src/error_page/MistrustedHost.gemini | 7 | ||||
| -rw-r--r-- | src/error_page/ProtocolViolation.gemini | 5 | ||||
| -rw-r--r-- | src/error_page/ProxyRequest.gemini | 5 | ||||
| -rw-r--r-- | src/error_page/ResourceNotFound.gemini | 5 | ||||
| -rw-r--r-- | src/error_page/Timeout.gemini | 5 | ||||
| -rw-r--r-- | src/error_page/TlsFailure.gemini | 5 | ||||
| -rw-r--r-- | src/error_page/Unauthorized.gemini | 7 | ||||
| -rw-r--r-- | src/error_page/UnknownError.gemini | 5 | ||||
| -rw-r--r-- | src/error_page/UntrustedHost.gemini | 6 | ||||
| -rw-r--r-- | src/fingerclient.cpp | 11 | ||||
| -rw-r--r-- | src/fingerclient.hpp | 1 | ||||
| -rw-r--r-- | src/geminiclient.cpp | 11 | ||||
| -rw-r--r-- | src/gopherclient.cpp | 11 | ||||
| -rw-r--r-- | src/gopherclient.hpp | 4 | ||||
| -rw-r--r-- | src/protocolhandler.cpp | 30 | ||||
| -rw-r--r-- | src/protocolhandler.hpp | 11 | ||||
| -rw-r--r-- | src/webclient.cpp | 28 |
24 files changed, 226 insertions, 14 deletions
diff --git a/src/browsertab.cpp b/src/browsertab.cpp index 9e9b7b7..d7e2e6c 100644 --- a/src/browsertab.cpp +++ b/src/browsertab.cpp @@ -203,7 +203,39 @@ void BrowserTab::on_refresh_button_clicked() void BrowserTab::on_networkError(ProtocolHandler::NetworkError error_code, const QString &reason) { - this->setErrorMessage(QString("%1:\n%2").arg(error_code).arg(reason)); + QString file_name; + switch(error_code) + { + case ProtocolHandler::UnknownError: file_name = "UnknownError.gemini"; break; + case ProtocolHandler::ProtocolViolation: file_name = "ProtocolViolation.gemini"; break; + case ProtocolHandler::HostNotFound: file_name = "HostNotFound.gemini"; break; + case ProtocolHandler::ConnectionRefused: file_name = "ConnectionRefused.gemini"; break; + case ProtocolHandler::ResourceNotFound: file_name = "ResourceNotFound.gemini"; break; + case ProtocolHandler::BadRequest: file_name = "BadRequest.gemini"; break; + case ProtocolHandler::ProxyRequest: file_name = "ProxyRequest.gemini"; break; + case ProtocolHandler::InternalServerError: file_name = "InternalServerError.gemini"; break; + case ProtocolHandler::InvalidClientCertificate: file_name = "InvalidClientCertificate.gemini"; break; + case ProtocolHandler::UntrustedHost: file_name = "UntrustedHost.gemini"; break; + case ProtocolHandler::MistrustedHost: file_name = "MistrustedHost.gemini"; break; + case ProtocolHandler::Unauthorized: file_name = "Unauthorized.gemini"; break; + case ProtocolHandler::TlsFailure: file_name = "TlsFailure.gemini"; break; + case ProtocolHandler::Timeout: file_name = "Timeout.gemini"; break; + } + file_name = ":/error_page/" + file_name; + + QFile file_src { file_name }; + + if(not file_src.open(QFile::ReadOnly)) { + assert(false); + } + + auto contents = QString::fromUtf8(file_src.readAll()).arg(reason).toUtf8(); + + this->on_requestComplete( + contents, + "text/gemini"); + + this->updateUI(); } void BrowserTab::on_certificateRequired(const QString &reason) @@ -603,7 +635,7 @@ void BrowserTab::on_text_browser_customContextMenuRequested(const QPoint &pos) mainWindow->addNewTab(false, real_url); }); - connect(menu.addAction("Copy link"), &QAction::triggered, [this, real_url]() { + connect(menu.addAction("Copy link"), &QAction::triggered, [real_url]() { global_clipboard->setText(real_url.toString(QUrl::FullyEncoded)); }); @@ -614,6 +646,14 @@ void BrowserTab::on_text_browser_customContextMenuRequested(const QPoint &pos) this->ui->text_browser->selectAll(); }); + menu.addSeparator(); + + QAction * copy = menu.addAction("Copy to clipboard"); + copy->setShortcut(QKeySequence("Ctrl-C")); + connect(copy, &QAction::triggered, [this]() { + this->ui->text_browser->copy(); + }); + menu.exec(ui->text_browser->mapToGlobal(pos)); } diff --git a/src/builtins.qrc b/src/builtins.qrc index 35f1fe7..41b5965 100644 --- a/src/builtins.qrc +++ b/src/builtins.qrc @@ -3,5 +3,19 @@ <file>about/easter-egg.gemini</file> <file>about/help.gemini</file> <file>about/updates.gemini</file> + <file>error_page/BadRequest.gemini</file> + <file>error_page/ConnectionRefused.gemini</file> + <file>error_page/HostNotFound.gemini</file> + <file>error_page/InternalServerError.gemini</file> + <file>error_page/InvalidClientCertificate.gemini</file> + <file>error_page/MistrustedHost.gemini</file> + <file>error_page/ProtocolViolation.gemini</file> + <file>error_page/ProxyRequest.gemini</file> + <file>error_page/ResourceNotFound.gemini</file> + <file>error_page/Timeout.gemini</file> + <file>error_page/TlsFailure.gemini</file> + <file>error_page/Unauthorized.gemini</file> + <file>error_page/UnknownError.gemini</file> + <file>error_page/UntrustedHost.gemini</file> </qresource> </RCC> diff --git a/src/error_page/BadRequest.gemini b/src/error_page/BadRequest.gemini new file mode 100644 index 0000000..99d6c56 --- /dev/null +++ b/src/error_page/BadRequest.gemini @@ -0,0 +1,5 @@ +# Bad Request + +Kristall tried to access the resource and made a mistake. + +> %1 diff --git a/src/error_page/ConnectionRefused.gemini b/src/error_page/ConnectionRefused.gemini new file mode 100644 index 0000000..62e85e6 --- /dev/null +++ b/src/error_page/ConnectionRefused.gemini @@ -0,0 +1,5 @@ +# Connection Refused + +The server refused the connection. Please check that your URL is valid and that the server actually serves the files, then try again. + +> %1 diff --git a/src/error_page/HostNotFound.gemini b/src/error_page/HostNotFound.gemini new file mode 100644 index 0000000..4d52f49 --- /dev/null +++ b/src/error_page/HostNotFound.gemini @@ -0,0 +1,5 @@ +# Host Not Found + +The server you tried to reach does not exist. Please verify that your URL is valid. + +> %1 diff --git a/src/error_page/InternalServerError.gemini b/src/error_page/InternalServerError.gemini new file mode 100644 index 0000000..93f9f32 --- /dev/null +++ b/src/error_page/InternalServerError.gemini @@ -0,0 +1,5 @@ +# Internal Server Error + +The server failed to handle your request. + +> %1 diff --git a/src/error_page/InvalidClientCertificate.gemini b/src/error_page/InvalidClientCertificate.gemini new file mode 100644 index 0000000..e7699ec --- /dev/null +++ b/src/error_page/InvalidClientCertificate.gemini @@ -0,0 +1,5 @@ +# Invalid Client Certificate + +Your client certificate is not accepted by the server. + +> %1 diff --git a/src/error_page/MistrustedHost.gemini b/src/error_page/MistrustedHost.gemini new file mode 100644 index 0000000..7673de3 --- /dev/null +++ b/src/error_page/MistrustedHost.gemini @@ -0,0 +1,7 @@ +# Mistrusted Host + +The host you tried to visit does not look trustworty anymore. The certificate changed since your last visit. + +If you still trust this host, please revoke trust in the settings menu, then reload the page. + +> %1 diff --git a/src/error_page/ProtocolViolation.gemini b/src/error_page/ProtocolViolation.gemini new file mode 100644 index 0000000..0cf15ec --- /dev/null +++ b/src/error_page/ProtocolViolation.gemini @@ -0,0 +1,5 @@ +# Protocol Violation + +The server did not serve the content you requested in a well-defined manner and Kristall could not process the data sent. + +> %1 diff --git a/src/error_page/ProxyRequest.gemini b/src/error_page/ProxyRequest.gemini new file mode 100644 index 0000000..d2dc615 --- /dev/null +++ b/src/error_page/ProxyRequest.gemini @@ -0,0 +1,5 @@ +# Proxy Request + +You tried to request a resource from one host that is actually located on another host. Please verify your URL. + +> %1 diff --git a/src/error_page/ResourceNotFound.gemini b/src/error_page/ResourceNotFound.gemini new file mode 100644 index 0000000..d5d53de --- /dev/null +++ b/src/error_page/ResourceNotFound.gemini @@ -0,0 +1,5 @@ +# Resource Not Found + +The resource you requested is not available. + +> %1 diff --git a/src/error_page/Timeout.gemini b/src/error_page/Timeout.gemini new file mode 100644 index 0000000..d7bc704 --- /dev/null +++ b/src/error_page/Timeout.gemini @@ -0,0 +1,5 @@ +# Timeout + +The server timed out while answering your response. + +> %1 diff --git a/src/error_page/TlsFailure.gemini b/src/error_page/TlsFailure.gemini new file mode 100644 index 0000000..4e7dc02 --- /dev/null +++ b/src/error_page/TlsFailure.gemini @@ -0,0 +1,5 @@ +# TLS Failure + +There was an error while negotiating the TLS encryption. + +> %1 diff --git a/src/error_page/Unauthorized.gemini b/src/error_page/Unauthorized.gemini new file mode 100644 index 0000000..0251abe --- /dev/null +++ b/src/error_page/Unauthorized.gemini @@ -0,0 +1,7 @@ +# Unauthorized + +You are not authorized to access the requested resource. + +To solve this problem, you may enable a client certificate for gemini:// resources and try again. + +> %1 diff --git a/src/error_page/UnknownError.gemini b/src/error_page/UnknownError.gemini new file mode 100644 index 0000000..fd48fb7 --- /dev/null +++ b/src/error_page/UnknownError.gemini @@ -0,0 +1,5 @@ +# Unknown Error + +Kristall tried its best but it failed doing so. This is an error that is not handled by any special logic and bubbled up to you. That's sad. ☹ + +> %1 diff --git a/src/error_page/UntrustedHost.gemini b/src/error_page/UntrustedHost.gemini new file mode 100644 index 0000000..41c21c0 --- /dev/null +++ b/src/error_page/UntrustedHost.gemini @@ -0,0 +1,6 @@ +# Untrusted Host + +The host you tried to visit is not trusted by Kristall. If you do trust this server, please add it to the list of trusted certificates! +(which is currently not possible ☹) + +> %1 diff --git a/src/fingerclient.cpp b/src/fingerclient.cpp index 433e63b..13336b6 100644 --- a/src/fingerclient.cpp +++ b/src/fingerclient.cpp @@ -6,6 +6,12 @@ FingerClient::FingerClient() : ProtocolHandler(nullptr) connect(&socket, &QTcpSocket::connected, this, &FingerClient::on_connected); connect(&socket, &QTcpSocket::readyRead, this, &FingerClient::on_readRead); connect(&socket, &QTcpSocket::disconnected, this, &FingerClient::on_finished); + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) + connect(&socket, &QTcpSocket::errorOccurred, this, &FingerClient::on_socketError); +#else + connect(&socket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error), this, &FingerClient::on_socketError); +#endif } FingerClient::~FingerClient() @@ -68,3 +74,8 @@ void FingerClient::on_finished() } body.clear(); } + +void FingerClient::on_socketError(QAbstractSocket::SocketError error_code) +{ + this->emitNetworkError(error_code, socket.errorString()); +} diff --git a/src/fingerclient.hpp b/src/fingerclient.hpp index 87ddc7e..c0b94e2 100644 --- a/src/fingerclient.hpp +++ b/src/fingerclient.hpp @@ -27,6 +27,7 @@ private slots: void on_connected(); void on_readRead(); void on_finished(); + void on_socketError(QTcpSocket::SocketError error_code); private: QTcpSocket socket; diff --git a/src/geminiclient.cpp b/src/geminiclient.cpp index 8dff65b..c8a9642 100644 --- a/src/geminiclient.cpp +++ b/src/geminiclient.cpp @@ -10,7 +10,12 @@ GeminiClient::GeminiClient() : ProtocolHandler(nullptr) connect(&socket, &QSslSocket::readyRead, this, &GeminiClient::socketReadyRead); connect(&socket, &QSslSocket::disconnected, this, &GeminiClient::socketDisconnected); connect(&socket, QOverload<const QList<QSslError> &>::of(&QSslSocket::sslErrors), this, &GeminiClient::sslErrors); - connect(&socket, QOverload<QAbstractSocket::SocketError>::of(&QSslSocket::error), this, &GeminiClient::socketError); + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) + connect(&socket, &QTcpSocket::errorOccurred, this, &GeminiClient::socketError); +#else + connect(&socket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error), this, &GeminiClient::socketError); +#endif QSslConfiguration ssl_config; ssl_config.setProtocol(QSsl::TlsV1_2); @@ -318,8 +323,6 @@ void GeminiClient::socketError(QAbstractSocket::SocketError socketError) if(socketError == QAbstractSocket::RemoteHostClosedError) { socket.close(); } else { - // qWarning() << socketError << socket.errorString(); - // TODO: Make the correct error here! - emit this->networkError(HostNotFound, socket.errorString()); + this->emitNetworkError(socketError, socket.errorString()); } } diff --git a/src/gopherclient.cpp b/src/gopherclient.cpp index 6b19b02..2f6f31d 100644 --- a/src/gopherclient.cpp +++ b/src/gopherclient.cpp @@ -6,6 +6,12 @@ GopherClient::GopherClient(QObject *parent) : ProtocolHandler(parent) connect(&socket, &QTcpSocket::connected, this, &GopherClient::on_connected); connect(&socket, &QTcpSocket::readyRead, this, &GopherClient::on_readRead); connect(&socket, &QTcpSocket::disconnected, this, &GopherClient::on_finished); + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) + connect(&socket, &QTcpSocket::errorOccurred, this, &GopherClient::on_socketError); +#else + connect(&socket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error), this, &GopherClient::on_socketError); +#endif } GopherClient::~GopherClient() @@ -92,3 +98,8 @@ void GopherClient::on_finished() } body.clear(); } + +void GopherClient::on_socketError(QAbstractSocket::SocketError error_code) +{ + this->emitNetworkError(error_code, socket.errorString()); +} diff --git a/src/gopherclient.hpp b/src/gopherclient.hpp index 2ead2c4..f750d7b 100644 --- a/src/gopherclient.hpp +++ b/src/gopherclient.hpp @@ -23,10 +23,12 @@ public: bool cancelRequest() override; -private slots: +private: // slots void on_connected(); void on_readRead(); void on_finished(); + void on_socketError(QAbstractSocket::SocketError errorCode); + private: QTcpSocket socket; diff --git a/src/protocolhandler.cpp b/src/protocolhandler.cpp index 5a87bac..6a3bd92 100644 --- a/src/protocolhandler.cpp +++ b/src/protocolhandler.cpp @@ -2,7 +2,6 @@ ProtocolHandler::ProtocolHandler(QObject *parent) : QObject(parent) { - } bool ProtocolHandler::enableClientCertificate(const CryptoIdentity &ident) @@ -13,5 +12,34 @@ bool ProtocolHandler::enableClientCertificate(const CryptoIdentity &ident) void ProtocolHandler::disableClientCertificate() { +} +void ProtocolHandler::emitNetworkError(QAbstractSocket::SocketError error_code, const QString &textual_description) +{ + NetworkError network_error = UnknownError; + switch (error_code) + { + case QAbstractSocket::ConnectionRefusedError: + network_error = ConnectionRefused; + break; + case QAbstractSocket::HostNotFoundError: + network_error = HostNotFound; + break; + case QAbstractSocket::SocketTimeoutError: + network_error = Timeout; + break; + case QAbstractSocket::SslHandshakeFailedError: + network_error = TlsFailure; + break; + case QAbstractSocket::SslInternalError: + network_error = TlsFailure; + break; + case QAbstractSocket::SslInvalidUserDataError: + network_error = TlsFailure; + break; + default: + qDebug() << "unhandled network error:" << error_code; + break; + } + emit this->networkError(network_error, textual_description); } diff --git a/src/protocolhandler.hpp b/src/protocolhandler.hpp index f4ae9eb..f93ef87 100644 --- a/src/protocolhandler.hpp +++ b/src/protocolhandler.hpp @@ -1,10 +1,11 @@ #ifndef GENERICPROTOCOLCLIENT_HPP #define GENERICPROTOCOLCLIENT_HPP -#include <QObject> - #include "cryptoidentity.hpp" +#include <QObject> +#include <QAbstractSocket> + class ProtocolHandler : public QObject { Q_OBJECT @@ -12,7 +13,8 @@ public: enum NetworkError { UnknownError, //!< There was an unhandled network error ProtocolViolation, //!< The server responded with something unexpected and violated the protocol - HostNotFound, //!< The host + HostNotFound, //!< The host was not found by the client + ConnectionRefused, //!< The host refused connection on that port ResourceNotFound, //!< The requested resource was not found on the server BadRequest, //!< Our client misbehaved and did a request the server cannot understand ProxyRequest, //!< We requested to @@ -22,6 +24,7 @@ public: MistrustedHost, //!< We know the host and it's not the server identity we've seen before Unauthorized, //!< The requested resource could not be accessed. TlsFailure, //!< Unspecified TLS failure + Timeout, //!< The network connection timed out. }; public: explicit ProtocolHandler(QObject *parent = nullptr); @@ -54,6 +57,8 @@ signals: //! The server wants us to use a client certificate void certificateRequired(QString const & info); +protected: + void emitNetworkError(QAbstractSocket::SocketError error_code, QString const & textual_description); }; #endif // GENERICPROTOCOLCLIENT_HPP diff --git a/src/webclient.cpp b/src/webclient.cpp index b317692..40beec0 100644 --- a/src/webclient.cpp +++ b/src/webclient.cpp @@ -71,15 +71,36 @@ void WebClient::on_finished() { if(this->current_reply->error() != QNetworkReply::NoError) { + NetworkError error = UnknownError; + switch(this->current_reply->error()) + { + case QNetworkReply::ConnectionRefusedError: error = ConnectionRefused; break; + case QNetworkReply::RemoteHostClosedError: error = ProtocolViolation; break; + case QNetworkReply::HostNotFoundError: error = HostNotFound; break; + case QNetworkReply::TimeoutError: error = Timeout; break; + case QNetworkReply::SslHandshakeFailedError: error = TlsFailure; break; + + case QNetworkReply::ContentAccessDenied: error = Unauthorized; break; + case QNetworkReply::ContentOperationNotPermittedError: error = BadRequest; break; + case QNetworkReply::ContentNotFoundError: error = ResourceNotFound; break; + case QNetworkReply::AuthenticationRequiredError: error = Unauthorized; break; + case QNetworkReply::ContentGoneError: error = ResourceNotFound; break; + + case QNetworkReply::InternalServerError: error = InternalServerError; break; + case QNetworkReply::OperationNotImplementedError: error = InternalServerError; break; + case QNetworkReply::ServiceUnavailableError: error = InternalServerError; break; + default: + qDebug() << "Unhandled server error:" << this->current_reply->error(); + break; + } + qDebug() << "web network error" << this->current_reply->errorString(); - emit this->networkError(UnknownError, this->current_reply->errorString()); + emit this->networkError(error, this->current_reply->errorString()); } else { auto mime = this->current_reply->header(QNetworkRequest::ContentTypeHeader).toString(); - // qDebug() << this->current_reply->url() << mime; - emit this->requestComplete(this->body, mime); this->body.clear(); @@ -90,6 +111,7 @@ void WebClient::on_finished() void WebClient::on_sslErrors(const QList<QSslError> &errors) { + qDebug() << "HTTP SSL Errors:"; for(auto const & err : errors) qDebug() << err; this->current_reply->ignoreSslErrors(); |
