Skip to content

Commit

Permalink
Catch exception when assiging String<> type with too long string (#966)
Browse files Browse the repository at this point in the history
* Catch exception when assiging String<> type with too long string
* Add choice between throw and truncating, also remove runtime length variable which can be done purely compile time
---------

Signed-off-by: Marc Emmers <[email protected]>
Signed-off-by: Marc Emmers <[email protected]>
Signed-off-by: Piet Gömpel <[email protected]>
Co-authored-by: Piet Gömpel <[email protected]>
  • Loading branch information
marcemmers and Pietfried authored Feb 14, 2025
1 parent fc107f3 commit 3283265
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 22 deletions.
8 changes: 4 additions & 4 deletions include/ocpp/common/cistring.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ template <size_t L> class CiString : public String<L> {

public:
/// \brief Creates a string from the given \p data
CiString(const std::string& data) : String<L>(data) {
CiString(const std::string& data, StringTooLarge to_large = StringTooLarge::Throw) : String<L>(data, to_large) {
}

CiString(const char* data) : String<L>(data) {
CiString(const char* data, StringTooLarge to_large = StringTooLarge::Throw) : String<L>(data, to_large) {
}

CiString(const CiString<L>& data) : String<L>(data.get()) {
Expand All @@ -35,8 +35,8 @@ template <size_t L> class CiString : public String<L> {
CiString& operator=(CiString&&) = default;

/// \brief CaseInsensitive string implementation only allows printable ASCII characters
bool is_valid(const std::string& data) {
for (const char& character : data) {
bool is_valid(std::string_view data) {
for (char character : data) {
// printable ASCII starts at code 0x20 (space) and ends with code 0x7e (tilde) and 0xa (\n)
if ((character < 0x20 || character > 0x7e) && character != 0xa) {
throw std::runtime_error("CiString can only contain printable ASCII characters");
Expand Down
45 changes: 29 additions & 16 deletions include/ocpp/common/string.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,33 @@

namespace ocpp {

class StringConversionException : public std::runtime_error {
using std::runtime_error::runtime_error;
};

enum class StringTooLarge {
Throw,
Truncate
};

/// \brief Contains a String impementation with a maximum length
template <size_t L> class String {
private:
std::string data;
size_t length;
static constexpr size_t length = L;

public:
/// \brief Creates a string from the given \p data
String(const std::string& data) : length(L) {
this->set(data);
explicit String(const std::string& data, StringTooLarge to_large = StringTooLarge::Throw) {
this->set(data, to_large);
}

String(const char* data) : length(L) {
this->set(data);
explicit String(const char* data, StringTooLarge to_large = StringTooLarge::Throw) {
this->set(data, to_large);
}

/// \brief Creates a string
String() : length(L) {
}
String() = default;

/// \brief Provides a std::string representation of the string
/// \returns a std::string
Expand All @@ -38,21 +46,26 @@ template <size_t L> class String {
}

/// \brief Sets the content of the string to the given \p data
void set(const std::string& data) {
if (data.length() <= this->length) {
if (this->is_valid(data)) {
this->data = data;
} else {
throw std::runtime_error("String has invalid format");
void set(const std::string& data, StringTooLarge to_large = StringTooLarge::Throw) {
std::string_view view = data;
if (view.length() > this->length) {
if (to_large == StringTooLarge::Throw) {
throw StringConversionException("String length (" + std::to_string(view.length()) +
") exceeds permitted length (" + std::to_string(this->length) + ")");
}
// Truncate
view = view.substr(0, length);
}

if (this->is_valid(view)) {
this->data = view;
} else {
throw std::runtime_error("String length (" + std::to_string(data.length()) +
") exceeds permitted length (" + std::to_string(this->length) + ")");
throw StringConversionException("String has invalid format");
}
}

/// \brief Override this to check for a specific format
bool is_valid(const std::string& data) {
bool is_valid(std::string_view data) {
(void)data; // not needed here
return true;
}
Expand Down
16 changes: 14 additions & 2 deletions lib/ocpp/v201/charge_point.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -832,15 +832,27 @@ void ChargePoint::message_callback(const std::string& message) {
this->message_dispatcher->dispatch_call_error(
CallError(MessageId("-1"), "RpcFrameworkError", e.what(), json({})));
const auto& security_event = ocpp::security_events::INVALIDMESSAGES;
this->security->security_event_notification_req(CiString<50>(security_event), CiString<255>(message), true,
this->security->security_event_notification_req(CiString<50>(security_event, StringTooLarge::Truncate),
CiString<255>(message, StringTooLarge::Truncate), true,
utils::is_critical(security_event));
return;
} catch (const StringConversionException& e) {
this->logging->central_system("Unknown", message);
EVLOG_error << "JSON exception during reception of message: " << e.what();
this->message_dispatcher->dispatch_call_error(
CallError(MessageId("-1"), "RpcFrameworkError", e.what(), json({})));
const auto& security_event = ocpp::security_events::INVALIDMESSAGES;
this->security->security_event_notification_req(CiString<50>(security_event, StringTooLarge::Truncate),
CiString<255>(message, StringTooLarge::Truncate), true,
utils::is_critical(security_event));
return;
} catch (const EnumConversionException& e) {
EVLOG_error << "EnumConversionException during handling of message: " << e.what();
auto call_error = CallError(MessageId("-1"), "FormationViolation", e.what(), json({}));
this->message_dispatcher->dispatch_call_error(call_error);
const auto& security_event = ocpp::security_events::INVALIDMESSAGES;
this->security->security_event_notification_req(CiString<50>(security_event), CiString<255>(message), true,
this->security->security_event_notification_req(CiString<50>(security_event, StringTooLarge::Truncate),
CiString<255>(message, StringTooLarge::Truncate), true,
utils::is_critical(security_event));
return;
}
Expand Down

0 comments on commit 3283265

Please sign in to comment.