Skip to content

Commit 96c5269

Browse files
JoelKatzJeff Garzik
authored andcommitted
RPC: Support HTTP/1.0 and HTTP/1.1, including the proper use of keep-alives
1 parent e920529 commit 96c5269

File tree

1 file changed

+38
-12
lines changed

1 file changed

+38
-12
lines changed

src/bitcoinrpc.cpp

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2357,7 +2357,7 @@ string rfc1123Time()
23572357
return string(buffer);
23582358
}
23592359

2360-
static string HTTPReply(int nStatus, const string& strMsg)
2360+
static string HTTPReply(int nStatus, const string& strMsg, bool keepalive)
23612361
{
23622362
if (nStatus == 401)
23632363
return strprintf("HTTP/1.0 401 Authorization Required\r\n"
@@ -2386,7 +2386,7 @@ static string HTTPReply(int nStatus, const string& strMsg)
23862386
return strprintf(
23872387
"HTTP/1.1 %d %s\r\n"
23882388
"Date: %s\r\n"
2389-
"Connection: close\r\n"
2389+
"Connection: %s\r\n"
23902390
"Content-Length: %d\r\n"
23912391
"Content-Type: application/json\r\n"
23922392
"Server: bitcoin-json-rpc/%s\r\n"
@@ -2395,19 +2395,24 @@ static string HTTPReply(int nStatus, const string& strMsg)
23952395
nStatus,
23962396
cStatus,
23972397
rfc1123Time().c_str(),
2398+
keepalive ? "keep-alive" : "close",
23982399
strMsg.size(),
23992400
FormatFullVersion().c_str(),
24002401
strMsg.c_str());
24012402
}
24022403

2403-
int ReadHTTPStatus(std::basic_istream<char>& stream)
2404+
int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto)
24042405
{
24052406
string str;
24062407
getline(stream, str);
24072408
vector<string> vWords;
24082409
boost::split(vWords, str, boost::is_any_of(" "));
24092410
if (vWords.size() < 2)
24102411
return 500;
2412+
proto = 0;
2413+
const char *ver = strstr(str.c_str(), "HTTP/1.");
2414+
if (ver != NULL)
2415+
proto = atoi(ver+7);
24112416
return atoi(vWords[1].c_str());
24122417
}
24132418

@@ -2442,7 +2447,8 @@ int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRe
24422447
strMessageRet = "";
24432448

24442449
// Read status
2445-
int nStatus = ReadHTTPStatus(stream);
2450+
int nProto;
2451+
int nStatus = ReadHTTPStatus(stream, nProto);
24462452

24472453
// Read header
24482454
int nLen = ReadHTTPHeader(stream, mapHeadersRet);
@@ -2457,6 +2463,16 @@ int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRe
24572463
strMessageRet = string(vch.begin(), vch.end());
24582464
}
24592465

2466+
string sConHdr = mapHeadersRet["connection"];
2467+
2468+
if ((sConHdr != "close") && (sConHdr != "keep-alive"))
2469+
{
2470+
if (nProto >= 1)
2471+
mapHeadersRet["connection"] = "keep-alive";
2472+
else
2473+
mapHeadersRet["connection"] = "close";
2474+
}
2475+
24602476
return nStatus;
24612477
}
24622478

@@ -2509,7 +2525,7 @@ void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
25092525
if (code == -32600) nStatus = 400;
25102526
else if (code == -32601) nStatus = 404;
25112527
string strReply = JSONRPCReply(Value::null, objError, id);
2512-
stream << HTTPReply(nStatus, strReply) << std::flush;
2528+
stream << HTTPReply(nStatus, strReply, false) << std::flush;
25132529
}
25142530

25152531
bool ClientAllowed(const string& strAddress)
@@ -2681,7 +2697,7 @@ void ThreadRPCServer2(void* parg)
26812697
{
26822698
// Accept connection
26832699
AcceptedConnection *conn =
2684-
new AcceptedConnection(io_service, context, fUseSSL);
2700+
new AcceptedConnection(io_service, context, fUseSSL);
26852701

26862702
vnThreadsRunning[THREAD_RPCLISTENER]--;
26872703
acceptor.accept(conn->sslStream.lowest_layer(), conn->peer);
@@ -2700,7 +2716,7 @@ void ThreadRPCServer2(void* parg)
27002716
{
27012717
// Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
27022718
if (!fUseSSL)
2703-
conn->stream << HTTPReply(403, "") << std::flush;
2719+
conn->stream << HTTPReply(403, "", false) << std::flush;
27042720
delete conn;
27052721
}
27062722

@@ -2718,7 +2734,15 @@ void ThreadRPCServer3(void* parg)
27182734
vnThreadsRunning[THREAD_RPCHANDLER]++;
27192735
AcceptedConnection *conn = (AcceptedConnection *) parg;
27202736

2721-
do {
2737+
bool fRun = true;
2738+
loop {
2739+
if (fShutdown || !fRun)
2740+
{
2741+
conn->stream.close();
2742+
delete conn;
2743+
--vnThreadsRunning[THREAD_RPCHANDLER];
2744+
return;
2745+
}
27222746
map<string, string> mapHeaders;
27232747
string strRequest;
27242748

@@ -2727,7 +2751,7 @@ void ThreadRPCServer3(void* parg)
27272751
// Check authorization
27282752
if (mapHeaders.count("authorization") == 0)
27292753
{
2730-
conn->stream << HTTPReply(401, "") << std::flush;
2754+
conn->stream << HTTPReply(401, "", false) << std::flush;
27312755
break;
27322756
}
27332757
if (!HTTPAuthorized(mapHeaders))
@@ -2739,9 +2763,11 @@ void ThreadRPCServer3(void* parg)
27392763
if (mapArgs["-rpcpassword"].size() < 20)
27402764
Sleep(250);
27412765

2742-
conn->stream << HTTPReply(401, "") << std::flush;
2766+
conn->stream << HTTPReply(401, "", false) << std::flush;
27432767
break;
27442768
}
2769+
if (mapHeaders["connection"] == "close")
2770+
fRun = false;
27452771

27462772
Value id = Value::null;
27472773
try
@@ -2779,7 +2805,7 @@ void ThreadRPCServer3(void* parg)
27792805

27802806
// Send reply
27812807
string strReply = JSONRPCReply(result, Value::null, id);
2782-
conn->stream << HTTPReply(200, strReply) << std::flush;
2808+
conn->stream << HTTPReply(200, strReply, fRun) << std::flush;
27832809
}
27842810
catch (Object& objError)
27852811
{
@@ -2792,7 +2818,7 @@ void ThreadRPCServer3(void* parg)
27922818
break;
27932819
}
27942820
}
2795-
while (0);
2821+
27962822
delete conn;
27972823
vnThreadsRunning[THREAD_RPCHANDLER]--;
27982824
}

0 commit comments

Comments
 (0)