Adds improved error handling.
This commit is contained in:
parent
a3f3e3933c
commit
94dbe30902
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
# Bad Request
|
||||
|
||||
Kristall tried to access the resource and made a mistake.
|
||||
|
||||
> %1
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
# Host Not Found
|
||||
|
||||
The server you tried to reach does not exist. Please verify that your URL is valid.
|
||||
|
||||
> %1
|
|
@ -0,0 +1,5 @@
|
|||
# Internal Server Error
|
||||
|
||||
The server failed to handle your request.
|
||||
|
||||
> %1
|
|
@ -0,0 +1,5 @@
|
|||
# Invalid Client Certificate
|
||||
|
||||
Your client certificate is not accepted by the server.
|
||||
|
||||
> %1
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
# Resource Not Found
|
||||
|
||||
The resource you requested is not available.
|
||||
|
||||
> %1
|
|
@ -0,0 +1,5 @@
|
|||
# Timeout
|
||||
|
||||
The server timed out while answering your response.
|
||||
|
||||
> %1
|
|
@ -0,0 +1,5 @@
|
|||
# TLS Failure
|
||||
|
||||
There was an error while negotiating the TLS encryption.
|
||||
|
||||
> %1
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue