mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 04:22:55 +01:00
feat: implementation for /external handler for RPC
This commit is contained in:
parent
3612b8a399
commit
f1c1fd873e
@ -146,7 +146,7 @@ static bool RPCAuthorized(const std::string& strAuth, std::string& strAuthUserna
|
|||||||
return multiUserAuthorized(strUserPass);
|
return multiUserAuthorized(strUserPass);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool HTTPReq_JSONRPC(const CoreContext& context, HTTPRequest* req)
|
static bool HTTPReq_JSONRPC(const CoreContext& context, HTTPRequest* req, bool external = false)
|
||||||
{
|
{
|
||||||
// JSONRPC handles only POST
|
// JSONRPC handles only POST
|
||||||
if (req->GetRequestMethod() != HTTPRequest::POST) {
|
if (req->GetRequestMethod() != HTTPRequest::POST) {
|
||||||
@ -176,6 +176,14 @@ static bool HTTPReq_JSONRPC(const CoreContext& context, HTTPRequest* req)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (jreq.authUser == gArgs.GetArg("-rpcexternaluser", "") && !jreq.authUser.empty()) {
|
||||||
|
if (!external) {
|
||||||
|
LogPrintf("RPC User '%s' is allowed to call rpc only by path /external\n", jreq.authUser);
|
||||||
|
req->WriteReply(HTTP_FORBIDDEN);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LogPrintf("RPC user '%s' is external\n", jreq.authUser);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
// Parse request
|
// Parse request
|
||||||
UniValue valRequest;
|
UniValue valRequest;
|
||||||
@ -298,10 +306,12 @@ bool StartHTTPRPC(const CoreContext& context)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto handle_rpc = [&context](HTTPRequest* req, const std::string&) { return HTTPReq_JSONRPC(context, req); };
|
auto handle_rpc = [&context](HTTPRequest* req, const std::string&) { return HTTPReq_JSONRPC(context, req); };
|
||||||
RegisterHTTPHandler("/", true, handle_rpc);
|
auto handle_rpc_external = [&context](HTTPRequest* req, const std::string&) { return HTTPReq_JSONRPC(context, req, true); };
|
||||||
|
RegisterHTTPHandler("/", true, false, handle_rpc);
|
||||||
if (g_wallet_init_interface.HasWalletSupport()) {
|
if (g_wallet_init_interface.HasWalletSupport()) {
|
||||||
RegisterHTTPHandler("/wallet/", false, handle_rpc);
|
RegisterHTTPHandler("/wallet/", false, false, handle_rpc);
|
||||||
}
|
}
|
||||||
|
RegisterHTTPHandler("/external", true, true, handle_rpc_external);
|
||||||
struct event_base* eventBase = EventBase();
|
struct event_base* eventBase = EventBase();
|
||||||
assert(eventBase);
|
assert(eventBase);
|
||||||
httpRPCTimerInterface = std::make_unique<HTTPRPCTimerInterface>(eventBase);
|
httpRPCTimerInterface = std::make_unique<HTTPRPCTimerInterface>(eventBase);
|
||||||
@ -317,6 +327,7 @@ void InterruptHTTPRPC()
|
|||||||
void StopHTTPRPC()
|
void StopHTTPRPC()
|
||||||
{
|
{
|
||||||
LogPrint(BCLog::RPC, "Stopping HTTP RPC server\n");
|
LogPrint(BCLog::RPC, "Stopping HTTP RPC server\n");
|
||||||
|
UnregisterHTTPHandler("/external", true);
|
||||||
UnregisterHTTPHandler("/", true);
|
UnregisterHTTPHandler("/", true);
|
||||||
if (g_wallet_init_interface.HasWalletSupport()) {
|
if (g_wallet_init_interface.HasWalletSupport()) {
|
||||||
UnregisterHTTPHandler("/wallet/", false);
|
UnregisterHTTPHandler("/wallet/", false);
|
||||||
|
@ -71,10 +71,12 @@ private:
|
|||||||
std::deque<std::unique_ptr<WorkItem>> queue GUARDED_BY(cs);
|
std::deque<std::unique_ptr<WorkItem>> queue GUARDED_BY(cs);
|
||||||
bool running GUARDED_BY(cs);
|
bool running GUARDED_BY(cs);
|
||||||
const size_t maxDepth;
|
const size_t maxDepth;
|
||||||
|
const bool m_is_external;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit WorkQueue(size_t _maxDepth) : running(true),
|
explicit WorkQueue(size_t _maxDepth, bool is_external) : running(true),
|
||||||
maxDepth(_maxDepth)
|
maxDepth(_maxDepth),
|
||||||
|
m_is_external(is_external)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
/** Precondition: worker threads have all stopped (they have been joined).
|
/** Precondition: worker threads have all stopped (they have been joined).
|
||||||
@ -107,6 +109,9 @@ public:
|
|||||||
i = std::move(queue.front());
|
i = std::move(queue.front());
|
||||||
queue.pop_front();
|
queue.pop_front();
|
||||||
}
|
}
|
||||||
|
if (m_is_external) {
|
||||||
|
LogPrintf("HTTP: Calling handler for external user...\n");
|
||||||
|
}
|
||||||
(*i)();
|
(*i)();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,12 +126,13 @@ public:
|
|||||||
|
|
||||||
struct HTTPPathHandler
|
struct HTTPPathHandler
|
||||||
{
|
{
|
||||||
HTTPPathHandler(std::string _prefix, bool _exactMatch, HTTPRequestHandler _handler):
|
HTTPPathHandler(std::string _prefix, bool _exactMatch, bool external, HTTPRequestHandler _handler):
|
||||||
prefix(_prefix), exactMatch(_exactMatch), handler(_handler)
|
prefix(_prefix), exactMatch(_exactMatch), m_external(external), handler(_handler)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
std::string prefix;
|
std::string prefix;
|
||||||
bool exactMatch;
|
bool exactMatch;
|
||||||
|
bool m_external;
|
||||||
HTTPRequestHandler handler;
|
HTTPRequestHandler handler;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -140,6 +146,7 @@ static struct evhttp* eventHTTP = nullptr;
|
|||||||
static std::vector<CSubNet> rpc_allow_subnets;
|
static std::vector<CSubNet> rpc_allow_subnets;
|
||||||
//! Work queue for handling longer requests off the event loop thread
|
//! Work queue for handling longer requests off the event loop thread
|
||||||
static std::unique_ptr<WorkQueue<HTTPClosure>> g_work_queue{nullptr};
|
static std::unique_ptr<WorkQueue<HTTPClosure>> g_work_queue{nullptr};
|
||||||
|
static std::unique_ptr<WorkQueue<HTTPClosure>> g_work_queue_external{nullptr};
|
||||||
//! Handlers for (sub)paths
|
//! Handlers for (sub)paths
|
||||||
static std::vector<HTTPPathHandler> pathHandlers;
|
static std::vector<HTTPPathHandler> pathHandlers;
|
||||||
//! Bound listening sockets
|
//! Bound listening sockets
|
||||||
@ -258,9 +265,18 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
|
|||||||
|
|
||||||
// Dispatch to worker thread
|
// Dispatch to worker thread
|
||||||
if (i != iend) {
|
if (i != iend) {
|
||||||
auto item{std::make_unique<HTTPWorkItem>(std::move(hreq), path, i->handler)};
|
auto item{std::make_unique<HTTPWorkItem>(std::move(hreq), path, i->handler)}; /// this handler!
|
||||||
assert(g_work_queue);
|
assert(g_work_queue);
|
||||||
if (g_work_queue->Enqueue(item.get())) {
|
|
||||||
|
// We have queue created only if RPC arg 'rpcexternaluser' is specified
|
||||||
|
if (i->m_external && g_work_queue_external) {
|
||||||
|
if (g_work_queue_external->Enqueue(item.get())) {
|
||||||
|
item.release();
|
||||||
|
} else {
|
||||||
|
LogPrintf("WARNING: request rejected because http work queue depth of externals exceeded, it can be increased with the -rpcexternalworkqueue= setting\n");
|
||||||
|
item->req->WriteReply(HTTP_SERVICE_UNAVAILABLE, "Work queue depth of externals exceeded");
|
||||||
|
}
|
||||||
|
} else if (g_work_queue->Enqueue(item.get())) {
|
||||||
item.release(); /* if true, queue took ownership */
|
item.release(); /* if true, queue took ownership */
|
||||||
} else {
|
} else {
|
||||||
LogPrintf("WARNING: request rejected because http work queue depth exceeded, it can be increased with the -rpcworkqueue= setting\n");
|
LogPrintf("WARNING: request rejected because http work queue depth exceeded, it can be increased with the -rpcworkqueue= setting\n");
|
||||||
@ -393,9 +409,14 @@ bool InitHTTPServer()
|
|||||||
|
|
||||||
LogPrint(BCLog::HTTP, "Initialized HTTP server\n");
|
LogPrint(BCLog::HTTP, "Initialized HTTP server\n");
|
||||||
int workQueueDepth = std::max((long)gArgs.GetArg("-rpcworkqueue", DEFAULT_HTTP_WORKQUEUE), 1L);
|
int workQueueDepth = std::max((long)gArgs.GetArg("-rpcworkqueue", DEFAULT_HTTP_WORKQUEUE), 1L);
|
||||||
|
int workQueueDepthExternal = std::max((long)gArgs.GetArg("-rpcexternalworkqueue", DEFAULT_HTTP_WORKQUEUE), 1L);
|
||||||
LogPrintf("HTTP: creating work queue of depth %d\n", workQueueDepth);
|
LogPrintf("HTTP: creating work queue of depth %d\n", workQueueDepth);
|
||||||
|
|
||||||
g_work_queue = std::make_unique<WorkQueue<HTTPClosure>>(workQueueDepth);
|
g_work_queue = std::make_unique<WorkQueue<HTTPClosure>>(workQueueDepth, false);
|
||||||
|
if (!gArgs.GetArg("-rpcexternaluser", "").empty()) {
|
||||||
|
LogPrintf("HTTP: creating external work queue of depth %d\n", workQueueDepthExternal);
|
||||||
|
g_work_queue_external = std::make_unique<WorkQueue<HTTPClosure>>(workQueueDepthExternal, true);
|
||||||
|
}
|
||||||
// transfer ownership to eventBase/HTTP via .release()
|
// transfer ownership to eventBase/HTTP via .release()
|
||||||
eventBase = base_ctr.release();
|
eventBase = base_ctr.release();
|
||||||
eventHTTP = http_ctr.release();
|
eventHTTP = http_ctr.release();
|
||||||
@ -423,12 +444,18 @@ void StartHTTPServer()
|
|||||||
{
|
{
|
||||||
LogPrint(BCLog::HTTP, "Starting HTTP server\n");
|
LogPrint(BCLog::HTTP, "Starting HTTP server\n");
|
||||||
int rpcThreads = std::max((long)gArgs.GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L);
|
int rpcThreads = std::max((long)gArgs.GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L);
|
||||||
|
int rpcThreadsExternals = std::max((long)gArgs.GetArg("-rpcexternalthreads", DEFAULT_HTTP_THREADS), 1L);
|
||||||
LogPrintf("HTTP: starting %d worker threads\n", rpcThreads);
|
LogPrintf("HTTP: starting %d worker threads\n", rpcThreads);
|
||||||
g_thread_http = std::thread(ThreadHTTP, eventBase);
|
g_thread_http = std::thread(ThreadHTTP, eventBase);
|
||||||
|
|
||||||
for (int i = 0; i < rpcThreads; i++) {
|
for (int i = 0; i < rpcThreads; i++) {
|
||||||
g_thread_http_workers.emplace_back(HTTPWorkQueueRun, g_work_queue.get(), i);
|
g_thread_http_workers.emplace_back(HTTPWorkQueueRun, g_work_queue.get(), i);
|
||||||
}
|
}
|
||||||
|
if (g_work_queue_external) {
|
||||||
|
for (int i = 0; i < rpcThreadsExternals; i++) {
|
||||||
|
g_thread_http_workers.emplace_back(HTTPWorkQueueRun, g_work_queue_external.get(), i);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterruptHTTPServer()
|
void InterruptHTTPServer()
|
||||||
@ -438,6 +465,9 @@ void InterruptHTTPServer()
|
|||||||
// Reject requests on current connections
|
// Reject requests on current connections
|
||||||
evhttp_set_gencb(eventHTTP, http_reject_request_cb, nullptr);
|
evhttp_set_gencb(eventHTTP, http_reject_request_cb, nullptr);
|
||||||
}
|
}
|
||||||
|
if (g_work_queue_external) {
|
||||||
|
g_work_queue_external->Interrupt();
|
||||||
|
}
|
||||||
if (g_work_queue) {
|
if (g_work_queue) {
|
||||||
g_work_queue->Interrupt();
|
g_work_queue->Interrupt();
|
||||||
}
|
}
|
||||||
@ -446,6 +476,9 @@ void InterruptHTTPServer()
|
|||||||
void StopHTTPServer()
|
void StopHTTPServer()
|
||||||
{
|
{
|
||||||
LogPrint(BCLog::HTTP, "Stopping HTTP server\n");
|
LogPrint(BCLog::HTTP, "Stopping HTTP server\n");
|
||||||
|
if (g_work_queue_external) {
|
||||||
|
g_work_queue_external->Interrupt();
|
||||||
|
}
|
||||||
if (g_work_queue) {
|
if (g_work_queue) {
|
||||||
LogPrint(BCLog::HTTP, "Waiting for HTTP worker threads to exit\n");
|
LogPrint(BCLog::HTTP, "Waiting for HTTP worker threads to exit\n");
|
||||||
for (auto& thread : g_thread_http_workers) {
|
for (auto& thread : g_thread_http_workers) {
|
||||||
@ -471,6 +504,7 @@ void StopHTTPServer()
|
|||||||
event_base_free(eventBase);
|
event_base_free(eventBase);
|
||||||
eventBase = nullptr;
|
eventBase = nullptr;
|
||||||
}
|
}
|
||||||
|
g_work_queue_external.reset();
|
||||||
g_work_queue.reset();
|
g_work_queue.reset();
|
||||||
LogPrint(BCLog::HTTP, "Stopped HTTP server\n");
|
LogPrint(BCLog::HTTP, "Stopped HTTP server\n");
|
||||||
}
|
}
|
||||||
@ -639,10 +673,10 @@ HTTPRequest::RequestMethod HTTPRequest::GetRequestMethod() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
|
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, bool external, const HTTPRequestHandler &handler)
|
||||||
{
|
{
|
||||||
LogPrint(BCLog::HTTP, "Registering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch);
|
LogPrint(BCLog::HTTP, "Registering HTTP handler for %s (exactmatch %d external %d)\n", prefix, exactMatch, external);
|
||||||
pathHandlers.push_back(HTTPPathHandler(prefix, exactMatch, handler));
|
pathHandlers.push_back(HTTPPathHandler(prefix, exactMatch, external, handler));
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
|
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
|
||||||
|
@ -41,7 +41,7 @@ typedef std::function<bool(HTTPRequest* req, const std::string &)> HTTPRequestHa
|
|||||||
* If multiple handlers match a prefix, the first-registered one will
|
* If multiple handlers match a prefix, the first-registered one will
|
||||||
* be invoked.
|
* be invoked.
|
||||||
*/
|
*/
|
||||||
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler);
|
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, bool external, const HTTPRequestHandler &handler);
|
||||||
/** Unregister handler for prefix */
|
/** Unregister handler for prefix */
|
||||||
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch);
|
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch);
|
||||||
|
|
||||||
|
@ -768,10 +768,13 @@ void SetupServerArgs(NodeContext& node)
|
|||||||
argsman.AddArg("-rpcport=<port>", strprintf("Listen for JSON-RPC connections on <port> (default: %u, testnet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
|
argsman.AddArg("-rpcport=<port>", strprintf("Listen for JSON-RPC connections on <port> (default: %u, testnet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpcservertimeout=<n>", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_SERVER_TIMEOUT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
|
argsman.AddArg("-rpcservertimeout=<n>", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_SERVER_TIMEOUT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpcthreads=<n>", strprintf("Set the number of threads to service RPC calls (default: %d)", DEFAULT_HTTP_THREADS), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
argsman.AddArg("-rpcthreads=<n>", strprintf("Set the number of threads to service RPC calls (default: %d)", DEFAULT_HTTP_THREADS), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
||||||
|
argsman.AddArg("-rpcexternalthreads=<n>", strprintf("Set the number of threads to service RPC calls from external consumers (default: %d)", DEFAULT_HTTP_THREADS), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpcuser=<user>", "Username for JSON-RPC connections", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
|
argsman.AddArg("-rpcuser=<user>", "Username for JSON-RPC connections", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
|
||||||
|
argsman.AddArg("-rpcexternaluser=<user>", "Username for JSON-RPC external connections", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpcwhitelist=<whitelist>", "Set a whitelist to filter incoming RPC calls for a specific user. The field <whitelist> comes in the format: <USERNAME>:<rpc 1>,<rpc 2>,...,<rpc n>. If multiple whitelists are set for a given user, they are set-intersected. See -rpcwhitelistdefault documentation for information on default whitelist behavior.", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
argsman.AddArg("-rpcwhitelist=<whitelist>", "Set a whitelist to filter incoming RPC calls for a specific user. The field <whitelist> comes in the format: <USERNAME>:<rpc 1>,<rpc 2>,...,<rpc n>. If multiple whitelists are set for a given user, they are set-intersected. See -rpcwhitelistdefault documentation for information on default whitelist behavior.", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpcwhitelistdefault", "Sets default behavior for rpc whitelisting. Unless rpcwhitelistdefault is set to 0, if any -rpcwhitelist is set, the rpc server acts as if all rpc users are subject to empty-unless-otherwise-specified whitelists. If rpcwhitelistdefault is set to 1 and no -rpcwhitelist is set, rpc server acts as if all rpc users are subject to empty whitelists.", ArgsManager::ALLOW_BOOL, OptionsCategory::RPC);
|
argsman.AddArg("-rpcwhitelistdefault", "Sets default behavior for rpc whitelisting. Unless rpcwhitelistdefault is set to 0, if any -rpcwhitelist is set, the rpc server acts as if all rpc users are subject to empty-unless-otherwise-specified whitelists. If rpcwhitelistdefault is set to 1 and no -rpcwhitelist is set, rpc server acts as if all rpc users are subject to empty whitelists.", ArgsManager::ALLOW_BOOL, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpcworkqueue=<n>", strprintf("Set the depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
|
argsman.AddArg("-rpcworkqueue=<n>", strprintf("Set the depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
|
||||||
|
argsman.AddArg("-rpcexternalworkqueue=<n>", strprintf("Set the depth of the work queue to service external RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-server", "Accept command line and JSON-RPC commands", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
argsman.AddArg("-server", "Accept command line and JSON-RPC commands", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
||||||
|
|
||||||
argsman.AddArg("-statsenabled", strprintf("Publish internal stats to statsd (default: %u)", DEFAULT_STATSD_ENABLE), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD);
|
argsman.AddArg("-statsenabled", strprintf("Publish internal stats to statsd (default: %u)", DEFAULT_STATSD_ENABLE), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD);
|
||||||
|
@ -723,7 +723,7 @@ void StartREST(const CoreContext& context)
|
|||||||
{
|
{
|
||||||
for (const auto& up : uri_prefixes) {
|
for (const auto& up : uri_prefixes) {
|
||||||
auto handler = [&context, up](HTTPRequest* req, const std::string& prefix) { return up.handler(context, req, prefix); };
|
auto handler = [&context, up](HTTPRequest* req, const std::string& prefix) { return up.handler(context, req, prefix); };
|
||||||
RegisterHTTPHandler(up.prefix, false, handler);
|
RegisterHTTPHandler(up.prefix, false, false, handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,18 +42,24 @@ class HTTPBasicsTest(BitcoinTestFramework):
|
|||||||
def run_test(self):
|
def run_test(self):
|
||||||
url = urllib.parse.urlparse(self.nodes[0].url)
|
url = urllib.parse.urlparse(self.nodes[0].url)
|
||||||
|
|
||||||
def test_command(method, params, auth, expexted_status, should_not_match=False):
|
def test_command(method, params, auth, expected_status, should_not_match=False):
|
||||||
|
test_command_helper(method, params, '/', auth, expected_status, should_not_match)
|
||||||
|
|
||||||
|
def test_external_command(method, params, auth, expected_status, should_not_match=False):
|
||||||
|
test_command_helper(method, params, '/external', auth, expected_status, should_not_match)
|
||||||
|
|
||||||
|
def test_command_helper(method, params, path, auth, expected_status, should_not_match):
|
||||||
conn = http.client.HTTPConnection(url.hostname, url.port)
|
conn = http.client.HTTPConnection(url.hostname, url.port)
|
||||||
conn.connect()
|
conn.connect()
|
||||||
body = {"method": method}
|
body = {"method": method}
|
||||||
if len(params):
|
if len(params):
|
||||||
body["params"] = params
|
body["params"] = params
|
||||||
conn.request('POST', '/', json.dumps(body), {"Authorization": "Basic " + str_to_b64str(auth)})
|
conn.request('POST', path, json.dumps(body), {"Authorization": "Basic " + str_to_b64str(auth)})
|
||||||
resp = conn.getresponse()
|
resp = conn.getresponse()
|
||||||
if should_not_match:
|
if should_not_match:
|
||||||
assert resp.status != expexted_status
|
assert resp.status != expected_status
|
||||||
else:
|
else:
|
||||||
assert_equal(resp.status, expexted_status)
|
assert_equal(resp.status, expected_status)
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
whitelisted = ["getassetunlockstatuses",
|
whitelisted = ["getassetunlockstatuses",
|
||||||
@ -114,5 +120,17 @@ class HTTPBasicsTest(BitcoinTestFramework):
|
|||||||
test_command("debug", ["1"], rpcuser_authpair_operator, 200)
|
test_command("debug", ["1"], rpcuser_authpair_operator, 200)
|
||||||
|
|
||||||
|
|
||||||
|
self.log.info("Restart node with /external handler...")
|
||||||
|
test_external_command("getbestblockhash", [], rpcuser_authpair_platform, 200)
|
||||||
|
test_external_command("getblockchaininfo", [], rpcuser_authpair_platform, 403)
|
||||||
|
|
||||||
|
self.restart_node(0, extra_args=["-rpcexternaluser=platform-user"])
|
||||||
|
test_command("getbestblockhash", [], rpcuser_authpair_platform, 403)
|
||||||
|
test_external_command("getbestblockhash", [], rpcuser_authpair_platform, 200)
|
||||||
|
test_external_command("getblockchaininfo", [], rpcuser_authpair_platform, 403)
|
||||||
|
test_external_command("getbestblockhash", [], rpcuser_authpair_operator, 200)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
HTTPBasicsTest().main()
|
HTTPBasicsTest().main()
|
||||||
|
Loading…
Reference in New Issue
Block a user