|
|
|
@ -116,17 +116,42 @@ static bool AppInitRPC(int argc, char* argv[])
@@ -116,17 +116,42 @@ static bool AppInitRPC(int argc, char* argv[])
|
|
|
|
|
/** Reply structure for request_done to fill in */ |
|
|
|
|
struct HTTPReply |
|
|
|
|
{ |
|
|
|
|
HTTPReply(): status(0), error(-1) {} |
|
|
|
|
|
|
|
|
|
int status; |
|
|
|
|
int error; |
|
|
|
|
std::string body; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const char *http_errorstring(int code) |
|
|
|
|
{ |
|
|
|
|
switch(code) { |
|
|
|
|
#if LIBEVENT_VERSION_NUMBER >= 0x02010300 |
|
|
|
|
case EVREQ_HTTP_TIMEOUT: |
|
|
|
|
return "timeout reached"; |
|
|
|
|
case EVREQ_HTTP_EOF: |
|
|
|
|
return "EOF reached"; |
|
|
|
|
case EVREQ_HTTP_INVALID_HEADER: |
|
|
|
|
return "error while reading header, or invalid header"; |
|
|
|
|
case EVREQ_HTTP_BUFFER_ERROR: |
|
|
|
|
return "error encountered while reading or writing"; |
|
|
|
|
case EVREQ_HTTP_REQUEST_CANCEL: |
|
|
|
|
return "request was canceled"; |
|
|
|
|
case EVREQ_HTTP_DATA_TOO_LONG: |
|
|
|
|
return "response body is larger than allowed"; |
|
|
|
|
#endif |
|
|
|
|
default: |
|
|
|
|
return "unknown"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void http_request_done(struct evhttp_request *req, void *ctx) |
|
|
|
|
{ |
|
|
|
|
HTTPReply *reply = static_cast<HTTPReply*>(ctx); |
|
|
|
|
|
|
|
|
|
if (req == NULL) { |
|
|
|
|
/* If req is NULL, it means an error occurred while connecting, but
|
|
|
|
|
* I'm not sure how to find out which one. We also don't really care. |
|
|
|
|
/* If req is NULL, it means an error occurred while connecting: the
|
|
|
|
|
* error code will have been passed to http_error_cb. |
|
|
|
|
*/ |
|
|
|
|
reply->status = 0; |
|
|
|
|
return; |
|
|
|
@ -145,6 +170,14 @@ static void http_request_done(struct evhttp_request *req, void *ctx)
@@ -145,6 +170,14 @@ static void http_request_done(struct evhttp_request *req, void *ctx)
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#if LIBEVENT_VERSION_NUMBER >= 0x02010300 |
|
|
|
|
static void http_error_cb(enum evhttp_request_error err, void *ctx) |
|
|
|
|
{ |
|
|
|
|
HTTPReply *reply = static_cast<HTTPReply*>(ctx); |
|
|
|
|
reply->error = err; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
UniValue CallRPC(const string& strMethod, const UniValue& params) |
|
|
|
|
{ |
|
|
|
|
std::string host = GetArg("-rpcconnect", DEFAULT_RPCCONNECT); |
|
|
|
@ -165,6 +198,9 @@ UniValue CallRPC(const string& strMethod, const UniValue& params)
@@ -165,6 +198,9 @@ UniValue CallRPC(const string& strMethod, const UniValue& params)
|
|
|
|
|
struct evhttp_request *req = evhttp_request_new(http_request_done, (void*)&response); // TODO RAII
|
|
|
|
|
if (req == NULL) |
|
|
|
|
throw runtime_error("create http request failed"); |
|
|
|
|
#if LIBEVENT_VERSION_NUMBER >= 0x02010300 |
|
|
|
|
evhttp_request_set_error_cb(req, http_error_cb); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
// Get credentials
|
|
|
|
|
std::string strRPCUserColonPass; |
|
|
|
@ -204,7 +240,7 @@ UniValue CallRPC(const string& strMethod, const UniValue& params)
@@ -204,7 +240,7 @@ UniValue CallRPC(const string& strMethod, const UniValue& params)
|
|
|
|
|
event_base_free(base); |
|
|
|
|
|
|
|
|
|
if (response.status == 0) |
|
|
|
|
throw CConnectionFailed("couldn't connect to server"); |
|
|
|
|
throw CConnectionFailed(strprintf("couldn't connect to server (%d %s)", response.error, http_errorstring(response.error))); |
|
|
|
|
else if (response.status == HTTP_UNAUTHORIZED) |
|
|
|
|
throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)"); |
|
|
|
|
else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR) |
|
|
|
|