|
|
@ -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) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ErrorReply(conn->stream(), objError, jreq.id); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
catch (std::exception& e) |
|
|
|
|
|
|
|
{ |
|
|
|
else { |
|
|
|
ErrorReply(conn->stream(), JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id); |
|
|
|
conn->stream() << HTTPReply(HTTP_NOT_FOUND, "", false) << std::flush; |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|