Browse Source

RPC cleanup: Improve HTTP server replies

1) support varying content types
2) support only sending the header
3) properly deliver error message as content, if HTTP error
4) move AcceptedConnection class to header, for wider use
0.10
Jeff Garzik 11 years ago
parent
commit
c912e22db0
  1. 17
      src/rpcprotocol.cpp
  2. 14
      src/rpcprotocol.h
  3. 10
      src/rpcserver.cpp

17
src/rpcprotocol.cpp

@ -54,7 +54,8 @@ static string rfc1123Time()
return DateTimeStrFormat("%a, %d %b %Y %H:%M:%S +0000", GetTime()); return DateTimeStrFormat("%a, %d %b %Y %H:%M:%S +0000", GetTime());
} }
string HTTPReply(int nStatus, const string& strMsg, bool keepalive) string HTTPReply(int nStatus, const string& strMsg, bool keepalive,
bool headersOnly, const char *contentType)
{ {
if (nStatus == HTTP_UNAUTHORIZED) if (nStatus == HTTP_UNAUTHORIZED)
return strprintf("HTTP/1.0 401 Authorization Required\r\n" return strprintf("HTTP/1.0 401 Authorization Required\r\n"
@ -73,6 +74,7 @@ string HTTPReply(int nStatus, const string& strMsg, bool keepalive)
"</HEAD>\r\n" "</HEAD>\r\n"
"<BODY><H1>401 Unauthorized.</H1></BODY>\r\n" "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
"</HTML>\r\n", rfc1123Time(), FormatFullVersion()); "</HTML>\r\n", rfc1123Time(), FormatFullVersion());
const char *cStatus; const char *cStatus;
if (nStatus == HTTP_OK) cStatus = "OK"; if (nStatus == HTTP_OK) cStatus = "OK";
else if (nStatus == HTTP_BAD_REQUEST) cStatus = "Bad Request"; else if (nStatus == HTTP_BAD_REQUEST) cStatus = "Bad Request";
@ -80,12 +82,19 @@ string HTTPReply(int nStatus, const string& strMsg, bool keepalive)
else if (nStatus == HTTP_NOT_FOUND) cStatus = "Not Found"; else if (nStatus == HTTP_NOT_FOUND) cStatus = "Not Found";
else if (nStatus == HTTP_INTERNAL_SERVER_ERROR) cStatus = "Internal Server Error"; else if (nStatus == HTTP_INTERNAL_SERVER_ERROR) cStatus = "Internal Server Error";
else cStatus = ""; else cStatus = "";
bool useInternalContent = false;
if (nStatus != HTTP_OK) {
contentType = "text/plain";
useInternalContent = true;
}
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: %s\r\n" "Connection: %s\r\n"
"Content-Length: %u\r\n" "Content-Length: %u\r\n"
"Content-Type: application/json\r\n" "Content-Type: %s\r\n"
"Server: bitcoin-json-rpc/%s\r\n" "Server: bitcoin-json-rpc/%s\r\n"
"\r\n" "\r\n"
"%s", "%s",
@ -94,8 +103,10 @@ string HTTPReply(int nStatus, const string& strMsg, bool keepalive)
rfc1123Time(), rfc1123Time(),
keepalive ? "keep-alive" : "close", keepalive ? "keep-alive" : "close",
strMsg.size(), strMsg.size(),
contentType,
FormatFullVersion(), FormatFullVersion(),
strMsg); headersOnly ? "" :
useInternalContent ? cStatus : strMsg.c_str());
} }
bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto, bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto,

14
src/rpcprotocol.h

@ -71,6 +71,16 @@ enum RPCErrorCode
RPC_WALLET_ALREADY_UNLOCKED = -17, // Wallet is already unlocked RPC_WALLET_ALREADY_UNLOCKED = -17, // Wallet is already unlocked
}; };
class AcceptedConnection
{
public:
virtual ~AcceptedConnection() {}
virtual std::iostream& stream() = 0;
virtual std::string peer_address_to_string() const = 0;
virtual void close() = 0;
};
// //
// IOStream device that speaks SSL but can also speak non-SSL // IOStream device that speaks SSL but can also speak non-SSL
// //
@ -141,7 +151,9 @@ private:
}; };
std::string HTTPPost(const std::string& strMsg, const std::map<std::string,std::string>& mapRequestHeaders); std::string HTTPPost(const std::string& strMsg, const std::map<std::string,std::string>& mapRequestHeaders);
std::string HTTPReply(int nStatus, const std::string& strMsg, bool keepalive); std::string HTTPReply(int nStatus, const std::string& strMsg, bool keepalive,
bool headerOnly = false,
const char *contentType = "application/json");
bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto, bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto,
std::string& http_method, std::string& http_uri); std::string& http_method, std::string& http_uri);
int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto); int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto);

10
src/rpcserver.cpp

@ -393,16 +393,6 @@ bool ClientAllowed(const boost::asio::ip::address& address)
return false; return false;
} }
class AcceptedConnection
{
public:
virtual ~AcceptedConnection() {}
virtual std::iostream& stream() = 0;
virtual std::string peer_address_to_string() const = 0;
virtual void close() = 0;
};
template <typename Protocol> template <typename Protocol>
class AcceptedConnectionImpl : public AcceptedConnection class AcceptedConnectionImpl : public AcceptedConnection
{ {

Loading…
Cancel
Save