1 | /************************************************************************* |
2 | * libjson-rpc-cpp |
3 | ************************************************************************* |
4 | * @file responsehandler.cpp |
5 | * @date 13.03.2013 |
6 | * @author Peter Spiess-Knafl <dev@spiessknafl.at> |
7 | * @license See attached LICENSE.txt |
8 | ************************************************************************/ |
9 | |
10 | #include "rpcprotocolclient.h" |
11 | #include <jsonrpccpp/common/jsonparser.h> |
12 | |
13 | using namespace jsonrpc; |
14 | |
15 | const std::string RpcProtocolClient::KEY_PROTOCOL_VERSION = "jsonrpc" ; |
16 | const std::string RpcProtocolClient::KEY_PROCEDURE_NAME = "method" ; |
17 | const std::string RpcProtocolClient::KEY_ID = "id" ; |
18 | const std::string RpcProtocolClient::KEY_PARAMETER = "params" ; |
19 | const std::string RpcProtocolClient::KEY_AUTH = "auth" ; |
20 | const std::string RpcProtocolClient::KEY_RESULT = "result" ; |
21 | const std::string RpcProtocolClient::KEY_ERROR = "error" ; |
22 | const std::string RpcProtocolClient::KEY_ERROR_CODE = "code" ; |
23 | const std::string RpcProtocolClient::KEY_ERROR_MESSAGE = "message" ; |
24 | const std::string RpcProtocolClient::KEY_ERROR_DATA = "data" ; |
25 | |
26 | RpcProtocolClient::RpcProtocolClient(clientVersion_t version, bool omitEndingLineFeed) : version(version), omitEndingLineFeed(omitEndingLineFeed) {} |
27 | |
28 | void RpcProtocolClient::BuildRequest(const std::string &method, const Json::Value ¶meter, std::string &result, bool isNotification) { |
29 | Json::Value request; |
30 | Json::StreamWriterBuilder wbuilder; |
31 | wbuilder["indentation" ] = "" ; |
32 | this->BuildRequest(1, method, parameter, request, isNotification); |
33 | |
34 | result = Json::writeString(wbuilder, request); |
35 | } |
36 | |
37 | void RpcProtocolClient::HandleResponse(const std::string &response, Json::Value &result) { |
38 | Json::Value value; |
39 | |
40 | try { |
41 | if (std::istringstream(response) >> value) { |
42 | this->HandleResponse(value, result); |
43 | } else { |
44 | throw JsonRpcException(Errors::ERROR_RPC_JSON_PARSE_ERROR, " " + response); |
45 | } |
46 | } catch (Json::Exception &e) { |
47 | throw JsonRpcException(Errors::ERROR_RPC_JSON_PARSE_ERROR, " " + response); |
48 | } |
49 | } |
50 | |
51 | Json::Value RpcProtocolClient::HandleResponse(const Json::Value &value, Json::Value &result) { |
52 | if (this->ValidateResponse(value)) { |
53 | if (this->HasError(value)) { |
54 | this->throwErrorException(value); |
55 | } else { |
56 | result = value[KEY_RESULT]; |
57 | } |
58 | } else { |
59 | throw JsonRpcException(Errors::ERROR_CLIENT_INVALID_RESPONSE, " " + value.toStyledString()); |
60 | } |
61 | return value[KEY_ID]; |
62 | } |
63 | |
64 | void RpcProtocolClient::BuildRequest(int id, const std::string &method, const Json::Value ¶meter, Json::Value &result, bool isNotification) { |
65 | if (this->version == JSONRPC_CLIENT_V2) |
66 | result[KEY_PROTOCOL_VERSION] = "2.0" ; |
67 | result[KEY_PROCEDURE_NAME] = method; |
68 | if (parameter != Json::nullValue) |
69 | result[KEY_PARAMETER] = parameter; |
70 | if (!isNotification) |
71 | result[KEY_ID] = id; |
72 | else if (this->version == JSONRPC_CLIENT_V1) |
73 | result[KEY_ID] = Json::nullValue; |
74 | } |
75 | |
76 | void RpcProtocolClient::throwErrorException(const Json::Value &response) { |
77 | if (response[KEY_ERROR].isMember(KEY_ERROR_MESSAGE) && response[KEY_ERROR][KEY_ERROR_MESSAGE].isString()) { |
78 | if (response[KEY_ERROR].isMember(KEY_ERROR_DATA)) { |
79 | throw JsonRpcException(response[KEY_ERROR][KEY_ERROR_CODE].asInt(), response[KEY_ERROR][KEY_ERROR_MESSAGE].asString(), |
80 | response[KEY_ERROR][KEY_ERROR_DATA]); |
81 | } else { |
82 | throw JsonRpcException(response[KEY_ERROR][KEY_ERROR_CODE].asInt(), response[KEY_ERROR][KEY_ERROR_MESSAGE].asString()); |
83 | } |
84 | } else { |
85 | throw JsonRpcException(response[KEY_ERROR][KEY_ERROR_CODE].asInt()); |
86 | } |
87 | } |
88 | |
89 | bool RpcProtocolClient::ValidateResponse(const Json::Value &response) { |
90 | if (!response.isObject() || !response.isMember(KEY_ID)) |
91 | return false; |
92 | |
93 | if (this->version == JSONRPC_CLIENT_V1) { |
94 | if (!response.isMember(KEY_RESULT) || !response.isMember(KEY_ERROR)) |
95 | return false; |
96 | if (!response[KEY_RESULT].isNull() && !response[KEY_ERROR].isNull()) |
97 | return false; |
98 | if (!response[KEY_ERROR].isNull() && |
99 | !(response[KEY_ERROR].isObject() && response[KEY_ERROR].isMember(KEY_ERROR_CODE) && response[KEY_ERROR][KEY_ERROR_CODE].isIntegral())) |
100 | return false; |
101 | } else if (this->version == JSONRPC_CLIENT_V2) { |
102 | if (!response.isMember(KEY_PROTOCOL_VERSION) || response[KEY_PROTOCOL_VERSION] != "2.0" ) |
103 | return false; |
104 | if (response.isMember(KEY_RESULT) && response.isMember(KEY_ERROR)) |
105 | return false; |
106 | if (!response.isMember(KEY_RESULT) && !response.isMember(KEY_ERROR)) |
107 | return false; |
108 | if (response.isMember(KEY_ERROR) && |
109 | !(response[KEY_ERROR].isObject() && response[KEY_ERROR].isMember(KEY_ERROR_CODE) && response[KEY_ERROR][KEY_ERROR_CODE].isIntegral())) |
110 | return false; |
111 | } |
112 | |
113 | return true; |
114 | } |
115 | |
116 | bool RpcProtocolClient::HasError(const Json::Value &response) { |
117 | if (this->version == JSONRPC_CLIENT_V1 && !response[KEY_ERROR].isNull()) |
118 | return true; |
119 | else if (this->version == JSONRPC_CLIENT_V2 && response.isMember(KEY_ERROR)) |
120 | return true; |
121 | return false; |
122 | } |
123 | |