aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJeff Garzik <jgarzik@bitpay.com>2014-06-04 11:24:43 -0400
committerJeff Garzik <jgarzik@bitpay.com>2014-06-26 23:32:18 -0400
commitc912e22db08d0a44ad6fd027c09bbdf79c34dbbc (patch)
tree0eb4939d21c7900a4bbbcdb35488d898bf2d3999 /src
parent236ae8665efadf7b4456c0a9fbf204a5cb4ce9f4 (diff)
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
Diffstat (limited to 'src')
-rw-r--r--src/rpcprotocol.cpp17
-rw-r--r--src/rpcprotocol.h14
-rw-r--r--src/rpcserver.cpp10
3 files changed, 27 insertions, 14 deletions
diff --git a/src/rpcprotocol.cpp b/src/rpcprotocol.cpp
index 2718f81783..bfa799f84f 100644
--- a/src/rpcprotocol.cpp
+++ b/src/rpcprotocol.cpp
@@ -54,7 +54,8 @@ static string rfc1123Time()
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)
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"
"<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";
@@ -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_INTERNAL_SERVER_ERROR) cStatus = "Internal Server Error";
else cStatus = "";
+
+ bool useInternalContent = false;
+ if (nStatus != HTTP_OK) {
+ contentType = "text/plain";
+ useInternalContent = true;
+ }
+
return strprintf(
"HTTP/1.1 %d %s\r\n"
"Date: %s\r\n"
"Connection: %s\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"
"\r\n"
"%s",
@@ -94,8 +103,10 @@ string HTTPReply(int nStatus, const string& strMsg, bool keepalive)
rfc1123Time(),
keepalive ? "keep-alive" : "close",
strMsg.size(),
+ contentType,
FormatFullVersion(),
- strMsg);
+ headersOnly ? "" :
+ useInternalContent ? cStatus : strMsg.c_str());
}
bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto,
diff --git a/src/rpcprotocol.h b/src/rpcprotocol.h
index 11bdd171d9..8d415efb1b 100644
--- a/src/rpcprotocol.h
+++ b/src/rpcprotocol.h
@@ -71,6 +71,16 @@ enum RPCErrorCode
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
//
@@ -141,7 +151,9 @@ private:
};
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,
std::string& http_method, std::string& http_uri);
int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto);
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index 6552de8c49..b85b17c812 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -393,16 +393,6 @@ bool ClientAllowed(const boost::asio::ip::address& address)
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>
class AcceptedConnectionImpl : public AcceptedConnection
{