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
13using namespace jsonrpc;
14
15const std::string RpcProtocolClient::KEY_PROTOCOL_VERSION = "jsonrpc";
16const std::string RpcProtocolClient::KEY_PROCEDURE_NAME = "method";
17const std::string RpcProtocolClient::KEY_ID = "id";
18const std::string RpcProtocolClient::KEY_PARAMETER = "params";
19const std::string RpcProtocolClient::KEY_AUTH = "auth";
20const std::string RpcProtocolClient::KEY_RESULT = "result";
21const std::string RpcProtocolClient::KEY_ERROR = "error";
22const std::string RpcProtocolClient::KEY_ERROR_CODE = "code";
23const std::string RpcProtocolClient::KEY_ERROR_MESSAGE = "message";
24const std::string RpcProtocolClient::KEY_ERROR_DATA = "data";
25
26RpcProtocolClient::RpcProtocolClient(clientVersion_t version, bool omitEndingLineFeed) : version(version), omitEndingLineFeed(omitEndingLineFeed) {}
27
28void RpcProtocolClient::BuildRequest(const std::string &method, const Json::Value &parameter, 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
37void 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
51Json::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
64void RpcProtocolClient::BuildRequest(int id, const std::string &method, const Json::Value &parameter, 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
76void 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
89bool 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
116bool 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