Skip to content

Commit 3283265

Browse files
Catch exception when assiging String<> type with too long string (#966)
* 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 <m.emmers@alfen.com> Signed-off-by: Marc Emmers <35759328+marcemmers@users.noreply.github.com> Signed-off-by: Piet Gömpel <pietgoempel@gmail.com> Co-authored-by: Piet Gömpel <pietgoempel@gmail.com>
1 parent fc107f3 commit 3283265

File tree

3 files changed

+47
-22
lines changed

3 files changed

+47
-22
lines changed

include/ocpp/common/cistring.hpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ template <size_t L> class CiString : public String<L> {
1717

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

23-
CiString(const char* data) : String<L>(data) {
23+
CiString(const char* data, StringTooLarge to_large = StringTooLarge::Throw) : String<L>(data, to_large) {
2424
}
2525

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

3737
/// \brief CaseInsensitive string implementation only allows printable ASCII characters
38-
bool is_valid(const std::string& data) {
39-
for (const char& character : data) {
38+
bool is_valid(std::string_view data) {
39+
for (char character : data) {
4040
// printable ASCII starts at code 0x20 (space) and ends with code 0x7e (tilde) and 0xa (\n)
4141
if ((character < 0x20 || character > 0x7e) && character != 0xa) {
4242
throw std::runtime_error("CiString can only contain printable ASCII characters");

include/ocpp/common/string.hpp

+29-16
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,33 @@
1111

1212
namespace ocpp {
1313

14+
class StringConversionException : public std::runtime_error {
15+
using std::runtime_error::runtime_error;
16+
};
17+
18+
enum class StringTooLarge {
19+
Throw,
20+
Truncate
21+
};
22+
1423
/// \brief Contains a String impementation with a maximum length
1524
template <size_t L> class String {
1625
private:
1726
std::string data;
18-
size_t length;
27+
static constexpr size_t length = L;
1928

2029
public:
2130
/// \brief Creates a string from the given \p data
22-
String(const std::string& data) : length(L) {
23-
this->set(data);
31+
explicit String(const std::string& data, StringTooLarge to_large = StringTooLarge::Throw) {
32+
this->set(data, to_large);
2433
}
2534

26-
String(const char* data) : length(L) {
27-
this->set(data);
35+
explicit String(const char* data, StringTooLarge to_large = StringTooLarge::Throw) {
36+
this->set(data, to_large);
2837
}
2938

3039
/// \brief Creates a string
31-
String() : length(L) {
32-
}
40+
String() = default;
3341

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

4048
/// \brief Sets the content of the string to the given \p data
41-
void set(const std::string& data) {
42-
if (data.length() <= this->length) {
43-
if (this->is_valid(data)) {
44-
this->data = data;
45-
} else {
46-
throw std::runtime_error("String has invalid format");
49+
void set(const std::string& data, StringTooLarge to_large = StringTooLarge::Throw) {
50+
std::string_view view = data;
51+
if (view.length() > this->length) {
52+
if (to_large == StringTooLarge::Throw) {
53+
throw StringConversionException("String length (" + std::to_string(view.length()) +
54+
") exceeds permitted length (" + std::to_string(this->length) + ")");
4755
}
56+
// Truncate
57+
view = view.substr(0, length);
58+
}
59+
60+
if (this->is_valid(view)) {
61+
this->data = view;
4862
} else {
49-
throw std::runtime_error("String length (" + std::to_string(data.length()) +
50-
") exceeds permitted length (" + std::to_string(this->length) + ")");
63+
throw StringConversionException("String has invalid format");
5164
}
5265
}
5366

5467
/// \brief Override this to check for a specific format
55-
bool is_valid(const std::string& data) {
68+
bool is_valid(std::string_view data) {
5669
(void)data; // not needed here
5770
return true;
5871
}

lib/ocpp/v201/charge_point.cpp

+14-2
Original file line numberDiff line numberDiff line change
@@ -832,15 +832,27 @@ void ChargePoint::message_callback(const std::string& message) {
832832
this->message_dispatcher->dispatch_call_error(
833833
CallError(MessageId("-1"), "RpcFrameworkError", e.what(), json({})));
834834
const auto& security_event = ocpp::security_events::INVALIDMESSAGES;
835-
this->security->security_event_notification_req(CiString<50>(security_event), CiString<255>(message), true,
835+
this->security->security_event_notification_req(CiString<50>(security_event, StringTooLarge::Truncate),
836+
CiString<255>(message, StringTooLarge::Truncate), true,
837+
utils::is_critical(security_event));
838+
return;
839+
} catch (const StringConversionException& e) {
840+
this->logging->central_system("Unknown", message);
841+
EVLOG_error << "JSON exception during reception of message: " << e.what();
842+
this->message_dispatcher->dispatch_call_error(
843+
CallError(MessageId("-1"), "RpcFrameworkError", e.what(), json({})));
844+
const auto& security_event = ocpp::security_events::INVALIDMESSAGES;
845+
this->security->security_event_notification_req(CiString<50>(security_event, StringTooLarge::Truncate),
846+
CiString<255>(message, StringTooLarge::Truncate), true,
836847
utils::is_critical(security_event));
837848
return;
838849
} catch (const EnumConversionException& e) {
839850
EVLOG_error << "EnumConversionException during handling of message: " << e.what();
840851
auto call_error = CallError(MessageId("-1"), "FormationViolation", e.what(), json({}));
841852
this->message_dispatcher->dispatch_call_error(call_error);
842853
const auto& security_event = ocpp::security_events::INVALIDMESSAGES;
843-
this->security->security_event_notification_req(CiString<50>(security_event), CiString<255>(message), true,
854+
this->security->security_event_notification_req(CiString<50>(security_event, StringTooLarge::Truncate),
855+
CiString<255>(message, StringTooLarge::Truncate), true,
844856
utils::is_critical(security_event));
845857
return;
846858
}

0 commit comments

Comments
 (0)