| 102 | } |
| 103 | |
| 104 | UniValue ExecuteHTTPRPC(const UniValue& valRequest, JSONRPCRequest& jreq, HTTPStatusCode& status) |
| 105 | { |
| 106 | status = HTTP_OK; |
| 107 | try { |
| 108 | bool user_has_whitelist = g_rpc_whitelist.contains(jreq.authUser); |
| 109 | if (!user_has_whitelist && g_rpc_whitelist_default) { |
| 110 | LogWarning("RPC User %s not allowed to call any methods", jreq.authUser); |
| 111 | status = HTTP_FORBIDDEN; |
| 112 | return {}; |
| 113 | |
| 114 | // singleton request |
| 115 | } else if (valRequest.isObject()) { |
| 116 | jreq.parse(valRequest); |
| 117 | if (user_has_whitelist && !g_rpc_whitelist[jreq.authUser].contains(jreq.strMethod)) { |
| 118 | LogWarning("RPC User %s not allowed to call method %s", jreq.authUser, jreq.strMethod); |
| 119 | status = HTTP_FORBIDDEN; |
| 120 | return {}; |
| 121 | } |
| 122 | |
| 123 | // Legacy 1.0/1.1 behavior is for failed requests to throw |
| 124 | // exceptions which return HTTP errors and RPC errors to the client. |
| 125 | // 2.0 behavior is to catch exceptions and return HTTP success with |
| 126 | // RPC errors, as long as there is not an actual HTTP server error. |
| 127 | const bool catch_errors{jreq.m_json_version == JSONRPCVersion::V2}; |
| 128 | UniValue reply{JSONRPCExec(jreq, catch_errors)}; |
| 129 | if (jreq.IsNotification()) { |
| 130 | // Even though we do execute notifications, we do not respond to them |
| 131 | status = HTTP_NO_CONTENT; |
| 132 | return {}; |
| 133 | } |
| 134 | return reply; |
| 135 | // array of requests |
| 136 | } else if (valRequest.isArray()) { |
| 137 | // Check authorization for each request's method |
| 138 | if (user_has_whitelist) { |
| 139 | for (unsigned int reqIdx = 0; reqIdx < valRequest.size(); reqIdx++) { |
| 140 | if (!valRequest[reqIdx].isObject()) { |
| 141 | throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object"); |
| 142 | } else { |
| 143 | const UniValue& request = valRequest[reqIdx].get_obj(); |
| 144 | // Parse method |
| 145 | std::string strMethod = request.find_value("method").get_str(); |
| 146 | if (!g_rpc_whitelist[jreq.authUser].contains(strMethod)) { |
| 147 | LogWarning("RPC User %s not allowed to call method %s", jreq.authUser, strMethod); |
| 148 | status = HTTP_FORBIDDEN; |
| 149 | return {}; |
| 150 | } |
| 151 | } |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | // Execute each request |
| 156 | UniValue reply = UniValue::VARR; |
| 157 | for (size_t i{0}; i < valRequest.size(); ++i) { |
| 158 | // Batches never throw HTTP errors, they are always just included |
| 159 | // in "HTTP OK" responses. Notifications never get any response. |
| 160 | UniValue response; |
| 161 | try { |
no test coverage detected