Merge pull request #4412 from PastaPastaPasta/backport-trivial-pr15

Backport trivial pr15
This commit is contained in:
UdjinM6 2021-09-11 23:52:10 +03:00 committed by GitHub
commit c829f1a889
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 214 additions and 62 deletions

View File

@ -21,5 +21,5 @@ test/lint/lint-all.sh
if [ "$TRAVIS_REPO_SLUG" = "bitcoin/bitcoin" -a "$TRAVIS_EVENT_TYPE" = "cron" ]; then
git log --merges --before="2 days ago" -1 --format='%H' > ./contrib/verify-commits/trusted-sha512-root-commit
while read -r LINE; do travis_retry gpg --keyserver hkp://subset.pool.sks-keyservers.net --recv-keys $LINE; done < contrib/verify-commits/trusted-keys &&
travis_wait 50 contrib/verify-commits/verify-commits.py --clean-merge=2;
./contrib/verify-commits/verify-commits.py --clean-merge=2;
fi

View File

@ -25,6 +25,7 @@ BITCOIND_BIN=$(top_builddir)/src/$(BITCOIN_DAEMON_NAME)$(EXEEXT)
BITCOIN_QT_BIN=$(top_builddir)/src/qt/$(BITCOIN_GUI_NAME)$(EXEEXT)
BITCOIN_CLI_BIN=$(top_builddir)/src/$(BITCOIN_CLI_NAME)$(EXEEXT)
BITCOIN_TX_BIN=$(top_builddir)/src/$(BITCOIN_TX_NAME)$(EXEEXT)
BITCOIN_WALLET_BIN=$(top_builddir)/src/$(BITCOIN_WALLET_TOOL_NAME)$(EXEEXT)
BITCOIN_WIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EXEEXT)
empty :=
@ -81,6 +82,7 @@ $(BITCOIN_WIN_INSTALLER): all-recursive
STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_QT_BIN) $(top_builddir)/release
STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_CLI_BIN) $(top_builddir)/release
STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_TX_BIN) $(top_builddir)/release
STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_WALLET_BIN) $(top_builddir)/release
@test -f $(MAKENSIS) && $(MAKENSIS) -V2 $(top_builddir)/share/setup.nsi || \
echo error: could not build $@
@echo built $@
@ -177,6 +179,9 @@ $(BITCOIN_CLI_BIN): FORCE
$(BITCOIN_TX_BIN): FORCE
$(MAKE) -C src $(@F)
$(BITCOIN_WALLET_BIN): FORCE
$(MAKE) -C src $(@F)
if USE_LCOV
LCOV_FILTER_PATTERN=-p "/usr/include/" -p "/usr/lib/" -p "src/leveldb/" -p "src/crc32c/" -p "src/bench/" -p "src/univalue" -p "src/crypto/ctaes" -p "src/secp256k1"

View File

@ -47,13 +47,12 @@ def git_config_get(option, default=None):
except subprocess.CalledProcessError:
return default
def retrieve_pr_info(repo,pull,ghtoken):
def retrieve_json(req, ghtoken):
'''
Retrieve pull request information from github.
Return None if no title can be found, or an error happens.
Retrieve json from github.
Return None if an error happens.
'''
try:
req = Request("https://api.github.com/repos/"+repo+"/pulls/"+pull)
if ghtoken is not None:
req.add_header('Authorization', 'token ' + ghtoken)
result = urlopen(req)
@ -69,6 +68,18 @@ def retrieve_pr_info(repo,pull,ghtoken):
print('Warning: unable to retrieve pull information from github: %s' % e)
return None
def retrieve_pr_info(repo,pull,ghtoken):
req = Request("https://api.github.com/repos/"+repo+"/pulls/"+pull)
return retrieve_json(req,ghtoken)
def retrieve_pr_comments(repo,pull,ghtoken):
req = Request("https://api.github.com/repos/"+repo+"/issues/"+pull+"/comments")
return retrieve_json(req,ghtoken)
def retrieve_pr_reviews(repo,pull,ghtoken):
req = Request("https://api.github.com/repos/"+repo+"/pulls/"+pull+"/reviews")
return retrieve_json(req,ghtoken)
def ask_prompt(text):
print(text,end=" ",file=stderr)
stderr.flush()
@ -133,6 +144,16 @@ def tree_sha512sum(commit='HEAD'):
raise IOError('Non-zero return value executing git cat-file')
return overall.hexdigest()
def get_acks_from_comments(head_commit, comments):
assert len(head_commit) == 6
ack_str ='\n\nACKs for commit {}:\n'.format(head_commit)
for c in comments:
review = [l for l in c['body'].split('\r\n') if 'ACK' in l and head_commit in l]
if review:
ack_str += ' {}:\n'.format(c['user']['login'])
ack_str += ' {}\n'.format(review[0])
return ack_str
def print_merge_details(pull, title, branch, base_branch, head_branch):
print('%s#%s%s %s %sinto %s%s' % (ATTR_RESET+ATTR_PR,pull,ATTR_RESET,title,ATTR_RESET+ATTR_PR,branch,ATTR_RESET))
subprocess.check_call([GIT,'log','--graph','--topo-order','--pretty=format:'+COMMIT_FORMAT,base_branch+'..'+head_branch])
@ -185,6 +206,9 @@ def main():
info = retrieve_pr_info(repo,pull,ghtoken)
if info is None:
sys.exit(1)
comments = retrieve_pr_comments(repo,pull,ghtoken) + retrieve_pr_reviews(repo,pull,ghtoken)
if comments is None:
sys.exit(1)
title = info['title'].strip()
body = info['body'].strip()
# precedence order for destination branch argument:
@ -238,6 +262,7 @@ def main():
message = firstline + '\n\n'
message += subprocess.check_output([GIT,'log','--no-merges','--topo-order','--pretty=format:%H %s (%an)',base_branch+'..'+head_branch]).decode('utf-8')
message += '\n\nPull request description:\n\n ' + body.replace('\n', '\n ') + '\n'
message += get_acks_from_comments(head_commit=subprocess.check_output([GIT,'log','-1','--pretty=format:%H',head_branch]).decode('utf-8')[:6], comments=comments)
try:
subprocess.check_call([GIT,'merge','-q','--commit','--no-edit','--no-ff','--no-gpg-sign','-m',message.encode('utf-8'),head_branch])
except subprocess.CalledProcessError:

View File

@ -5,6 +5,7 @@
"""Verify commits against a trusted keys list."""
import argparse
import hashlib
import logging
import os
import subprocess
import sys
@ -66,6 +67,11 @@ def tree_sha512sum(commit='HEAD'):
return overall.hexdigest()
def main():
# Enable debug logging if running in CI
if 'CI' in os.environ and os.environ['CI'].lower() == "true":
logging.getLogger().setLevel(logging.DEBUG)
# Parse arguments
parser = argparse.ArgumentParser(usage='%(prog)s [options] [commit id]')
parser.add_argument('--disable-tree-check', action='store_false', dest='verify_tree', help='disable SHA-512 tree check')
@ -95,6 +101,10 @@ def main():
# Iterate through commits
while True:
# Log a message to prevent Travis from timing out
logging.debug("verify-commits: [in-progress] processing commit {}".format(current_commit[:8]))
if current_commit == verified_root:
print('There is a valid path from "{}" to {} where all commits are signed!'.format(initial_commit, verified_root))
sys.exit(0)

View File

@ -5,6 +5,97 @@ The headless daemon `dashd` has the JSON-RPC API enabled by default, the GUI
option. In the GUI it is possible to execute RPC methods in the Debug Console
Dialog.
## Versioning
The RPC interface might change from one major version of Dash Core to the
next. This makes the RPC interface implicitly versioned on the major version.
The version tuple can be retrieved by e.g. the `getnetworkinfo` RPC in
`version`.
Usually deprecated features can be re-enabled during the grace-period of one
major version via the `-deprecatedrpc=` command line option. The release notes
of a new major release come with detailed instructions on what RPC features
were deprecated and how to re-enable them temporarily.
## Security
The RPC interface allows other programs to control Dash Core,
including the ability to spend funds from your wallets, affect consensus
verification, read private data, and otherwise perform operations that
can cause loss of money, data, or privacy. This section suggests how
you should use and configure Dash Core to reduce the risk that its
RPC interface will be abused.
- **Securing the executable:** Anyone with physical or remote access to
the computer, container, or virtual machine running Dash Core can
compromise either the whole program or just the RPC interface. This
includes being able to record any passphrases you enter for unlocking
your encrypted wallets or changing settings so that your Dash Core
program tells you that certain transactions have multiple
confirmations even when they aren't part of the best block chain. For
this reason, you should not use Dash Core for security sensitive
operations on systems you do not exclusively control, such as shared
computers or virtual private servers.
- **Securing local network access:** By default, the RPC interface can
only be accessed by a client running on the same computer and only
after the client provides a valid authentication credential (username
and passphrase). Any program on your computer with access to the file
system and local network can obtain this level of access.
Additionally, other programs on your computer can attempt to provide
an RPC interface on the same port as used by Dash Core in order to
trick you into revealing your authentication credentials. For this
reason, it is important to only use Dash Core for
security-sensitive operations on a computer whose other programs you
trust.
- **Securing remote network access:** You may optionally allow other
computers to remotely control Dash Core by setting the `rpcallowip`
and `rpcbind` configuration parameters. These settings are only meant
for enabling connections over secure private networks or connections
that have been otherwise secured (e.g. using a VPN or port forwarding
with SSH or stunnel). **Do not enable RPC connections over the public
Internet.** Although Dash Core's RPC interface does use
authentication, it does not use encryption, so your login credentials
are sent as clear text that can be read by anyone on your network
path. Additionally, the RPC interface has not been hardened to
withstand arbitrary Internet traffic, so changing the above settings
to expose it to the Internet (even using something like a Tor hidden
service) could expose you to unconsidered vulnerabilities. See
`dashd -help` for more information about these settings and other
settings described in this document.
Related, if you use Dash Core inside a Docker container, you may
need to expose the RPC port to the host system. The default way to
do this in Docker also exposes the port to the public Internet.
Instead, expose it only on the host system's localhost, for example:
`-p 127.0.0.1:8332:8332`
- **Secure authentication:** By default, Dash Core generates unique
login credentials each time it restarts and puts them into a file
readable only by the user that started Dash Core, allowing any of
that user's RPC clients with read access to the file to login
automatically. The file is `.cookie` in the Dash Core
configuration directory, and using these credentials is the preferred
RPC authentication method. If you need to generate static login
credentials for your programs, you can use the script in the
`share/rpcauth` directory in the Dash Core source tree. As a final
fallback, you can directly use manually-chosen `rpcuser` and
`rpcpassword` configuration parameters---but you must ensure that you
choose a strong and unique passphrase (and still don't use insecure
networks, as mentioned above).
- **Secure string handling:** The RPC interface does not guarantee any
escaping of data beyond what's necessary to encode it as JSON,
although it does usually provide serialized data using a hex
representation of the bytes. If you use RPC data in your programs or
provide its data to other programs, you must ensure any problem
strings are properly escaped. For example, multiple websites have
been manipulated because they displayed decoded hex strings that
included HTML `<script>` tags. For this reason, and other
non-security reasons, it is recommended to display all serialized data
in hex form only.
## RPC consistency guarantees
State that can be queried via RPCs is guaranteed to be at least up-to-date with

View File

@ -80,6 +80,7 @@ Section -Main SEC0000
File @abs_top_srcdir@/release/@BITCOIN_DAEMON_NAME@@EXEEXT@
File @abs_top_srcdir@/release/@BITCOIN_CLI_NAME@@EXEEXT@
File @abs_top_srcdir@/release/@BITCOIN_TX_NAME@@EXEEXT@
File @abs_top_srcdir@/release/@BITCOIN_WALLET_TOOL_NAME@@EXEEXT@
SetOutPath $INSTDIR\doc
File /r /x Makefile* @abs_top_srcdir@/doc\*.*
SetOutPath $INSTDIR

View File

@ -180,6 +180,7 @@ static std::string openmodeToStr(std::ios_base::openmode mode)
void ifstream::open(const fs::path& p, std::ios_base::openmode mode)
{
close();
mode |= std::ios_base::in;
m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str());
if (m_file == nullptr) {
return;
@ -203,6 +204,7 @@ void ifstream::close()
void ofstream::open(const fs::path& p, std::ios_base::openmode mode)
{
close();
mode |= std::ios_base::out;
m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str());
if (m_file == nullptr) {
return;

View File

@ -211,7 +211,7 @@ Q_SIGNALS:
void requestedRestart(QStringList args);
void requestedShutdown();
void stopThread();
void splashFinished(QWidget *window);
void splashFinished();
private:
QThread *coreThread;
@ -358,9 +358,9 @@ void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle)
{
SplashScreen *splash = new SplashScreen(m_node, nullptr, networkStyle);
// We don't hold a direct pointer to the splash screen after creation, but the splash
// screen will take care of deleting itself when slotFinish happens.
// screen will take care of deleting itself when finish() happens.
splash->show();
connect(this, &BitcoinApplication::splashFinished, splash, &SplashScreen::slotFinish);
connect(this, &BitcoinApplication::splashFinished, splash, &SplashScreen::finish);
connect(this, &BitcoinApplication::requestedShutdown, splash, &QWidget::close);
}
@ -501,7 +501,7 @@ void BitcoinApplication::initializeResult(bool success)
} else {
window->showMinimized();
}
Q_EMIT splashFinished(window);
Q_EMIT splashFinished();
// Let the users setup their preferred appearance if there are no settings for it defined yet.
GUIUtil::setupAppearance(window, clientModel->getOptionsModel());
@ -518,7 +518,7 @@ void BitcoinApplication::initializeResult(bool success)
#endif
pollShutdownTimer->start(200);
} else {
Q_EMIT splashFinished(window); // Make sure splash screen doesn't stick around during shutdown
Q_EMIT splashFinished(); // Make sure splash screen doesn't stick around during shutdown
quit(); // Exit first main loop invocation
}
}

View File

@ -149,10 +149,8 @@ bool SplashScreen::eventFilter(QObject * obj, QEvent * ev) {
return QObject::eventFilter(obj, ev);
}
void SplashScreen::slotFinish(QWidget *mainWin)
void SplashScreen::finish()
{
Q_UNUSED(mainWin);
/* If the window is minimized, hide() will be ignored. */
/* Make sure we de-minimize the splashscreen window before hiding */
if (isMinimized())

View File

@ -5,8 +5,7 @@
#ifndef BITCOIN_QT_SPLASHSCREEN_H
#define BITCOIN_QT_SPLASHSCREEN_H
#include <functional>
#include <QSplashScreen>
#include <QWidget>
#include <memory>
@ -37,8 +36,8 @@ protected:
void closeEvent(QCloseEvent *event) override;
public Q_SLOTS:
/** Slot to call finish() method as it's not defined as slot */
void slotFinish(QWidget *mainWin);
/** Hide the splash screen window and schedule the splash screen object for deletion */
void finish();
/** Show message and progress */
void showMessage(const QString &message, int alignment, const QColor &color);

View File

@ -49,15 +49,11 @@ void WalletFrame::setClientModel(ClientModel *_clientModel)
}
}
bool WalletFrame::addWallet(WalletModel *walletModel)
void WalletFrame::addWallet(WalletModel *walletModel)
{
if (!gui || !clientModel || !walletModel) {
return false;
}
if (!gui || !clientModel || !walletModel) return;
if (mapWalletViews.count(walletModel) > 0) {
return false;
}
if (mapWalletViews.count(walletModel) > 0) return;
WalletView* walletView = new WalletView(this);
walletView->setBitcoinGUI(gui);
@ -81,31 +77,25 @@ bool WalletFrame::addWallet(WalletModel *walletModel)
});
connect(walletView, &WalletView::outOfSyncWarningClicked, this, &WalletFrame::outOfSyncWarningClicked);
return true;
}
bool WalletFrame::setCurrentWallet(WalletModel* wallet_model)
void WalletFrame::setCurrentWallet(WalletModel* wallet_model)
{
if (mapWalletViews.count(wallet_model) == 0)
return false;
if (mapWalletViews.count(wallet_model) == 0) return;
WalletView *walletView = mapWalletViews.value(wallet_model);
walletStack->setCurrentWidget(walletView);
assert(walletView);
walletView->updateEncryptionStatus();
return true;
}
bool WalletFrame::removeWallet(WalletModel* wallet_model)
void WalletFrame::removeWallet(WalletModel* wallet_model)
{
if (mapWalletViews.count(wallet_model) == 0)
return false;
if (mapWalletViews.count(wallet_model) == 0) return;
WalletView *walletView = mapWalletViews.take(wallet_model);
walletStack->removeWidget(walletView);
delete walletView;
return true;
}
void WalletFrame::removeAllWallets()

View File

@ -36,9 +36,9 @@ public:
void setClientModel(ClientModel *clientModel);
bool addWallet(WalletModel *walletModel);
bool setCurrentWallet(WalletModel* wallet_model);
bool removeWallet(WalletModel* wallet_model);
void addWallet(WalletModel *walletModel);
void setCurrentWallet(WalletModel* wallet_model);
void removeWallet(WalletModel* wallet_model);
void removeAllWallets();
bool handlePaymentRequest(const SendCoinsRecipient& recipient);

View File

@ -935,7 +935,7 @@ static bool GetConfigOptions(std::istream& stream, std::string& error, std::vect
} else if ((pos = str.find('=')) != std::string::npos) {
std::string name = prefix + TrimString(str.substr(0, pos), pattern);
std::string value = TrimString(str.substr(pos + 1), pattern);
if (used_hash && name == "rpcpassword") {
if (used_hash && name.find("rpcpassword") != std::string::npos) {
error = strprintf("parse error on line %i, using # in rpcpassword can be ambiguous and should be avoided", linenr);
return false;
}

View File

@ -4462,19 +4462,6 @@ UniValue importmulti(const JSONRPCRequest& request);
UniValue dumphdinfo(const JSONRPCRequest& request);
UniValue importelectrumwallet(const JSONRPCRequest& request);
void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map<CPubKey, KeyOriginInfo>& hd_keypaths)
{
CPubKey vchPubKey;
if (!pwallet->GetPubKey(keyID, vchPubKey)) {
return;
}
KeyOriginInfo info;
if (!pwallet->GetKeyOrigin(keyID, info)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal keypath is broken");
}
hd_keypaths.emplace(vchPubKey, std::move(info));
}
UniValue walletprocesspsbt(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);

View File

@ -4,6 +4,7 @@
#include <wallet/walletutil.h>
#include <logging.h>
#include <util/system.h>
fs::path GetWalletDir()
@ -33,9 +34,11 @@ static bool IsBerkeleyBtree(const fs::path& path)
// A Berkeley DB Btree file has at least 4K.
// This check also prevents opening lock files.
boost::system::error_code ec;
if (fs::file_size(path, ec) < 4096) return false;
auto size = fs::file_size(path, ec);
if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), path.string());
if (size < 4096) return false;
fs::ifstream file(path.string(), std::ios::binary);
fsbridge::ifstream file(path, std::ios::binary);
if (!file.is_open()) return false;
file.seekg(12, std::ios::beg); // Magic bytes start at offset 12
@ -54,8 +57,14 @@ std::vector<fs::path> ListWalletDir()
const fs::path wallet_dir = GetWalletDir();
const size_t offset = wallet_dir.string().size() + 1;
std::vector<fs::path> paths;
boost::system::error_code ec;
for (auto it = fs::recursive_directory_iterator(wallet_dir, ec); it != fs::recursive_directory_iterator(); it.increment(ec)) {
if (ec) {
LogPrintf("%s: %s %s\n", __func__, ec.message(), it->path().string());
continue;
}
for (auto it = fs::recursive_directory_iterator(wallet_dir); it != fs::recursive_directory_iterator(); ++it) {
// Get wallet path relative to walletdir by removing walletdir from the wallet path.
// This can be replaced by boost::filesystem::lexically_relative once boost is bumped to 1.60.
const fs::path path = it->path().string().substr(offset);

View File

@ -43,6 +43,14 @@ class ConfArgsTest(BitcoinTestFramework):
conf.write('server=1\nrpcuser=someuser\nrpcpassword=some#pass')
self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 3, using # in rpcpassword can be ambiguous and should be avoided')
with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
conf.write('server=1\nrpcuser=someuser\nmain.rpcpassword=some#pass')
self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 3, using # in rpcpassword can be ambiguous and should be avoided')
with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
conf.write('server=1\nrpcuser=someuser\n[main]\nrpcpassword=some#pass')
self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 4, using # in rpcpassword can be ambiguous and should be avoided')
with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
conf.write('testnot.datadir=1\n[testnet]\n')
self.restart_node(0)

View File

@ -4,9 +4,19 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Tests some generic aspects of the RPC interface."""
from test_framework.authproxy import JSONRPCException
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
def expect_http_status(expected_http_status, expected_rpc_code,
fcn, *args):
try:
fcn(*args)
raise AssertionError("Expected RPC error %d, got none" % expected_rpc_code)
except JSONRPCException as exc:
assert_equal(exc.error["code"], expected_rpc_code)
assert_equal(exc.http_status, expected_http_status)
class RPCInterfaceTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
@ -38,8 +48,15 @@ class RPCInterfaceTest(BitcoinTestFramework):
assert_equal(result_by_id[3]['error'], None)
assert result_by_id[3]['result'] is not None
def test_http_status_codes(self):
self.log.info("Testing HTTP status codes for JSON-RPC requests...")
expect_http_status(404, -32601, self.nodes[0].invalidmethod)
expect_http_status(500, -8, self.nodes[0].getblockhash, 42)
def run_test(self):
self.test_batch_request()
self.test_http_status_codes()
if __name__ == '__main__':

View File

@ -35,6 +35,7 @@ ServiceProxy class:
import base64
import decimal
from http import HTTPStatus
import http.client
import json
import logging
@ -48,13 +49,14 @@ USER_AGENT = "AuthServiceProxy/0.1"
log = logging.getLogger("BitcoinRPC")
class JSONRPCException(Exception):
def __init__(self, rpc_error):
def __init__(self, rpc_error, http_status=None):
try:
errmsg = '%(message)s (%(code)i)' % rpc_error
except (KeyError, TypeError):
errmsg = ''
super().__init__(errmsg)
self.error = rpc_error
self.http_status = http_status
def EncodeDecimal(o):
@ -136,19 +138,26 @@ class AuthServiceProxy():
def __call__(self, *args, **argsn):
postdata = json.dumps(self.get_request(*args, **argsn), default=EncodeDecimal, ensure_ascii=self.ensure_ascii)
response = self._request('POST', self.__url.path, postdata.encode('utf-8'))
response, status = self._request('POST', self.__url.path, postdata.encode('utf-8'))
if response['error'] is not None:
raise JSONRPCException(response['error'])
raise JSONRPCException(response['error'], status)
elif 'result' not in response:
raise JSONRPCException({
'code': -343, 'message': 'missing JSON-RPC result'})
'code': -343, 'message': 'missing JSON-RPC result'}, status)
elif status != HTTPStatus.OK:
raise JSONRPCException({
'code': -342, 'message': 'non-200 HTTP status code but no JSON-RPC error'}, status)
else:
return response['result']
def batch(self, rpc_call_list):
postdata = json.dumps(list(rpc_call_list), default=EncodeDecimal, ensure_ascii=self.ensure_ascii)
log.debug("--> " + postdata)
return self._request('POST', self.__url.path, postdata.encode('utf-8'))
response, status = self._request('POST', self.__url.path, postdata.encode('utf-8'))
if status != HTTPStatus.OK:
raise JSONRPCException({
'code': -342, 'message': 'non-200 HTTP status code but no JSON-RPC error'}, status)
return response
def _get_response(self):
req_start_time = time.time()
@ -167,8 +176,9 @@ class AuthServiceProxy():
content_type = http_response.getheader('Content-Type')
if content_type != 'application/json':
raise JSONRPCException({
'code': -342, 'message': 'non-JSON HTTP response with \'%i %s\' from server' % (http_response.status, http_response.reason)})
raise JSONRPCException(
{'code': -342, 'message': 'non-JSON HTTP response with \'%i %s\' from server' % (http_response.status, http_response.reason)},
http_response.status)
responsedata = http_response.read().decode('utf8')
response = json.loads(responsedata, parse_float=decimal.Decimal)
@ -177,7 +187,7 @@ class AuthServiceProxy():
log.debug("<-%s- [%.6f] %s" % (response["id"], elapsed, json.dumps(response["result"], default=EncodeDecimal, ensure_ascii=self.ensure_ascii)))
else:
log.debug("<-- [%.6f] %s" % (elapsed, responsedata))
return response
return response, http_response.status
def __truediv__(self, relative_uri):
return AuthServiceProxy("{}/{}".format(self.__service_url, relative_uri), self._service_name, connection=self.__conn)