Skip to content

Commit

Permalink
RPC code movement: separate out JSON-RPC execution logic from HTTP se…
Browse files Browse the repository at this point in the history
…rver logic
  • Loading branch information
Jeff Garzik committed Jun 27, 2014
1 parent c912e22 commit 854d013
Showing 1 changed file with 72 additions and 57 deletions.
129 changes: 72 additions & 57 deletions src/rpcserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,71 @@ static string JSONRPCExecBatch(const Array& vReq)
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)
{
bool fRun = true;
Expand All @@ -825,67 +890,17 @@ void ServiceConnection(AcceptedConnection *conn)
// Read HTTP message headers and body
ReadHTTPMessage(conn->stream(), mapHeaders, strRequest, nProto);

if (strURI != "/") {
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;
}
// HTTP Keep-Alive is false; close connection immediately
if (mapHeaders["connection"] == "close")
fRun = 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);
break;
if (strURI == "/") {
if (!HTTPReq_JSONRPC(conn, strRequest, mapHeaders, fRun))
break;
}
catch (std::exception& e)
{
ErrorReply(conn->stream(), JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);

else {
conn->stream() << HTTPReply(HTTP_NOT_FOUND, "", false) << std::flush;
break;
}
}
Expand Down

0 comments on commit 854d013

Please sign in to comment.