| 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 | |