A standalone test case for the API thread #1900
54
src/api.py
54
src/api.py
|
@ -57,28 +57,25 @@ For further examples please reference `.tests.test_api`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import ConfigParser
|
|
||||||
import errno
|
import errno
|
||||||
import hashlib
|
import hashlib
|
||||||
import httplib
|
|
||||||
import json
|
import json
|
||||||
import random # nosec
|
import random # nosec
|
||||||
import socket
|
import socket
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
import xmlrpclib
|
|
||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer
|
|
||||||
from struct import pack
|
from struct import pack
|
||||||
|
|
||||||
|
from six.moves import configparser, http_client, queue, xmlrpc_server
|
||||||
|
|
||||||
import defaults
|
import defaults
|
||||||
import helper_inbox
|
import helper_inbox
|
||||||
import helper_sent
|
import helper_sent
|
||||||
import network.stats
|
|
||||||
import proofofwork
|
import proofofwork
|
||||||
import queues
|
import queues
|
||||||
import shared
|
import shared
|
||||||
import shutdown
|
|
||||||
import state
|
import state
|
||||||
from addresses import (
|
from addresses import (
|
||||||
addBMIfNotPresent,
|
addBMIfNotPresent,
|
||||||
|
@ -90,9 +87,21 @@ from addresses import (
|
||||||
from bmconfigparser import BMConfigParser
|
from bmconfigparser import BMConfigParser
|
||||||
from debug import logger
|
from debug import logger
|
||||||
from helper_sql import SqlBulkExecute, sqlExecute, sqlQuery, sqlStoredProcedure, sql_ready
|
from helper_sql import SqlBulkExecute, sqlExecute, sqlQuery, sqlStoredProcedure, sql_ready
|
||||||
from inventory import Inventory
|
|
||||||
|
# TODO: solve the issue with next two imports and remove the cutout
|
||||||
|
# FIXME: perhaps this module shouldn't use the Inventory at all
|
||||||
|
try:
|
||||||
|
import shutdown
|
||||||
|
from inventory import Inventory
|
||||||
|
except ImportError:
|
||||||
|
Inventory = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
import network.stats as network_stats
|
||||||
|
except ImportError:
|
||||||
|
network_stats = None
|
||||||
|
|
||||||
from network.threads import StoppableThread
|
from network.threads import StoppableThread
|
||||||
from six.moves import queue
|
|
||||||
from version import softwareVersion
|
from version import softwareVersion
|
||||||
|
|
||||||
try: # TODO: write tests for XML vulnerabilities
|
try: # TODO: write tests for XML vulnerabilities
|
||||||
|
@ -162,7 +171,7 @@ class ErrorCodes(type):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
class APIError(xmlrpclib.Fault):
|
class APIError(xmlrpc_server.Fault):
|
||||||
"""
|
"""
|
||||||
APIError exception class
|
APIError exception class
|
||||||
|
|
||||||
|
@ -210,7 +219,7 @@ class singleAPI(StoppableThread):
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
errno.WSAEADDRINUSE = errno.EADDRINUSE
|
errno.WSAEADDRINUSE = errno.EADDRINUSE
|
||||||
|
|
||||||
RPCServerBase = SimpleXMLRPCServer
|
RPCServerBase = xmlrpc_server.SimpleXMLRPCServer
|
||||||
ct = 'text/xml'
|
ct = 'text/xml'
|
||||||
if BMConfigParser().safeGet(
|
if BMConfigParser().safeGet(
|
||||||
'bitmessagesettings', 'apivariant') == 'json':
|
'bitmessagesettings', 'apivariant') == 'json':
|
||||||
|
@ -351,7 +360,7 @@ class command(object): # pylint: disable=too-few-public-methods
|
||||||
# Modified by Jonathan Warren (Atheros).
|
# Modified by Jonathan Warren (Atheros).
|
||||||
# Further modified by the Bitmessage developers
|
# Further modified by the Bitmessage developers
|
||||||
# http://code.activestate.com/recipes/501148
|
# http://code.activestate.com/recipes/501148
|
||||||
class BMXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
class BMXMLRPCRequestHandler(xmlrpc_server.SimpleXMLRPCRequestHandler):
|
||||||
"""The main API handler"""
|
"""The main API handler"""
|
||||||
|
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
|
@ -392,7 +401,7 @@ class BMXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
validuser = self.APIAuthenticateClient()
|
validuser = self.APIAuthenticateClient()
|
||||||
if not validuser:
|
if not validuser:
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
self.send_response(httplib.UNAUTHORIZED)
|
self.send_response(http_client.UNAUTHORIZED)
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
return
|
return
|
||||||
# "RPC Username or password incorrect or HTTP header"
|
# "RPC Username or password incorrect or HTTP header"
|
||||||
|
@ -409,11 +418,11 @@ class BMXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
)
|
)
|
||||||
except Exception: # This should only happen if the module is buggy
|
except Exception: # This should only happen if the module is buggy
|
||||||
# internal error, report as HTTP server error
|
# internal error, report as HTTP server error
|
||||||
self.send_response(httplib.INTERNAL_SERVER_ERROR)
|
self.send_response(http_client.INTERNAL_SERVER_ERROR)
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
else:
|
else:
|
||||||
# got a valid XML RPC response
|
# got a valid XML RPC response
|
||||||
self.send_response(httplib.OK)
|
self.send_response(http_client.OK)
|
||||||
self.send_header("Content-type", self.server.content_type)
|
self.send_header("Content-type", self.server.content_type)
|
||||||
self.send_header("Content-length", str(len(response)))
|
self.send_header("Content-length", str(len(response)))
|
||||||
|
|
||||||
|
@ -858,7 +867,7 @@ class BMRPCDispatcher(object):
|
||||||
' Use deleteAddress API call instead.')
|
' Use deleteAddress API call instead.')
|
||||||
try:
|
try:
|
||||||
self.config.remove_section(address)
|
self.config.remove_section(address)
|
||||||
except ConfigParser.NoSectionError:
|
except configparser.NoSectionError:
|
||||||
raise APIError(
|
raise APIError(
|
||||||
13, 'Could not find this address in your keys.dat file.')
|
13, 'Could not find this address in your keys.dat file.')
|
||||||
self.config.save()
|
self.config.save()
|
||||||
|
@ -875,7 +884,7 @@ class BMRPCDispatcher(object):
|
||||||
address = addBMIfNotPresent(address)
|
address = addBMIfNotPresent(address)
|
||||||
try:
|
try:
|
||||||
self.config.remove_section(address)
|
self.config.remove_section(address)
|
||||||
except ConfigParser.NoSectionError:
|
except configparser.NoSectionError:
|
||||||
raise APIError(
|
raise APIError(
|
||||||
13, 'Could not find this address in your keys.dat file.')
|
13, 'Could not find this address in your keys.dat file.')
|
||||||
self.config.save()
|
self.config.save()
|
||||||
|
@ -1266,6 +1275,8 @@ class BMRPCDispatcher(object):
|
||||||
requiredPayloadLengthExtraBytes):
|
requiredPayloadLengthExtraBytes):
|
||||||
"""Handle a request to disseminate an encrypted message"""
|
"""Handle a request to disseminate an encrypted message"""
|
||||||
|
|
||||||
|
if Inventory is None:
|
||||||
|
raise APIError(21, 'Could not import Inventory.')
|
||||||
# The device issuing this command to PyBitmessage supplies a msg
|
# The device issuing this command to PyBitmessage supplies a msg
|
||||||
# object that has already been encrypted but which still needs the POW
|
# object that has already been encrypted but which still needs the POW
|
||||||
# to be done. PyBitmessage accepts this msg object and sends it out
|
# to be done. PyBitmessage accepts this msg object and sends it out
|
||||||
|
@ -1322,6 +1333,8 @@ class BMRPCDispatcher(object):
|
||||||
def HandleDissimatePubKey(self, payload):
|
def HandleDissimatePubKey(self, payload):
|
||||||
"""Handle a request to disseminate a public key"""
|
"""Handle a request to disseminate a public key"""
|
||||||
|
|
||||||
|
if Inventory is None:
|
||||||
|
raise APIError(21, 'Could not import Inventory.')
|
||||||
# The device issuing this command to PyBitmessage supplies a pubkey
|
# The device issuing this command to PyBitmessage supplies a pubkey
|
||||||
# object to be disseminated to the rest of the Bitmessage network.
|
# object to be disseminated to the rest of the Bitmessage network.
|
||||||
# PyBitmessage accepts this pubkey object and sends it out to the rest
|
# PyBitmessage accepts this pubkey object and sends it out to the rest
|
||||||
|
@ -1411,7 +1424,10 @@ class BMRPCDispatcher(object):
|
||||||
or "connectedAndReceivingIncomingConnections".
|
or "connectedAndReceivingIncomingConnections".
|
||||||
"""
|
"""
|
||||||
|
|
||||||
connections_num = len(network.stats.connectedHostsList())
|
try:
|
||||||
|
connections_num = len(network_stats.connectedHostsList())
|
||||||
|
except AttributeError:
|
||||||
|
raise APIError(21, 'Could not import network_stats.')
|
||||||
if connections_num == 0:
|
if connections_num == 0:
|
||||||
networkStatus = 'notConnected'
|
networkStatus = 'notConnected'
|
||||||
elif state.clientHasReceivedIncomingConnections:
|
elif state.clientHasReceivedIncomingConnections:
|
||||||
|
@ -1423,7 +1439,7 @@ class BMRPCDispatcher(object):
|
||||||
'numberOfMessagesProcessed': state.numberOfMessagesProcessed,
|
'numberOfMessagesProcessed': state.numberOfMessagesProcessed,
|
||||||
'numberOfBroadcastsProcessed': state.numberOfBroadcastsProcessed,
|
'numberOfBroadcastsProcessed': state.numberOfBroadcastsProcessed,
|
||||||
'numberOfPubkeysProcessed': state.numberOfPubkeysProcessed,
|
'numberOfPubkeysProcessed': state.numberOfPubkeysProcessed,
|
||||||
'pendingDownload': network.stats.pendingDownload(),
|
'pendingDownload': network_stats.pendingDownload(),
|
||||||
'networkStatus': networkStatus,
|
'networkStatus': networkStatus,
|
||||||
'softwareName': 'PyBitmessage',
|
'softwareName': 'PyBitmessage',
|
||||||
'softwareVersion': softwareVersion
|
'softwareVersion': softwareVersion
|
||||||
|
@ -1475,6 +1491,8 @@ class BMRPCDispatcher(object):
|
||||||
@command('shutdown')
|
@command('shutdown')
|
||||||
def HandleShutdown(self):
|
def HandleShutdown(self):
|
||||||
"""Shutdown the bitmessage. Returns 'done'."""
|
"""Shutdown the bitmessage. Returns 'done'."""
|
||||||
|
if Inventory is None:
|
||||||
|
raise APIError(21, 'Could not import shutdown.')
|
||||||
# backward compatible trick because False == 0 is True
|
# backward compatible trick because False == 0 is True
|
||||||
state.shutdown = False
|
state.shutdown = False
|
||||||
return 'done'
|
return 'done'
|
||||||
|
|
Reference in New Issue
Block a user