Browse Source

fix RPC error replies

After pull #4288, RPC messages indicating errors have a Content-Length unrelated
to their actual contents, rendering bitcoin-cli and curl unable to decode the
reply.

This patch sets the Content-Length field based on the actual content returned.

Additionally, pull #4288 clobbered the error descriptions provided in
ErrorReply, which bitcoin-cli relies upon; this patch moves #4288 http-error
descriptions to an HTTPError method, allowing HTTPReply to pass content on
unchanged.
pull/145/head
kazcw 10 years ago
parent
commit
16f33f163d
  1. 42
      src/rpcprotocol.cpp
  2. 2
      src/rpcprotocol.h
  3. 8
      src/rpcserver.cpp

42
src/rpcprotocol.cpp

@ -54,8 +54,19 @@ static string rfc1123Time()
return DateTimeStrFormat("%a, %d %b %Y %H:%M:%S +0000", GetTime());
}
string HTTPReply(int nStatus, const string& strMsg, bool keepalive,
bool headersOnly, const char *contentType)
static const char *httpStatusDescription(int nStatus)
{
switch (nStatus) {
case HTTP_OK: return "OK";
case HTTP_BAD_REQUEST: return "Bad Request";
case HTTP_FORBIDDEN: return "Forbidden";
case HTTP_NOT_FOUND: return "Not Found";
case HTTP_INTERNAL_SERVER_ERROR: return "Internal Server Error";
default: return "";
}
}
string HTTPError(int nStatus, bool keepalive, bool headersOnly)
{
if (nStatus == HTTP_UNAUTHORIZED)
return strprintf("HTTP/1.0 401 Authorization Required\r\n"
@ -75,20 +86,13 @@ string HTTPReply(int nStatus, const string& strMsg, bool keepalive,
"<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
"</HTML>\r\n", rfc1123Time(), FormatFullVersion());
const char *cStatus;
if (nStatus == HTTP_OK) cStatus = "OK";
else if (nStatus == HTTP_BAD_REQUEST) cStatus = "Bad Request";
else if (nStatus == HTTP_FORBIDDEN) cStatus = "Forbidden";
else if (nStatus == HTTP_NOT_FOUND) cStatus = "Not Found";
else if (nStatus == HTTP_INTERNAL_SERVER_ERROR) cStatus = "Internal Server Error";
else cStatus = "";
bool useInternalContent = false;
if (nStatus != HTTP_OK) {
contentType = "text/plain";
useInternalContent = true;
}
return HTTPReply(nStatus, httpStatusDescription(nStatus), keepalive,
headersOnly, "text/plain");
}
string HTTPReply(int nStatus, const string& strMsg, bool keepalive,
bool headersOnly, const char *contentType)
{
return strprintf(
"HTTP/1.1 %d %s\r\n"
"Date: %s\r\n"
@ -99,14 +103,14 @@ string HTTPReply(int nStatus, const string& strMsg, bool keepalive,
"\r\n"
"%s",
nStatus,
cStatus,
httpStatusDescription(nStatus),
rfc1123Time(),
keepalive ? "keep-alive" : "close",
strMsg.size(),
(headersOnly ? 0 : strMsg.size()),
contentType,
FormatFullVersion(),
(headersOnly ? "" :
(useInternalContent ? cStatus : strMsg.c_str())));
(headersOnly ? "" : strMsg.c_str())
);
}
bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto,

2
src/rpcprotocol.h

@ -141,6 +141,8 @@ private:
};
std::string HTTPPost(const std::string& strMsg, const std::map<std::string,std::string>& mapRequestHeaders);
std::string HTTPError(int nStatus, bool keepalive,
bool headerOnly = false);
std::string HTTPReply(int nStatus, const std::string& strMsg, bool keepalive,
bool headerOnly = false,
const char *contentType = "application/json");

8
src/rpcserver.cpp

@ -481,7 +481,7 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol,
{
// Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
if (!fUseSSL)
conn->stream() << HTTPReply(HTTP_FORBIDDEN, "", false) << std::flush;
conn->stream() << HTTPError(HTTP_FORBIDDEN, false) << std::flush;
conn->close();
}
else {
@ -807,7 +807,7 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn,
// Check authorization
if (mapHeaders.count("authorization") == 0)
{
conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush;
conn->stream() << HTTPError(HTTP_UNAUTHORIZED, false) << std::flush;
return false;
}
@ -820,7 +820,7 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn,
if (mapArgs["-rpcpassword"].size() < 20)
MilliSleep(250);
conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush;
conn->stream() << HTTPError(HTTP_UNAUTHORIZED, false) << std::flush;
return false;
}
@ -888,7 +888,7 @@ void ServiceConnection(AcceptedConnection *conn)
if (!HTTPReq_JSONRPC(conn, strRequest, mapHeaders, fRun))
break;
} else {
conn->stream() << HTTPReply(HTTP_NOT_FOUND, "", false) << std::flush;
conn->stream() << HTTPError(HTTP_NOT_FOUND, false) << std::flush;
break;
}
}

Loading…
Cancel
Save