LCOV - code coverage report
Current view: top level - src - httprpc.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 68 88 77.3 %
Date: 2015-10-12 22:39:14 Functions: 14 17 82.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #include "httprpc.h"
       2             : 
       3             : #include "base58.h"
       4             : #include "chainparams.h"
       5             : #include "httpserver.h"
       6             : #include "rpcprotocol.h"
       7             : #include "rpcserver.h"
       8             : #include "random.h"
       9             : #include "sync.h"
      10             : #include "util.h"
      11             : #include "utilstrencodings.h"
      12             : #include "ui_interface.h"
      13             : 
      14             : #include <boost/algorithm/string.hpp> // boost::trim
      15             : 
      16             : /** Simple one-shot callback timer to be used by the RPC mechanism to e.g.
      17             :  * re-lock the wellet.
      18             :  */
      19           2 : class HTTPRPCTimer : public RPCTimerBase
      20             : {
      21             : public:
      22           1 :     HTTPRPCTimer(struct event_base* eventBase, boost::function<void(void)>& func, int64_t millis) :
      23           2 :         ev(eventBase, false, func)
      24             :     {
      25             :         struct timeval tv;
      26           1 :         tv.tv_sec = millis/1000;
      27           1 :         tv.tv_usec = (millis%1000)*1000;
      28           1 :         ev.trigger(&tv);
      29           1 :     }
      30             : private:
      31             :     HTTPEvent ev;
      32             : };
      33             : 
      34         188 : class HTTPRPCTimerInterface : public RPCTimerInterface
      35             : {
      36             : public:
      37         188 :     HTTPRPCTimerInterface(struct event_base* base) : base(base)
      38             :     {
      39           0 :     }
      40           1 :     const char* Name()
      41             :     {
      42           1 :         return "HTTP";
      43             :     }
      44           1 :     RPCTimerBase* NewTimer(boost::function<void(void)>& func, int64_t millis)
      45             :     {
      46           1 :         return new HTTPRPCTimer(base, func, millis);
      47             :     }
      48             : private:
      49             :     struct event_base* base;
      50             : };
      51             : 
      52             : 
      53             : /* Pre-base64-encoded authentication token */
      54          95 : static std::string strRPCUserColonPass;
      55             : /* Stored RPC timer interface (for unregistration) */
      56             : static HTTPRPCTimerInterface* httpRPCTimerInterface = 0;
      57             : 
      58          12 : static void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const UniValue& id)
      59             : {
      60             :     // Send error reply from json-rpc error object
      61          12 :     int nStatus = HTTP_INTERNAL_SERVER_ERROR;
      62          36 :     int code = find_value(objError, "code").get_int();
      63             : 
      64          12 :     if (code == RPC_INVALID_REQUEST)
      65             :         nStatus = HTTP_BAD_REQUEST;
      66          12 :     else if (code == RPC_METHOD_NOT_FOUND)
      67           0 :         nStatus = HTTP_NOT_FOUND;
      68             : 
      69          12 :     std::string strReply = JSONRPCReply(NullUniValue, objError, id);
      70             : 
      71          60 :     req->WriteHeader("Content-Type", "application/json");
      72          12 :     req->WriteReply(nStatus, strReply);
      73          12 : }
      74             : 
      75        3519 : static bool RPCAuthorized(const std::string& strAuth)
      76             : {
      77        3519 :     if (strRPCUserColonPass.empty()) // Belt-and-suspenders measure if InitRPCAuthentication was not called
      78             :         return false;
      79       10557 :     if (strAuth.substr(0, 6) != "Basic ")
      80             :         return false;
      81        3519 :     std::string strUserPass64 = strAuth.substr(6);
      82        3519 :     boost::trim(strUserPass64);
      83        3519 :     std::string strUserPass = DecodeBase64(strUserPass64);
      84        3519 :     return TimingResistantEqual(strUserPass, strRPCUserColonPass);
      85             : }
      86             : 
      87        3519 : static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
      88             : {
      89             :     // JSONRPC handles only POST
      90        3519 :     if (req->GetRequestMethod() != HTTPRequest::POST) {
      91           0 :         req->WriteReply(HTTP_BAD_METHOD, "JSONRPC server handles only POST requests");
      92           0 :         return false;
      93             :     }
      94             :     // Check authorization
      95       10557 :     std::pair<bool, std::string> authHeader = req->GetHeader("authorization");
      96        3519 :     if (!authHeader.first) {
      97           0 :         req->WriteReply(HTTP_UNAUTHORIZED);
      98           0 :         return false;
      99             :     }
     100             : 
     101        3519 :     if (!RPCAuthorized(authHeader.second)) {
     102           0 :         LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", req->GetPeer().ToString());
     103             : 
     104             :         /* Deter brute-forcing
     105             :            If this results in a DoS the user really
     106             :            shouldn't have their RPC port exposed. */
     107           0 :         MilliSleep(250);
     108             : 
     109           0 :         req->WriteReply(HTTP_UNAUTHORIZED);
     110           0 :         return false;
     111             :     }
     112             : 
     113        7038 :     JSONRequest jreq;
     114             :     try {
     115             :         // Parse request
     116             :         UniValue valRequest;
     117       10557 :         if (!valRequest.read(req->ReadBody()))
     118           0 :             throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
     119             : 
     120             :         std::string strReply;
     121             :         // singleton request
     122        3519 :         if (valRequest.isObject()) {
     123        3519 :             jreq.parse(valRequest);
     124             : 
     125        3519 :             UniValue result = tableRPC.execute(jreq.strMethod, jreq.params);
     126             : 
     127             :             // Send reply
     128        7014 :             strReply = JSONRPCReply(result, NullUniValue, jreq.id);
     129             : 
     130             :         // array of requests
     131           0 :         } else if (valRequest.isArray())
     132           0 :             strReply = JSONRPCExecBatch(valRequest.get_array());
     133             :         else
     134           0 :             throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
     135             : 
     136       17547 :         req->WriteHeader("Content-Type", "application/json");
     137        7026 :         req->WriteReply(HTTP_OK, strReply);
     138          24 :     } catch (const UniValue& objError) {
     139          12 :         JSONErrorReply(req, objError, jreq.id);
     140             :         return false;
     141           0 :     } catch (const std::exception& e) {
     142           0 :         JSONErrorReply(req, JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
     143             :         return false;
     144             :     }
     145        3507 :     return true;
     146             : }
     147             : 
     148          94 : static bool InitRPCAuthentication()
     149             : {
     150         376 :     if (mapArgs["-rpcpassword"] == "")
     151             :     {
     152           0 :         LogPrintf("No rpcpassword set - using random cookie authentication\n");
     153           0 :         if (!GenerateAuthCookie(&strRPCUserColonPass)) {
     154             :             uiInterface.ThreadSafeMessageBox(
     155             :                 _("Error: A fatal internal error occurred, see debug.log for details"), // Same message as AbortNode
     156           0 :                 "", CClientUIInterface::MSG_ERROR);
     157           0 :             return false;
     158             :         }
     159             :     } else {
     160         658 :         strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
     161             :     }
     162             :     return true;
     163             : }
     164             : 
     165          94 : bool StartHTTPRPC()
     166             : {
     167          94 :     LogPrint("rpc", "Starting HTTP RPC server\n");
     168          94 :     if (!InitRPCAuthentication())
     169             :         return false;
     170             : 
     171         376 :     RegisterHTTPHandler("/", true, HTTPReq_JSONRPC);
     172             : 
     173          94 :     assert(EventBase());
     174         188 :     httpRPCTimerInterface = new HTTPRPCTimerInterface(EventBase());
     175          94 :     RPCRegisterTimerInterface(httpRPCTimerInterface);
     176          94 :     return true;
     177             : }
     178             : 
     179          94 : void InterruptHTTPRPC()
     180             : {
     181          94 :     LogPrint("rpc", "Interrupting HTTP RPC server\n");
     182          94 : }
     183             : 
     184          94 : void StopHTTPRPC()
     185             : {
     186          94 :     LogPrint("rpc", "Stopping HTTP RPC server\n");
     187         282 :     UnregisterHTTPHandler("/", true);
     188          94 :     if (httpRPCTimerInterface) {
     189          94 :         RPCUnregisterTimerInterface(httpRPCTimerInterface);
     190          94 :         delete httpRPCTimerInterface;
     191          94 :         httpRPCTimerInterface = 0;
     192             :     }
     193         379 : }

Generated by: LCOV version 1.11