Skip to content

Commit f473ddf

Browse files
committed
feat(error-handling): add subcategories to fatal errors and display corresponding error messages
1 parent f3f20be commit f473ddf

17 files changed

+59
-46
lines changed

src/app/getcommandhandler.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ CommandHandler::ptr getCommandHandler(const CommandWithArguments& cmd)
4242
case CommandType::SIGN:
4343
return std::make_unique<Sign>(cmdCopy);
4444
default:
45-
throw std::invalid_argument("Unknown command '" + std::string(cmdType)
46-
+ "' in getCommandHandler()");
45+
throw ArgumentError("Unknown command '" + std::string(cmdType)
46+
+ "' in getCommandHandler()");
4747
}
4848
}

src/controller/application.hpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,6 @@
2626

2727
#include "commands.hpp"
2828

29-
class ArgumentError : public std::runtime_error
30-
{
31-
public:
32-
using std::runtime_error::runtime_error;
33-
};
34-
3529
class Application final : public QApplication
3630
{
3731
Q_OBJECT

src/controller/commands.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ CommandType commandNameToCommandType(const QString& cmdName)
4545
try {
4646
return SUPPORTED_COMMANDS.at(cmdName);
4747
} catch (const std::out_of_range&) {
48-
throw std::invalid_argument("Command '" + cmdName.toStdString() + "' is not supported");
48+
throw ArgumentError("Command '" + cmdName.toStdString() + "' is not supported");
4949
}
5050
}
5151

src/controller/commands.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,9 @@ CommandType commandNameToCommandType(const QString& cmdName);
6060

6161
using CommandWithArguments = std::pair<CommandType, QVariantMap>;
6262
using CommandWithArgumentsPtr = std::unique_ptr<CommandWithArguments>;
63+
64+
class ArgumentError : public std::runtime_error
65+
{
66+
public:
67+
using std::runtime_error::runtime_error;
68+
};

src/controller/controller.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@ using namespace electronic_id;
4444
namespace
4545
{
4646

47-
// TODO: Should we use more detailed error codes? E.g. report input data error back to the website
48-
// etc.
47+
const QString RESP_INVALID_ARGUMENT = QStringLiteral("ERR_WEBEID_INVALID_ARGUMENT");
4948
const QString RESP_TECH_ERROR = QStringLiteral("ERR_WEBEID_NATIVE_FATAL");
5049
const QString RESP_USER_CANCEL = QStringLiteral("ERR_WEBEID_USER_CANCELLED");
5150

@@ -99,7 +98,8 @@ void Controller::run()
9998
commandHandler = getCommandHandler(*command);
10099

101100
startCommandExecution();
102-
101+
} catch (const ArgumentError& error) {
102+
onCriticalFailureImpl(error.what(), FatalErrorType::ARGUMENT_ERROR);
103103
} catch (const std::exception& error) {
104104
onCriticalFailure(error.what());
105105
}
@@ -328,15 +328,22 @@ void Controller::onDialogCancel()
328328
}
329329

330330
void Controller::onCriticalFailure(const QString& error)
331+
{
332+
onCriticalFailureImpl(error, FatalErrorType::OTHER_ERROR);
333+
}
334+
335+
void Controller::onCriticalFailureImpl(const QString& error, const FatalErrorType errorType)
331336
{
332337
qCritical() << "Exiting due to command" << std::string(commandType())
333338
<< "fatal error:" << error;
334-
writeResponseToStdOut(isInStdinMode, makeErrorObject(RESP_TECH_ERROR, error), commandType());
339+
auto errorCode =
340+
errorType == FatalErrorType::ARGUMENT_ERROR ? RESP_INVALID_ARGUMENT : RESP_TECH_ERROR;
341+
writeResponseToStdOut(isInStdinMode, makeErrorObject(errorCode, error), commandType());
335342

336343
// Dispose the UI.
337344
window.reset();
338345

339-
WebEidUI::showFatalError();
346+
WebEidUI::showFatalError(errorType);
340347

341348
exit();
342349
}

src/controller/controller.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ class Controller : public QObject
8787
void connectRetry(const ControllerChildThread* childThread);
8888
void saveChildThreadPtrAndConnectFailureFinish(ControllerChildThread* childThread);
8989
void stopCardEventMonitorThread();
90+
void onCriticalFailureImpl(const QString& error,
91+
const FatalErrorType errorType = FatalErrorType::OTHER_ERROR);
9092
void exit();
9193
void waitForChildThreads();
9294
CommandType commandType();

src/controller/inputoutputmode.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222

2323
#include "inputoutputmode.hpp"
2424

25+
#include "pcsc-cpp/pcsc-cpp.hpp"
26+
#include "electronic-id/electronic-id.hpp"
27+
2528
#include <QJsonDocument>
2629
#include <QJsonObject>
2730

@@ -48,6 +51,7 @@ void setIoStreamsToBinaryMode()
4851
#endif
4952

5053
using namespace pcsc_cpp;
54+
using namespace electronic_id;
5155

5256
uint32_t readMessageLength(std::istream& input)
5357
{
@@ -71,15 +75,13 @@ CommandWithArgumentsPtr readCommandFromStdin()
7175
const auto messageLength = readMessageLength(std::cin);
7276

7377
if (messageLength < 5) {
74-
// FIXME: Pass errors back up to caller in stdin mode.
75-
throw std::invalid_argument("readCommandFromStdin: Message length is "
76-
+ std::to_string(messageLength) + ", at least 5 required");
78+
throw ArgumentError("readCommandFromStdin: Message length is "
79+
+ std::to_string(messageLength) + ", at least 5 required");
7780
}
7881

7982
if (messageLength > 8192) {
80-
throw std::invalid_argument("readCommandFromStdin: Message length "
81-
+ std::to_string(messageLength)
82-
+ " exceeds maximum allowed length 8192");
83+
throw ArgumentError("readCommandFromStdin: Message length " + std::to_string(messageLength)
84+
+ " exceeds maximum allowed length 8192");
8385
}
8486

8587
auto message = QByteArray(int(messageLength), '\0');
@@ -88,18 +90,16 @@ CommandWithArgumentsPtr readCommandFromStdin()
8890
const auto json = QJsonDocument::fromJson(message);
8991

9092
if (!json.isObject()) {
91-
// FIXME: Pass errors back up to caller in stdin mode.
92-
throw std::invalid_argument("readCommandFromStdin: Invalid JSON, not an object");
93+
throw ArgumentError("readCommandFromStdin: Invalid JSON, not an object");
9394
}
9495

9596
const auto jsonObject = json.object();
9697
const auto command = jsonObject["command"];
9798
const auto arguments = jsonObject["arguments"];
9899

99100
if (!command.isString() || !arguments.isObject()) {
100-
// FIXME: Pass errors back up to caller in stdin mode.
101-
throw std::invalid_argument("readCommandFromStdin: Invalid JSON, the main object does not "
102-
"contain a 'command' string and 'arguments' object");
101+
throw ArgumentError("readCommandFromStdin: Invalid JSON, the main object does not "
102+
"contain a 'command' string and 'arguments' object");
103103
}
104104

105105
return std::make_unique<CommandWithArguments>(commandNameToCommandType(command.toString()),

src/controller/inputoutputmode.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424

2525
#include "commands.hpp"
2626

27-
#include "pcsc-cpp/pcsc-cpp.hpp"
28-
2927
CommandWithArgumentsPtr readCommandFromStdin();
3028

3129
void writeResponseLength(std::ostream& stream, const uint32_t responseLength);

src/controller/retriableerror.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
#include <QMetaType>
2929
#include <QDebug>
3030

31+
// TODO: rename this file and .cpp to errors.{c,h}pp
32+
enum class FatalErrorType { PROGRAMMING_ERROR, ARGUMENT_ERROR, IO_ERROR, OTHER_ERROR };
33+
3134
enum class RetriableError {
3235
// libpcsc-cpp
3336
SMART_CARD_SERVICE_IS_NOT_RUNNING,

0 commit comments

Comments
 (0)