示例#1
0
static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
{
    // JSONRPC handles only POST
    if (req->GetRequestMethod() != HTTPRequest::POST) {
        req->WriteReply(HTTP_BAD_METHOD, "JSONRPC server handles only POST requests");
        return false;
    }
    // Check authorization
    std::pair<bool, std::string> authHeader = req->GetHeader("authorization");
    if (!authHeader.first) {
        req->WriteReply(HTTP_UNAUTHORIZED);
        return false;
    }

    if (!RPCAuthorized(authHeader.second)) {
        LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", req->GetPeer().ToString());

        /* Deter brute-forcing
           If this results in a DoS the user really
           shouldn't have their RPC port exposed. */
        MilliSleep(250);

        req->WriteReply(HTTP_UNAUTHORIZED);
        return false;
    }

    JSONRequest jreq;
    try {
        // Parse request
        UniValue valRequest;
        if (!valRequest.read(req->ReadBody()))
            throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");

        std::string strReply;
        // singleton request
        if (valRequest.isObject()) {
            jreq.parse(valRequest);

            UniValue result = tableRPC.execute(jreq.strMethod, jreq.params);

            // Send reply
            strReply = JSONRPCReply(result, NullUniValue, jreq.id);

        // array of requests
        } else if (valRequest.isArray())
            strReply = JSONRPCExecBatch(valRequest.get_array());
        else
            throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");

        req->WriteHeader("Content-Type", "application/json");
        req->WriteReply(HTTP_OK, strReply);
    } catch (const UniValue& objError) {
        JSONErrorReply(req, objError, jreq.id);
        return false;
    } catch (const std::exception& e) {
        JSONErrorReply(req, JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
        return false;
    }
    return true;
}
示例#2
0
void ErrorReply (std::ostream& stream, Json::Value const& objError, Json::Value const& id)
{
    // Send error reply from json-rpc error object
    int nStatus = 500;
    int code = objError[jss::code].asInt ();

    if (code == -32600) nStatus = 400;
    else if (code == -32601) nStatus = 404;

    std::string strReply = JSONRPCReply (Json::Value (), objError, id);
    stream << HTTPReply (nStatus, strReply) << std::flush;
}
示例#3
0
static void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const UniValue& id)
{
    // Send error reply from json-rpc error object
    int nStatus = HTTP_INTERNAL_SERVER_ERROR;
    int code = find_value(objError, "code").get_int();

    if (code == RPC_INVALID_REQUEST)
        nStatus = HTTP_BAD_REQUEST;
    else if (code == RPC_METHOD_NOT_FOUND)
        nStatus = HTTP_NOT_FOUND;

    std::string strReply = JSONRPCReply(NullUniValue, objError, id);

    req->WriteHeader("Content-Type", "application/json");
    req->WriteReply(nStatus, strReply);
}
示例#4
0
void ThreadCli()
{
    // - Simple persistent cli
    //   TODO:
    //      unbuffered terminal input on linux
    //      format help text
    
    char buffer[4096];
    size_t n;
    fd_set rfds;
    struct timeval tv;
    
    printf("vTorrent CLI ready:\n> ");
    fflush(stdout);
    
    for (;;)
    {
        boost::this_thread::interruption_point();
        
        // - must be set every iteration
        FD_ZERO(&rfds);
        FD_SET(STDIN_FILENO, &rfds);
        tv.tv_sec = 0;
        tv.tv_usec = 200000;
        
        if (select(1, &rfds, NULL, NULL, &tv) < 1) // read blocks thread from interrupt
            continue;
        
        if ((n = read(STDIN_FILENO, buffer, sizeof(buffer))) < 1)
            continue;
        
        buffer[n] = '\0';
        for ( ; n > 0 && (buffer[n-1] == '\n' || buffer[n-1] == '\r'); --n)
            buffer[n-1] = '\0';
        
        if (strcmp(buffer, "stop") == 0
            || strcmp(buffer, "exit") == 0
            || strcmp(buffer, "quit") == 0
            || strcmp(buffer, "q") == 0)
        {
            puts("Exiting...");
            break;
        };
        
        
        std::string strMethod;
        std::vector<std::string> strParams;
        char *p;
        if ((p = strchr(buffer, ' ')))
        {
            strMethod = std::string(buffer, p);
            
            char *pPS = p+1;
            char *pPE = p+1;
            while (*pPS
                && ((pPE = strchr(pPS, ' '))
                || (pPE = strchr(pPS, '\0'))))
            {
                strParams.push_back(std::string(pPS, pPE));
                pPS = pPE+1;
            };
        } else
        {
            strMethod = std::string(buffer);
        };
        
        std::string strReply;
        JSONRequest jreq;
        
        try
        {
            json_spirit::Array params = RPCConvertValues(strMethod, strParams);
            json_spirit::Value result = tableRPC.execute(strMethod, params);
            
            strReply = json_spirit::write_string(result, true);
            
            ReplaceStrInPlace(strReply, "\\n", "\n"); // format help msg
            
            if (write(STDOUT_FILENO, strReply.data(), strReply.length()) != (uint32_t) strReply.length())
                throw std::runtime_error("write failed.");
            
            printf("\n> ");
            fflush(stdout);
        } catch (json_spirit::Object& objError)
        {
            std::string strReply = JSONRPCReply(json_spirit::Value::null, objError, 0);
            printf("Error: %s\n> ", strReply.c_str());
            fflush(stdout);
        } catch (std::exception& e)
        {
            printf("Error: %s\n> ", e.what());
            fflush(stdout);
        };
        fflush(stdout);
    };
    
    StartShutdown();
};
// VFALCO ARGH! returning a single std::string for the entire response?
std::string
ServerHandlerImp::processRequest (std::string const& request,
    beast::IP::Endpoint const& remoteIPAddress)
{
    Json::Value jvRequest;
    {
        Json::Reader reader;
        if ((request.size () > 1000000) ||
            ! reader.parse (request, jvRequest) ||
            jvRequest.isNull () ||
            ! jvRequest.isObject ())
        {
            return createResponse (400, "Unable to parse request");
        }
    }

    auto const role = getConfig ().getAdminRole (jvRequest, remoteIPAddress);

    Resource::Consumer usage;

    if (role == Config::ADMIN)
        usage = m_resourceManager.newAdminEndpoint (remoteIPAddress.to_string());
    else
        usage = m_resourceManager.newInboundEndpoint(remoteIPAddress);

    if (usage.disconnect ())
        return createResponse (503, "Server is overloaded");

    // Parse id now so errors from here on will have the id
    //
    // VFALCO NOTE Except that "id" isn't included in the following errors.
    //
    Json::Value const id = jvRequest ["id"];

    Json::Value const method = jvRequest ["method"];

    if (method.isNull ())
        return createResponse (400, "Null method");

    if (! method.isString ())
        return createResponse (400, "method is not string");

    std::string strMethod = method.asString ();
    if (strMethod.empty())
        return createResponse (400, "method is empty");

    // Parse params
    Json::Value params = jvRequest ["params"];

    if (params.isNull ())
        params = Json::Value (Json::arrayValue);

    else if (!params.isArray ())
        return HTTPReply (400, "params unparseable");

    // VFALCO TODO Shouldn't we handle this earlier?
    //
    if (role == Config::FORBID)
    {
        // VFALCO TODO Needs implementing
        // FIXME Needs implementing
        // XXX This needs rate limiting to prevent brute forcing password.
        return HTTPReply (403, "Forbidden");
    }


    std::string response;
    RPCHandler rpcHandler (m_networkOPs);
    Resource::Charge loadType = Resource::feeReferenceRPC;

    m_journal.debug << "Query: " << strMethod << params;

    Json::Value const result (rpcHandler.doRpcCommand (
        strMethod, params, role, loadType));
    m_journal.debug << "Reply: " << result;

    usage.charge (loadType);

    response = JSONRPCReply (result, Json::Value (), id);

    return createResponse (200, response);
}
示例#6
0
    // Stolen directly from RPCServerHandler
    std::string processRequest (std::string const& request, std::string const& remoteAddress)
    {
        Json::Value jvRequest;
        {
            Json::Reader reader;

            if (! reader.parse (request, jvRequest) ||
                jvRequest.isNull () ||
                ! jvRequest.isObject ())
            {
                return createResponse (400, "Unable to parse request");
            }
        }

        Config::Role const role (getConfig ().getAdminRole (jvRequest, remoteAddress));

        // Parse id now so errors from here on will have the id
        //
        // VFALCO NOTE Except that "id" isn't included in the following errors...
        //
        Json::Value const id = jvRequest ["id"];

        Json::Value const method = jvRequest ["method"];

        if (method.isNull ())
        {
            return createResponse (400, "Null method");
        }
        else if (! method.isString ())
        {
            return createResponse (400, "method is not string");
        }

        std::string strMethod = method.asString ();

        // Parse params
        Json::Value params = jvRequest ["params"];

        if (params.isNull ())
        {
            params = Json::Value (Json::arrayValue);
        }
        else if (!params.isArray ())
        {
            return HTTPReply (400, "params unparseable");
        }

        // VFALCO TODO Shouldn't we handle this earlier?
        //
        if (role == Config::FORBID)
        {
            // VFALCO TODO Needs implementing
            // FIXME Needs implementing
            // XXX This needs rate limiting to prevent brute forcing password.
            return HTTPReply (403, "Forbidden");
        }

        // This code does all the work on the io_service thread and
        // has no rate-limiting based on source IP or anything.
        // This is a temporary safety
        if ((role != Config::ADMIN) && (getApp().getFeeTrack().isLoadedLocal()))
        {
            return HTTPReply (503, "Unable to service at this time");
        }

        std::string response;

        m_journal.debug << "Query: " << strMethod << params;

        RPCHandler rpcHandler (&m_networkOPs);

        LoadType loadType = LT_RPCReference;

        Json::Value const result (rpcHandler.doRpcCommand (
            strMethod, params, role, &loadType));
        // VFALCO NOTE We discard loadType since there is no endpoint to punish

        m_journal.debug << "Reply: " << result;

        response = JSONRPCReply (result, Json::Value (), id);

        return createResponse (200, response);
    }