RPC: Support HTTP/1.0 and HTTP/1.1, including the proper use of keep-alives
This commit is contained in:
parent
e9205293bd
commit
96c5269511
1 changed files with 38 additions and 12 deletions
|
@ -2357,7 +2357,7 @@ string rfc1123Time()
|
||||||
return string(buffer);
|
return string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static string HTTPReply(int nStatus, const string& strMsg)
|
static string HTTPReply(int nStatus, const string& strMsg, bool keepalive)
|
||||||
{
|
{
|
||||||
if (nStatus == 401)
|
if (nStatus == 401)
|
||||||
return strprintf("HTTP/1.0 401 Authorization Required\r\n"
|
return strprintf("HTTP/1.0 401 Authorization Required\r\n"
|
||||||
|
@ -2386,7 +2386,7 @@ static string HTTPReply(int nStatus, const string& strMsg)
|
||||||
return strprintf(
|
return strprintf(
|
||||||
"HTTP/1.1 %d %s\r\n"
|
"HTTP/1.1 %d %s\r\n"
|
||||||
"Date: %s\r\n"
|
"Date: %s\r\n"
|
||||||
"Connection: close\r\n"
|
"Connection: %s\r\n"
|
||||||
"Content-Length: %d\r\n"
|
"Content-Length: %d\r\n"
|
||||||
"Content-Type: application/json\r\n"
|
"Content-Type: application/json\r\n"
|
||||||
"Server: bitcoin-json-rpc/%s\r\n"
|
"Server: bitcoin-json-rpc/%s\r\n"
|
||||||
|
@ -2395,12 +2395,13 @@ static string HTTPReply(int nStatus, const string& strMsg)
|
||||||
nStatus,
|
nStatus,
|
||||||
cStatus,
|
cStatus,
|
||||||
rfc1123Time().c_str(),
|
rfc1123Time().c_str(),
|
||||||
|
keepalive ? "keep-alive" : "close",
|
||||||
strMsg.size(),
|
strMsg.size(),
|
||||||
FormatFullVersion().c_str(),
|
FormatFullVersion().c_str(),
|
||||||
strMsg.c_str());
|
strMsg.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
int ReadHTTPStatus(std::basic_istream<char>& stream)
|
int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto)
|
||||||
{
|
{
|
||||||
string str;
|
string str;
|
||||||
getline(stream, str);
|
getline(stream, str);
|
||||||
|
@ -2408,6 +2409,10 @@ int ReadHTTPStatus(std::basic_istream<char>& stream)
|
||||||
boost::split(vWords, str, boost::is_any_of(" "));
|
boost::split(vWords, str, boost::is_any_of(" "));
|
||||||
if (vWords.size() < 2)
|
if (vWords.size() < 2)
|
||||||
return 500;
|
return 500;
|
||||||
|
proto = 0;
|
||||||
|
const char *ver = strstr(str.c_str(), "HTTP/1.");
|
||||||
|
if (ver != NULL)
|
||||||
|
proto = atoi(ver+7);
|
||||||
return atoi(vWords[1].c_str());
|
return atoi(vWords[1].c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2442,7 +2447,8 @@ int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRe
|
||||||
strMessageRet = "";
|
strMessageRet = "";
|
||||||
|
|
||||||
// Read status
|
// Read status
|
||||||
int nStatus = ReadHTTPStatus(stream);
|
int nProto;
|
||||||
|
int nStatus = ReadHTTPStatus(stream, nProto);
|
||||||
|
|
||||||
// Read header
|
// Read header
|
||||||
int nLen = ReadHTTPHeader(stream, mapHeadersRet);
|
int nLen = ReadHTTPHeader(stream, mapHeadersRet);
|
||||||
|
@ -2457,6 +2463,16 @@ int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRe
|
||||||
strMessageRet = string(vch.begin(), vch.end());
|
strMessageRet = string(vch.begin(), vch.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string sConHdr = mapHeadersRet["connection"];
|
||||||
|
|
||||||
|
if ((sConHdr != "close") && (sConHdr != "keep-alive"))
|
||||||
|
{
|
||||||
|
if (nProto >= 1)
|
||||||
|
mapHeadersRet["connection"] = "keep-alive";
|
||||||
|
else
|
||||||
|
mapHeadersRet["connection"] = "close";
|
||||||
|
}
|
||||||
|
|
||||||
return nStatus;
|
return nStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2509,7 +2525,7 @@ void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
|
||||||
if (code == -32600) nStatus = 400;
|
if (code == -32600) nStatus = 400;
|
||||||
else if (code == -32601) nStatus = 404;
|
else if (code == -32601) nStatus = 404;
|
||||||
string strReply = JSONRPCReply(Value::null, objError, id);
|
string strReply = JSONRPCReply(Value::null, objError, id);
|
||||||
stream << HTTPReply(nStatus, strReply) << std::flush;
|
stream << HTTPReply(nStatus, strReply, false) << std::flush;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClientAllowed(const string& strAddress)
|
bool ClientAllowed(const string& strAddress)
|
||||||
|
@ -2681,7 +2697,7 @@ void ThreadRPCServer2(void* parg)
|
||||||
{
|
{
|
||||||
// Accept connection
|
// Accept connection
|
||||||
AcceptedConnection *conn =
|
AcceptedConnection *conn =
|
||||||
new AcceptedConnection(io_service, context, fUseSSL);
|
new AcceptedConnection(io_service, context, fUseSSL);
|
||||||
|
|
||||||
vnThreadsRunning[THREAD_RPCLISTENER]--;
|
vnThreadsRunning[THREAD_RPCLISTENER]--;
|
||||||
acceptor.accept(conn->sslStream.lowest_layer(), conn->peer);
|
acceptor.accept(conn->sslStream.lowest_layer(), conn->peer);
|
||||||
|
@ -2700,7 +2716,7 @@ void ThreadRPCServer2(void* parg)
|
||||||
{
|
{
|
||||||
// Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
|
// Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
|
||||||
if (!fUseSSL)
|
if (!fUseSSL)
|
||||||
conn->stream << HTTPReply(403, "") << std::flush;
|
conn->stream << HTTPReply(403, "", false) << std::flush;
|
||||||
delete conn;
|
delete conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2718,7 +2734,15 @@ void ThreadRPCServer3(void* parg)
|
||||||
vnThreadsRunning[THREAD_RPCHANDLER]++;
|
vnThreadsRunning[THREAD_RPCHANDLER]++;
|
||||||
AcceptedConnection *conn = (AcceptedConnection *) parg;
|
AcceptedConnection *conn = (AcceptedConnection *) parg;
|
||||||
|
|
||||||
do {
|
bool fRun = true;
|
||||||
|
loop {
|
||||||
|
if (fShutdown || !fRun)
|
||||||
|
{
|
||||||
|
conn->stream.close();
|
||||||
|
delete conn;
|
||||||
|
--vnThreadsRunning[THREAD_RPCHANDLER];
|
||||||
|
return;
|
||||||
|
}
|
||||||
map<string, string> mapHeaders;
|
map<string, string> mapHeaders;
|
||||||
string strRequest;
|
string strRequest;
|
||||||
|
|
||||||
|
@ -2727,7 +2751,7 @@ void ThreadRPCServer3(void* parg)
|
||||||
// Check authorization
|
// Check authorization
|
||||||
if (mapHeaders.count("authorization") == 0)
|
if (mapHeaders.count("authorization") == 0)
|
||||||
{
|
{
|
||||||
conn->stream << HTTPReply(401, "") << std::flush;
|
conn->stream << HTTPReply(401, "", false) << std::flush;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!HTTPAuthorized(mapHeaders))
|
if (!HTTPAuthorized(mapHeaders))
|
||||||
|
@ -2739,9 +2763,11 @@ void ThreadRPCServer3(void* parg)
|
||||||
if (mapArgs["-rpcpassword"].size() < 20)
|
if (mapArgs["-rpcpassword"].size() < 20)
|
||||||
Sleep(250);
|
Sleep(250);
|
||||||
|
|
||||||
conn->stream << HTTPReply(401, "") << std::flush;
|
conn->stream << HTTPReply(401, "", false) << std::flush;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (mapHeaders["connection"] == "close")
|
||||||
|
fRun = false;
|
||||||
|
|
||||||
Value id = Value::null;
|
Value id = Value::null;
|
||||||
try
|
try
|
||||||
|
@ -2779,7 +2805,7 @@ void ThreadRPCServer3(void* parg)
|
||||||
|
|
||||||
// Send reply
|
// Send reply
|
||||||
string strReply = JSONRPCReply(result, Value::null, id);
|
string strReply = JSONRPCReply(result, Value::null, id);
|
||||||
conn->stream << HTTPReply(200, strReply) << std::flush;
|
conn->stream << HTTPReply(200, strReply, fRun) << std::flush;
|
||||||
}
|
}
|
||||||
catch (Object& objError)
|
catch (Object& objError)
|
||||||
{
|
{
|
||||||
|
@ -2792,7 +2818,7 @@ void ThreadRPCServer3(void* parg)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (0);
|
|
||||||
delete conn;
|
delete conn;
|
||||||
vnThreadsRunning[THREAD_RPCHANDLER]--;
|
vnThreadsRunning[THREAD_RPCHANDLER]--;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue