Migrating json parsing from rapidjson to jsoncons. (#112)

* Migrating JSON parsing from RapidJSNO library to jsoncons library

* updating readme file and removing RapidJSON headers
This commit is contained in:
Savinda Senevirathne
2020-08-31 14:05:42 +05:30
committed by GitHub
parent 648b70892c
commit 2fc93d4291
10 changed files with 520 additions and 619 deletions

View File

@@ -46,7 +46,7 @@ namespace msg::usrmsg::json
util::bin2hex(challengehex, challenge_bytes, msg::usrmsg::CHALLENGE_LEN);
// Construct the challenge msg json.
// We do not use RapidJson here in favour of performance because this is a simple json message.
// We do not use jasoncons library here in favour of performance because this is a simple json message.
// Since we know the rough size of the challenge message we reserve adequate amount for the holder.
// Only Hot Pocket version number is variable length. Therefore message size is roughly 90 bytes
@@ -221,7 +221,7 @@ namespace msg::usrmsg::json
int verify_user_handshake_response(std::string &extracted_pubkeyhex, std::string &extracted_protocol,
std::string_view response, std::string_view original_challenge)
{
rapidjson::Document d;
jsoncons::json d;
if (parse_user_message(d, response) != 0)
return -1;
@@ -233,35 +233,35 @@ namespace msg::usrmsg::json
}
// Compare the response handshake string with the original issued challenge.
if (!d.HasMember(msg::usrmsg::FLD_CHALLENGE) || d[msg::usrmsg::FLD_CHALLENGE] != original_challenge.data())
if (!d.contains(msg::usrmsg::FLD_CHALLENGE) || d[msg::usrmsg::FLD_CHALLENGE] != original_challenge.data())
{
LOG_DBG << "User handshake response 'challenge' invalid.";
return -1;
}
// Check for the 'sig' field existence.
if (!d.HasMember(msg::usrmsg::FLD_SIG) || !d[msg::usrmsg::FLD_SIG].IsString())
if (!d.contains(msg::usrmsg::FLD_SIG) || !d[msg::usrmsg::FLD_SIG].is<std::string>())
{
LOG_DBG << "User handshake response 'challenge signature' invalid.";
return -1;
}
// Check for the 'pubkey' field existence.
if (!d.HasMember(msg::usrmsg::FLD_PUBKEY) || !d[msg::usrmsg::FLD_PUBKEY].IsString())
if (!d.contains(msg::usrmsg::FLD_PUBKEY) || !d[msg::usrmsg::FLD_PUBKEY].is<std::string>())
{
LOG_DBG << "User handshake response 'public key' invalid.";
return -1;
}
// Check for protocol field existence and valid value.
if (!d.HasMember(msg::usrmsg::FLD_PROTOCOL) || !d[msg::usrmsg::FLD_PROTOCOL].IsString())
if (!d.contains(msg::usrmsg::FLD_PROTOCOL) || !d[msg::usrmsg::FLD_PROTOCOL].is<std::string>())
{
LOG_DBG << "User handshake response 'protocol' invalid.";
return -1;
}
std::string_view protocolsv = util::getsv(d[msg::usrmsg::FLD_PROTOCOL]);
std::string_view protocolsv = d[msg::usrmsg::FLD_PROTOCOL].as<std::string_view>();
if (protocolsv != "json" && protocolsv != "bson")
{
LOG_DBG << "User handshake response 'protocol' type invalid.";
@@ -269,10 +269,10 @@ namespace msg::usrmsg::json
}
// Verify the challenge signature. We do this last due to signature verification cost.
std::string_view pubkeysv = util::getsv(d[msg::usrmsg::FLD_PUBKEY]);
std::string_view pubkeysv = d[msg::usrmsg::FLD_PUBKEY].as<std::string_view >();
if (crypto::verify_hex(
original_challenge,
util::getsv(d[msg::usrmsg::FLD_SIG]),
d[msg::usrmsg::FLD_SIG].as<std::string_view>(),
pubkeysv) != 0)
{
LOG_DBG << "User challenge response signature verification failed.";
@@ -287,7 +287,7 @@ namespace msg::usrmsg::json
/**
* Parses a json message sent by a user.
* @param d RapidJson document to which the parsed json should be loaded.
* @param d Jsoncons document to which the parsed json should be loaded.
* @param message The message to parse.
* Accepted message format:
* {
@@ -296,20 +296,20 @@ namespace msg::usrmsg::json
* }
* @return 0 on successful parsing. -1 for failure.
*/
int parse_user_message(rapidjson::Document &d, std::string_view message)
int parse_user_message(jsoncons::json &d, std::string_view message)
{
// We load response raw bytes into json document.
// Because we project the response message directly from the binary socket buffer in a zero-copy manner, the response
// string is not null terminated. 'kParseStopWhenDoneFlag' avoids rapidjson error in this case.
d.Parse<rapidjson::kParseStopWhenDoneFlag>(message.data());
if (d.HasParseError())
try
{
d = jsoncons::json::parse(message, jsoncons::strict_json_parsing());
}
catch(const std::exception& e)
{
LOG_DBG << "User json message parsing failed.";
return -1;
}
// Check existence of msg type field.
if (!d.HasMember(msg::usrmsg::FLD_TYPE) || !d[msg::usrmsg::FLD_TYPE].IsString())
if (!d.contains(msg::usrmsg::FLD_TYPE) || !d[msg::usrmsg::FLD_TYPE].is<std::string>())
{
LOG_DBG << "User json message 'type' missing or invalid.";
return -1;
@@ -321,9 +321,9 @@ namespace msg::usrmsg::json
/**
* Extracts the message 'type' value from the json document.
*/
int extract_type(std::string &extracted_type, const rapidjson::Document &d)
int extract_type(std::string &extracted_type, const jsoncons::json &d)
{
extracted_type = d[msg::usrmsg::FLD_TYPE].GetString();
extracted_type = d[msg::usrmsg::FLD_TYPE].as<std::string>();
return 0;
}
@@ -339,21 +339,21 @@ namespace msg::usrmsg::json
* }
* @return 0 on successful extraction. -1 for failure.
*/
int extract_read_request(std::string &extracted_content, const rapidjson::Document &d)
int extract_read_request(std::string &extracted_content, const jsoncons::json &d)
{
if (!d.HasMember(msg::usrmsg::FLD_CONTENT))
if (!d.contains(msg::usrmsg::FLD_CONTENT))
{
LOG_DBG << "Read request required fields missing.";
return -1;
}
if (!d[msg::usrmsg::FLD_CONTENT].IsString())
if (!d[msg::usrmsg::FLD_CONTENT].is<std::string>())
{
LOG_DBG << "Read request invalid field values.";
return -1;
}
std::string_view contenthex(d[msg::usrmsg::FLD_CONTENT].GetString(), d[msg::usrmsg::FLD_CONTENT].GetStringLength());
std::string_view contenthex = d[msg::usrmsg::FLD_CONTENT].as<std::string_view>();
std::string content;
content.resize(contenthex.length() / 2);
@@ -385,15 +385,15 @@ namespace msg::usrmsg::json
* @return 0 on successful extraction. -1 for failure.
*/
int extract_signed_input_container(
std::string &extracted_input_container, std::string &extracted_sig, const rapidjson::Document &d)
std::string &extracted_input_container, std::string &extracted_sig, const jsoncons::json &d)
{
if (!d.HasMember(msg::usrmsg::FLD_INPUT_CONTAINER) || !d.HasMember(msg::usrmsg::FLD_SIG))
if (!d.contains(msg::usrmsg::FLD_INPUT_CONTAINER) || !d.contains(msg::usrmsg::FLD_SIG))
{
LOG_DBG << "User signed input required fields missing.";
return -1;
}
if (!d[msg::usrmsg::FLD_INPUT_CONTAINER].IsString() || !d[msg::usrmsg::FLD_SIG].IsString())
if (!d[msg::usrmsg::FLD_INPUT_CONTAINER].is<std::string>() || !d[msg::usrmsg::FLD_SIG].is<std::string>())
{
LOG_DBG << "User signed input invalid field values.";
return -1;
@@ -402,12 +402,12 @@ namespace msg::usrmsg::json
// We do not verify the signature of the content here since we need to let each node
// (including self) to verify that individually after we broadcast the NUP proposal.
const std::string_view input_container_hex(d[msg::usrmsg::FLD_INPUT_CONTAINER].GetString(), d[msg::usrmsg::FLD_INPUT_CONTAINER].GetStringLength());
const std::string_view input_container_hex = d[msg::usrmsg::FLD_INPUT_CONTAINER].as<std::string_view>();
std::string input_container;
input_container.resize(input_container_hex.size() / 2);
util::hex2bin(reinterpret_cast<unsigned char *>(input_container.data()), input_container.length(), input_container_hex);
const std::string_view sig_hex(d[msg::usrmsg::FLD_SIG].GetString(), d[msg::usrmsg::FLD_SIG].GetStringLength());
const std::string_view sig_hex = d[msg::usrmsg::FLD_SIG].as<std::string_view>();
std::string sig;
sig.resize(crypto_sign_ed25519_BYTES);
util::hex2bin(reinterpret_cast<unsigned char *>(sig.data()), sig.length(), sig_hex);
@@ -432,28 +432,30 @@ namespace msg::usrmsg::json
*/
int extract_input_container(std::string &input, std::string &nonce, uint64_t &max_lcl_seqno, std::string_view contentjson)
{
rapidjson::Document d;
d.Parse(contentjson.data());
if (d.HasParseError())
jsoncons::json d;
try
{
d = jsoncons::json::parse(contentjson, jsoncons::strict_json_parsing());
}
catch(const std::exception& e)
{
LOG_DBG << "User input container json parsing failed.";
return -1;
}
if (!d.HasMember(msg::usrmsg::FLD_INPUT) || !d.HasMember(msg::usrmsg::FLD_NONCE) || !d.HasMember(msg::usrmsg::FLD_MAX_LCL_SEQ))
if (!d.contains(msg::usrmsg::FLD_INPUT) || !d.contains(msg::usrmsg::FLD_NONCE) || !d.contains(msg::usrmsg::FLD_MAX_LCL_SEQ))
{
LOG_DBG << "User input container required fields missing.";
return -1;
}
if (!d[msg::usrmsg::FLD_INPUT].IsString() || !d[msg::usrmsg::FLD_NONCE].IsString() || !d[msg::usrmsg::FLD_MAX_LCL_SEQ].IsUint64())
if (!d[msg::usrmsg::FLD_INPUT].is<std::string>() || !d[msg::usrmsg::FLD_NONCE].is<std::string>() || !d[msg::usrmsg::FLD_MAX_LCL_SEQ].is<uint64_t>())
{
LOG_DBG << "User input container invalid field values.";
return -1;
}
const rapidjson::Value &inputval = d[msg::usrmsg::FLD_INPUT];
std::string_view inputhex(inputval.GetString(), inputval.GetStringLength());
std::string_view inputhex = d[msg::usrmsg::FLD_INPUT].as<std::string_view>();
// Convert hex input to binary.
input.resize(inputhex.length() / 2);
@@ -466,8 +468,8 @@ namespace msg::usrmsg::json
return -1;
}
nonce = d[msg::usrmsg::FLD_NONCE].GetString();
max_lcl_seqno = d[msg::usrmsg::FLD_MAX_LCL_SEQ].GetUint64();
nonce = d[msg::usrmsg::FLD_NONCE].as<std::string>();
max_lcl_seqno = d[msg::usrmsg::FLD_MAX_LCL_SEQ].as<uint64_t>();
return 0;
}