std::string ServerHandlerImp::createResponse ( int statusCode, std::string const& description) { return HTTPReply (statusCode, description); }
void ErrorReply (std::ostream& stream, Json::Value const& objError, Json::Value const& id) { // Send error reply from json-rpc error object int nStatus = 500; int code = objError[jss::code].asInt (); if (code == -32600) nStatus = 400; else if (code == -32601) nStatus = 404; std::string strReply = JSONRPCReply (Json::Value (), objError, id); stream << HTTPReply (nStatus, strReply) << std::flush; }
void ServerHandlerImp::onRequest (HTTP::Session& session) { // Check user/password authorization auto const headers (build_map (session.message().headers)); if (! HTTPAuthorized (headers)) { session.write (HTTPReply (403, "Forbidden")); session.close (true); return; } session.detach(); m_jobQueue.addJob (jtCLIENT, "RPC-Client", std::bind ( &ServerHandlerImp::processSession, this, std::placeholders::_1, std::ref (session))); }
// VFALCO ARGH! returning a single std::string for the entire response? std::string ServerHandlerImp::processRequest (std::string const& request, beast::IP::Endpoint const& remoteIPAddress) { Json::Value jvRequest; { Json::Reader reader; if ((request.size () > 1000000) || ! reader.parse (request, jvRequest) || jvRequest.isNull () || ! jvRequest.isObject ()) { return createResponse (400, "Unable to parse request"); } } auto const role = getConfig ().getAdminRole (jvRequest, remoteIPAddress); Resource::Consumer usage; if (role == Config::ADMIN) usage = m_resourceManager.newAdminEndpoint (remoteIPAddress.to_string()); else usage = m_resourceManager.newInboundEndpoint(remoteIPAddress); if (usage.disconnect ()) return createResponse (503, "Server is overloaded"); // Parse id now so errors from here on will have the id // // VFALCO NOTE Except that "id" isn't included in the following errors. // Json::Value const id = jvRequest ["id"]; Json::Value const method = jvRequest ["method"]; if (method.isNull ()) return createResponse (400, "Null method"); if (! method.isString ()) return createResponse (400, "method is not string"); std::string strMethod = method.asString (); if (strMethod.empty()) return createResponse (400, "method is empty"); // Parse params Json::Value params = jvRequest ["params"]; if (params.isNull ()) params = Json::Value (Json::arrayValue); else if (!params.isArray ()) return HTTPReply (400, "params unparseable"); // VFALCO TODO Shouldn't we handle this earlier? // if (role == Config::FORBID) { // VFALCO TODO Needs implementing // FIXME Needs implementing // XXX This needs rate limiting to prevent brute forcing password. return HTTPReply (403, "Forbidden"); } std::string response; RPCHandler rpcHandler (m_networkOPs); Resource::Charge loadType = Resource::feeReferenceRPC; m_journal.debug << "Query: " << strMethod << params; Json::Value const result (rpcHandler.doRpcCommand ( strMethod, params, role, loadType)); m_journal.debug << "Reply: " << result; usage.charge (loadType); response = JSONRPCReply (result, Json::Value (), id); return createResponse (200, response); }
// Stolen directly from RPCServerHandler std::string processRequest (std::string const& request, std::string const& remoteAddress) { Json::Value jvRequest; { Json::Reader reader; if (! reader.parse (request, jvRequest) || jvRequest.isNull () || ! jvRequest.isObject ()) { return createResponse (400, "Unable to parse request"); } } Config::Role const role (getConfig ().getAdminRole (jvRequest, remoteAddress)); // Parse id now so errors from here on will have the id // // VFALCO NOTE Except that "id" isn't included in the following errors... // Json::Value const id = jvRequest ["id"]; Json::Value const method = jvRequest ["method"]; if (method.isNull ()) { return createResponse (400, "Null method"); } else if (! method.isString ()) { return createResponse (400, "method is not string"); } std::string strMethod = method.asString (); // Parse params Json::Value params = jvRequest ["params"]; if (params.isNull ()) { params = Json::Value (Json::arrayValue); } else if (!params.isArray ()) { return HTTPReply (400, "params unparseable"); } // VFALCO TODO Shouldn't we handle this earlier? // if (role == Config::FORBID) { // VFALCO TODO Needs implementing // FIXME Needs implementing // XXX This needs rate limiting to prevent brute forcing password. return HTTPReply (403, "Forbidden"); } // This code does all the work on the io_service thread and // has no rate-limiting based on source IP or anything. // This is a temporary safety if ((role != Config::ADMIN) && (getApp().getFeeTrack().isLoadedLocal())) { return HTTPReply (503, "Unable to service at this time"); } std::string response; m_journal.debug << "Query: " << strMethod << params; RPCHandler rpcHandler (&m_networkOPs); LoadType loadType = LT_RPCReference; Json::Value const result (rpcHandler.doRpcCommand ( strMethod, params, role, &loadType)); // VFALCO NOTE We discard loadType since there is no endpoint to punish m_journal.debug << "Reply: " << result; response = JSONRPCReply (result, Json::Value (), id); return createResponse (200, response); }
std::string createResponse ( int statusCode, std::string const& description) { return HTTPReply (statusCode, description); }