diff options
author | Jeff Garzik <jeff@garzik.org> | 2012-11-09 17:34:25 -0500 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2012-11-09 17:34:25 -0500 |
commit | 8146591a5305a737557aadec56002af4d11dc4b3 (patch) | |
tree | 41655c0dacdade4fb3d0ba92f49e60eae17cf190 /src/bitcoinrpc.cpp | |
parent | b41de54a2c6141db621a77877ec7964b05c98700 (diff) | |
parent | fcf234fc08e445e2e5b4dfd1a35b10e929940244 (diff) |
Merge branch 'http-improvements'
The base bits of pull req #1982.
Diffstat (limited to 'src/bitcoinrpc.cpp')
-rw-r--r-- | src/bitcoinrpc.cpp | 69 |
1 files changed, 57 insertions, 12 deletions
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 43c8da7acd..37f7859324 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -360,6 +360,41 @@ static string HTTPReply(int nStatus, const string& strMsg, bool keepalive) strMsg.c_str()); } +bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto, + string& http_method, string& http_uri) +{ + string str; + getline(stream, str); + + // HTTP request line is space-delimited + vector<string> vWords; + boost::split(vWords, str, boost::is_any_of(" ")); + if (vWords.size() < 2) + return false; + + // HTTP methods permitted: GET, POST + http_method = vWords[0]; + if (http_method != "GET" && http_method != "POST") + return false; + + // HTTP URI must be an absolute path, relative to current host + http_uri = vWords[1]; + if (http_uri.size() == 0 || http_uri[0] != '/') + return false; + + // parse proto, if present + string strProto = ""; + if (vWords.size() > 2) + strProto = vWords[2]; + + proto = 0; + const char *ver = strstr(strProto.c_str(), "HTTP/1."); + if (ver != NULL) + proto = atoi(ver+7); + + return true; +} + int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto) { string str; @@ -375,7 +410,7 @@ int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto) return atoi(vWords[1].c_str()); } -int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet) +int ReadHTTPHeaders(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet) { int nLen = 0; loop @@ -400,17 +435,15 @@ int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHea return nLen; } -int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet) +int ReadHTTPMessage(std::basic_istream<char>& stream, map<string, + string>& mapHeadersRet, string& strMessageRet, + int nProto) { mapHeadersRet.clear(); strMessageRet = ""; - // Read status - int nProto = 0; - int nStatus = ReadHTTPStatus(stream, nProto); - // Read header - int nLen = ReadHTTPHeader(stream, mapHeadersRet); + int nLen = ReadHTTPHeaders(stream, mapHeadersRet); if (nLen < 0 || nLen > (int)MAX_SIZE) return HTTP_INTERNAL_SERVER_ERROR; @@ -432,7 +465,7 @@ int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRe mapHeadersRet["connection"] = "close"; } - return nStatus; + return HTTP_OK; } bool HTTPAuthorized(map<string, string>& mapHeaders) @@ -939,10 +972,17 @@ void ThreadRPCServer3(void* parg) } return; } + + int nProto = 0; map<string, string> mapHeaders; - string strRequest; + string strRequest, strMethod, strURI; + + // Read HTTP request line + if (!ReadHTTPRequestLine(conn->stream(), nProto, strMethod, strURI)) + break; - ReadHTTP(conn->stream(), mapHeaders, strRequest); + // Read HTTP message headers and body + ReadHTTPMessage(conn->stream(), mapHeaders, strRequest, nProto); // Check authorization if (mapHeaders.count("authorization") == 0) @@ -1074,10 +1114,15 @@ Object CallRPC(const string& strMethod, const Array& params) string strPost = HTTPPost(strRequest, mapRequestHeaders); stream << strPost << std::flush; - // Receive reply + // Receive HTTP reply status + int nProto = 0; + int nStatus = ReadHTTPStatus(stream, nProto); + + // Receive HTTP reply message headers and body map<string, string> mapHeaders; string strReply; - int nStatus = ReadHTTP(stream, mapHeaders, strReply); + ReadHTTPMessage(stream, mapHeaders, strReply, nProto); + if (nStatus == HTTP_UNAUTHORIZED) throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)"); else if (nStatus >= 400 && nStatus != HTTP_BAD_REQUEST && nStatus != HTTP_NOT_FOUND && nStatus != HTTP_INTERNAL_SERVER_ERROR) |