aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix (xq) Queißner <git@mq32.de>2020-06-16 23:01:16 +0200
committerFelix (xq) Queißner <git@mq32.de>2020-06-16 23:01:16 +0200
commit94dbe30902e36cedb30cb89ea3bd7ecd6c5a03f2 (patch)
tree98b32b834960a59102118630f4d936671081f6c7
parenta3f3e3933c4a2522e233917a6795c6e9d677e65c (diff)
downloadkristall-94dbe30902e36cedb30cb89ea3bd7ecd6c5a03f2.tar.gz
Adds improved error handling.
-rw-r--r--src/browsertab.cpp44
-rw-r--r--src/builtins.qrc14
-rw-r--r--src/error_page/BadRequest.gemini5
-rw-r--r--src/error_page/ConnectionRefused.gemini5
-rw-r--r--src/error_page/HostNotFound.gemini5
-rw-r--r--src/error_page/InternalServerError.gemini5
-rw-r--r--src/error_page/InvalidClientCertificate.gemini5
-rw-r--r--src/error_page/MistrustedHost.gemini7
-rw-r--r--src/error_page/ProtocolViolation.gemini5
-rw-r--r--src/error_page/ProxyRequest.gemini5
-rw-r--r--src/error_page/ResourceNotFound.gemini5
-rw-r--r--src/error_page/Timeout.gemini5
-rw-r--r--src/error_page/TlsFailure.gemini5
-rw-r--r--src/error_page/Unauthorized.gemini7
-rw-r--r--src/error_page/UnknownError.gemini5
-rw-r--r--src/error_page/UntrustedHost.gemini6
-rw-r--r--src/fingerclient.cpp11
-rw-r--r--src/fingerclient.hpp1
-rw-r--r--src/geminiclient.cpp11
-rw-r--r--src/gopherclient.cpp11
-rw-r--r--src/gopherclient.hpp4
-rw-r--r--src/protocolhandler.cpp30
-rw-r--r--src/protocolhandler.hpp11
-rw-r--r--src/webclient.cpp28
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();