Description
socket.io-client-cpp parses incoming string payloads using bool packet::parse(const string& payload_ptr)
, which uses this code to parse the payload string:
Document doc;
doc.Parse<0>(payload_ptr.data()+json_pos);
_message = from_json(doc, vector<shared_ptr<const string> >());
return false;
Parse
eventually calls this method in reader.h to parse the number:
template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseNumber(InputStream& is, Handler& handler) {
When parsing an unsigned integer value requiring 64 bits (e.g. 17657333360744292000), ParseNumber
correctly parses the int64_t, and gives it to the handler using:
cont = handler.Uint64(i64);
This ends up calling this code to set the value:
explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUint64Flag) {
data_.n.u64 = u64;
if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))
flags_ |= kInt64Flag;
if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
flags_ |= kUintFlag;
if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
flags_ |= kIntFlag;
}
Note that kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag
.
When Parse
returns to packet::parse
, we create a message using:
message::ptr from_json(Value const& value, vector<shared_ptr<const string> > const& buffers)
{
if(value.IsInt64())
{
return int_message::create(value.GetInt64());
}
else if(value.IsDouble())
{
return double_message::create(value.GetDouble());
}
// ... UNRELATED ELSE-IFS REMOVED FOR BREVITY ...
else if(value.IsNull())
{
return null_message::create();
}
return message::ptr();
}
Note that there's no explicit check for IsUint64()
, although that is defined in document.h. Both the Int64 and Double checks fail, so we end up calling return message::ptr();
instead, essentially throwing away the UInt64 that we parsed.
I think the easiest way to address this (without adding to the message types defined in sio_message.h
) is to add a check for UInt64 values to from_json
and return them as doubles or integers:
message::ptr from_json(Value const& value, vector<shared_ptr<const string> > const& buffers)
{
if(value.IsInt64())
{
return int_message::create(value.GetInt64());
}
else if (value.IsUint64())
{
return double_message::create(value.GetDouble());
}
else if(value.IsDouble())
{
return double_message::create(value.GetDouble());
}
// ... UNRELATED ELSE-IFS REMOVED FOR BREVITY ...
else if(value.IsNull())
{
return null_message::create();
}
return message::ptr();
}
But I'm unsure which type would be better, or if this might have undesirable side-effects.