RPC code movement: separate out JSON-RPC execution logic from HTTP server logic
This commit is contained in:
parent
c912e22db0
commit
854d013012
1 changed files with 72 additions and 57 deletions
|
@ -809,6 +809,71 @@ static string JSONRPCExecBatch(const Array& vReq)
|
||||||
return write_string(Value(ret), false) + "\n";
|
return write_string(Value(ret), false) + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool HTTPReq_JSONRPC(AcceptedConnection *conn,
|
||||||
|
string& strRequest,
|
||||||
|
map<string, string>& mapHeaders,
|
||||||
|
bool fRun)
|
||||||
|
{
|
||||||
|
// Check authorization
|
||||||
|
if (mapHeaders.count("authorization") == 0)
|
||||||
|
{
|
||||||
|
conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!HTTPAuthorized(mapHeaders))
|
||||||
|
{
|
||||||
|
LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string());
|
||||||
|
/* Deter brute-forcing short passwords.
|
||||||
|
If this results in a DoS the user really
|
||||||
|
shouldn't have their RPC port exposed. */
|
||||||
|
if (mapArgs["-rpcpassword"].size() < 20)
|
||||||
|
MilliSleep(250);
|
||||||
|
|
||||||
|
conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONRequest jreq;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Parse request
|
||||||
|
Value valRequest;
|
||||||
|
if (!read_string(strRequest, valRequest))
|
||||||
|
throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
|
||||||
|
|
||||||
|
string strReply;
|
||||||
|
|
||||||
|
// singleton request
|
||||||
|
if (valRequest.type() == obj_type) {
|
||||||
|
jreq.parse(valRequest);
|
||||||
|
|
||||||
|
Value result = tableRPC.execute(jreq.strMethod, jreq.params);
|
||||||
|
|
||||||
|
// Send reply
|
||||||
|
strReply = JSONRPCReply(result, Value::null, jreq.id);
|
||||||
|
|
||||||
|
// array of requests
|
||||||
|
} else if (valRequest.type() == array_type)
|
||||||
|
strReply = JSONRPCExecBatch(valRequest.get_array());
|
||||||
|
else
|
||||||
|
throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
|
||||||
|
|
||||||
|
conn->stream() << HTTPReply(HTTP_OK, strReply, fRun) << std::flush;
|
||||||
|
}
|
||||||
|
catch (Object& objError)
|
||||||
|
{
|
||||||
|
ErrorReply(conn->stream(), objError, jreq.id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
ErrorReply(conn->stream(), JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void ServiceConnection(AcceptedConnection *conn)
|
void ServiceConnection(AcceptedConnection *conn)
|
||||||
{
|
{
|
||||||
bool fRun = true;
|
bool fRun = true;
|
||||||
|
@ -825,67 +890,17 @@ void ServiceConnection(AcceptedConnection *conn)
|
||||||
// Read HTTP message headers and body
|
// Read HTTP message headers and body
|
||||||
ReadHTTPMessage(conn->stream(), mapHeaders, strRequest, nProto);
|
ReadHTTPMessage(conn->stream(), mapHeaders, strRequest, nProto);
|
||||||
|
|
||||||
if (strURI != "/") {
|
// HTTP Keep-Alive is false; close connection immediately
|
||||||
conn->stream() << HTTPReply(HTTP_NOT_FOUND, "", false) << std::flush;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check authorization
|
|
||||||
if (mapHeaders.count("authorization") == 0)
|
|
||||||
{
|
|
||||||
conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!HTTPAuthorized(mapHeaders))
|
|
||||||
{
|
|
||||||
LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string());
|
|
||||||
/* Deter brute-forcing short passwords.
|
|
||||||
If this results in a DoS the user really
|
|
||||||
shouldn't have their RPC port exposed. */
|
|
||||||
if (mapArgs["-rpcpassword"].size() < 20)
|
|
||||||
MilliSleep(250);
|
|
||||||
|
|
||||||
conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (mapHeaders["connection"] == "close")
|
if (mapHeaders["connection"] == "close")
|
||||||
fRun = false;
|
fRun = false;
|
||||||
|
|
||||||
JSONRequest jreq;
|
if (strURI == "/") {
|
||||||
try
|
if (!HTTPReq_JSONRPC(conn, strRequest, mapHeaders, fRun))
|
||||||
{
|
break;
|
||||||
// Parse request
|
|
||||||
Value valRequest;
|
|
||||||
if (!read_string(strRequest, valRequest))
|
|
||||||
throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
|
|
||||||
|
|
||||||
string strReply;
|
|
||||||
|
|
||||||
// singleton request
|
|
||||||
if (valRequest.type() == obj_type) {
|
|
||||||
jreq.parse(valRequest);
|
|
||||||
|
|
||||||
Value result = tableRPC.execute(jreq.strMethod, jreq.params);
|
|
||||||
|
|
||||||
// Send reply
|
|
||||||
strReply = JSONRPCReply(result, Value::null, jreq.id);
|
|
||||||
|
|
||||||
// array of requests
|
|
||||||
} else if (valRequest.type() == array_type)
|
|
||||||
strReply = JSONRPCExecBatch(valRequest.get_array());
|
|
||||||
else
|
|
||||||
throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
|
|
||||||
|
|
||||||
conn->stream() << HTTPReply(HTTP_OK, strReply, fRun) << std::flush;
|
|
||||||
}
|
}
|
||||||
catch (Object& objError)
|
|
||||||
{
|
else {
|
||||||
ErrorReply(conn->stream(), objError, jreq.id);
|
conn->stream() << HTTPReply(HTTP_NOT_FOUND, "", false) << std::flush;
|
||||||
break;
|
|
||||||
}
|
|
||||||
catch (std::exception& e)
|
|
||||||
{
|
|
||||||
ErrorReply(conn->stream(), JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue