diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 43c8da7ac..37f785932 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& stream, int &proto, + string& http_method, string& http_uri) +{ + string str; + getline(stream, str); + + // HTTP request line is space-delimited + vector 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& stream, int &proto) { string str; @@ -375,7 +410,7 @@ int ReadHTTPStatus(std::basic_istream& stream, int &proto) return atoi(vWords[1].c_str()); } -int ReadHTTPHeader(std::basic_istream& stream, map& mapHeadersRet) +int ReadHTTPHeaders(std::basic_istream& stream, map& mapHeadersRet) { int nLen = 0; loop @@ -400,17 +435,15 @@ int ReadHTTPHeader(std::basic_istream& stream, map& mapHea return nLen; } -int ReadHTTP(std::basic_istream& stream, map& mapHeadersRet, string& strMessageRet) +int ReadHTTPMessage(std::basic_istream& stream, map& 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& stream, map& mapHeadersRe mapHeadersRet["connection"] = "close"; } - return nStatus; + return HTTP_OK; } bool HTTPAuthorized(map& mapHeaders) @@ -939,10 +972,17 @@ void ThreadRPCServer3(void* parg) } return; } + + int nProto = 0; map 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 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)