rapidjson crashed when json value should be INT but send as string type - c++

I have a C++ code that parses incoming json message using rapidjson.
The json message received contains one key:value pair ("userID": 100), where the value is an integer.
However, if the value is sent as a string '100', rapidjson crashed the whole program with the following error:
Invalid response: { "error": "ERR_RATE_LIMIT"}
trading: ../../include/rapidjson/document.h:1737: int rapidjson::GenericValue<Encoding, Allocator>::GetInt() const [with Encoding = rapidjson::UTF8<>; Allocator = rapidjson::MemoryPoolAllocator<>]: Assertion `data_.f.flags & kIntFlag' failed.
/home/ray/dev/trading_execution/src/trading/trading.run.sh: line 39: 2518 Aborted (core dumped) ./trading 1234
I would expect rapidjson can handle this more gently than crashing the program.
Any suggestion how to deal with this situation? For example, is there a better way to handle the error?
Json message:
{
"ctRequestId": "cfa5511f-8c1a-492b-b81a-1462d03bbe99",
"requestType": "generic",
"userID": 100,
}
Code:
userID = getJSONInt(document, "userID");
int getJSONInt(rapidjson::Document& document, const char* memberName)
{
int memberValue;
try
{
if (document.HasMember(memberName))
memberValue = document[memberName].GetInt();
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
return memberValue;
}

No expert of rapidjson, but according to the documentation (http://rapidjson.org/md_doc_tutorial.html)
Note that, RapidJSON does not automatically convert values between JSON types. If a value is a string, it is invalid to call GetInt(), for example. In debug mode it will fail an assertion. In release mode, the behavior is undefined.
In the following sections we discuss details about querying individual types.
If you look in the table in the section "Querying Number" of the linked document you can find some member function you can use to test the type before extracting it. In your case you might want to try IsInt()
Edit: for the particular use case IsUint/GetUint may be more appropriate as pointed out in the comments

Try this:
{
...,
...,
"UserId" : "100" // note double quotes for 100
}
And if the value of "UserId" is string, then query it using GetString() query and not GetInt() to pass assertion test.

Related

c++ JsonCpp parse string with escaped quotes as array

I've got the following json string:
{
"data" :
[
{
"cart" : "[{\"name\":\"Test item 1\",\"price\":15,\"quantity\":1,\"sum\":15,\"tax\":\"none\",\"payment_type\":\"advance\",\"item_type\":\"service\"},{\"name\":\"Test item 2\",\"price\":13.01,\"quantity\":2,\"sum\":26.02,\"tax\":\"none\",\"payment_type\":\"part_prepay\",\"item_type\":\"work\"}]",
"contact" : "noname#google.com",
"p_id" : "603",
"sum" : "100.02",
"tax_system" : "osn"
}
],
"msg" : null,
"result" : "success"
}
I can parse cart as std::string after parsing input json string as stringstream:
const std::string ParseJsonData(std::stringstream ssJsonStream)
{
Json::Value jsonData;
Json::Value responseData;
Json::Value responseDataCart;
Json::CharReaderBuilder jsonReader;
std::string errs;
if (Json::parseFromStream(jsonReader, ssJsonStream, &jsonData, &errs)) {
responseData = jsonData["data"];
responseDataCart = responseData[0]["cart"];
return responseDataCart.toStyledString().c_str();
}
else
return "Could not parse HTTP data as JSON";
}
Please, tell me, how can i parse cart as array with JsonCpp?
The same way you parsed the outer JSON!
You started with a string (well, hidden by a stream) and turned it into JSON.
Now that JSON contains a property that is a string and, itself, contains JSON. The problem is recursive. The fact that the inner string originally came from JSON too can be ignored. Just pretend it's a string you typed in.
So, you can use JSON::Reader to in turn get the JSON out of that string.
Something like:
const std::string responseDataCartStr = responseData[0]["cart"].asString();
Json::Reader reader;
if (!reader.parse(responseDataCartStr, responseDataCart))
throw std::runtime_error("Parsing nested JSON failed");
JsonCpp provides a few ways to parse JSON and it's worth exploring them to find the most appropriate for your use case. The above is just an example.
Ignore the backslashes — the escaping was meaningful within the encapsulating JSON document, but the outermost parse stage should already have taken that into consideration. You'll see if you print responseDataCartStr to console that it is a valid JSON document in its own right.

Sending POST using cpprest

I have the following code to send POST, but I am getting an error with that even it compile correctly
http_client client(U("http://l0.71.103.63:34568"));
json::value postData;
postData["name"] = json::value::string(U("Mohammad"));
http_response response = client.request(methods::POST,postData.to_string().c_str()).get();
if(response.status_code() == status_codes::OK)
{
auto body = response.extract_string();
std::wcout << L"Added new Id: " << body.get().c_str() << std::endl;
return std::stoi(body.get().c_str());
}
But I am getting the following error when try to run the program
terminate called after throwing an instance of 'web::uri_exception'
what(): provided uri is invalid: {"name":"Mohammad"}
Aborted (core dumped)
I think the problem is your IP address. It looks like your IP address is wrong? You have "http://l0." where the "10" is "l0" (lowercase L).
Hence the web:uri_exception.
You are wrong (I do think) in your request, should look like that:
auto response = client.request(methods::POST, U("\"), postData).get();
The second argument in the request is the URL complement, and you are passing your json in string, hence the error you have.
basically the syntax you want is this one:
pplx::task web::http::client::http_client::request (
const method & mtd, const utility::string_t &
path_query_fragment, const json::value & body_data, const
pplx::cancellation_token & token = pplx::cancellation_token::none()
)

How to create empty json object correctly using web.json in cpp?

I want to create following json request:
{
"Value1":{},
"Value2":"some string value"
}
to achieve this I have tried following code in cpp:
json::value &refRequest
json::value jRequest = json::value();
refRequest[requestKey::Value1] = json::value(json::value::object()); //for creating empty object
refRequest[requestKey::Value2] = json::value::string("some string");
but it gives output as:
{
"Value1":},
"Value2":"some string value"
}
if you observe, instead of returning empty object as {} it gives the output as } and this results in to malformed request. I am not sure where exactly I am going wrong, any help will would be appreciated. Thanks
I believe your mistake is that you are constructing a json::value from a json::value::object()
According to the documentation the line should be fixed to:
refRequest[requestKey::Value1] = json::value::object();

Not able to get values from JSON in Casablanca, C++

I'm using Casablanca, cpprestsdk to consume REST APIs in C++, in Visual Studio 2015 Professional. I'm trying to develop a simple example here hitting an API and parsing the response as JSON. The URL I'm using, actually returns all the parameters sent to the API.
I've hit the API and got response as well, extracted json from the response successfully. But when i try to read a value at any key from json, it crashes. Hence i put a check whether that key is available or not, and it always says json does not have the field. As an example i printed the data i.e. json. It has the key/field "name" but when i check it via has_field, it returns false.
Please help.
Complete code is below :
json::value postData;
postData[L"name"] = json::value::string(L"Joe Smith");
postData[L"sport"] = json::value::string(L"Baseball");
http_client client(L"https://httpbin.org/post);
http_request request(methods::POST);
request.set_body(postData);
client.request(request).then([](web::http::http_response response) {
json::value j = response.extract_json().get();
json::value data = j.at(U("data"));
std::wcout << "Json : " << data;
// Prints "{\"name\":\"Joe Smith\",\"sport\":\"Baseball\"}"
if (data.has_field(U("name"))) {
std::cout << "Name Found";
}
else {
std::cout << "Name key not Found";
}
});
It seems that your response looks like this:
{ "data": "{\"name\":\"Joe Smith\",\"sport\":\"Baseball\"}" }`
i.e. the actual data is not a JSon object but escaped JSon passed as string. I guess you need to return a payload that looks like this to do what you want to do the way you are doing it:
{
"data": {
"name": "John Smith",
"sport": "Baseball"
}
}

C++REST SDK, parse JSON that contains (0xEF 0xBF 0xBF) character

I have a REST API that returns a string with files metadata. Among those files I have one that has "￿" (0xEF0xBF0xBF, link) character in name. When I try to parse such a response I get exception that says:
e = {_message="* Line 1, Column 13 Syntax error: Malformed string literal" }
This is the string I'm trying to parse:
{"files":[["Thunderbolt ￿Gigabit￿ Ethernet ￿Adapter.txt",["bc288518-c426-4dbd-9600-a213a35d1c04",1447772221866,9,"Bartosz","Siewior"]],["System.Windows.Interactivity.dll",["56ce759b-019b-4723-8fca-7af877908971",1440507238241,55904,"Bartosz","Siewior"]]],"folderPermission":[["MODIFY"]],"directories":[]}
The code I'm using to receive and parse the string:
// ...
client.request(request).then([&](web::http::http_response response) {
status_code = response.status_code();
//response.extract_json(true).then([&](pplx::task<web::json::value> previousTask) {
response.extract_string().then([&](pplx::task<utility::string_t> previousTask) {
try {
utility::string_t str_response = previousTask.get();
web::json::value root;
root = web::json::value::parse(str_response);
}
catch (const web::http::http_exception& e) {
std::wstringstream ss;
ss << e.what();
str_response = ss.str();
}
catch (const web::json::json_exception& e) {
std::wstringstream ss;
ss << e.what();
str_response = ss.str();
}
TaskExecutionData data = { task.id, status_code, str_response.c_str() };
callback(data);
}).wait();
}).wait();
VS2013 JSON Visualizer can parse and show the result properly: VS_json_visualizer
I've tried C++REST version 2.5.0 and 2.6.0, neither of them is able to parse that string... Do you have any ides?
Answer from Casablanca's team:
The issue is that on windows we parse using UTF16 and the particular character you're having issues with maps to 0xFFFF. This is also the character returned by std::char_traits::eof(), so we detect the code point as an "end of stream" signal and terminate the parse appropriately.
The UTF8 parser should not have these issues, so as a workaround you can probably do something similar to how the current web::json::value::parse() function works in json_parsing.cpp:1245, except using char as the template parameter instead of utility::char_t.