3535
3636import base64
3737import decimal
38+ from http import HTTPStatus
3839import http .client
3940import json
4041import logging
4950log = logging .getLogger ("BitcoinRPC" )
5051
5152class JSONRPCException (Exception ):
52- def __init__ (self , rpc_error ):
53+ def __init__ (self , rpc_error , http_status = None ):
5354 try :
5455 errmsg = '%(message)s (%(code)i)' % rpc_error
5556 except (KeyError , TypeError ):
5657 errmsg = ''
5758 super ().__init__ (errmsg )
5859 self .error = rpc_error
60+ self .http_status = http_status
5961
6062
6163def EncodeDecimal (o ):
@@ -131,19 +133,26 @@ def get_request(self, *args, **argsn):
131133
132134 def __call__ (self , * args , ** argsn ):
133135 postdata = json .dumps (self .get_request (* args , ** argsn ), default = EncodeDecimal , ensure_ascii = self .ensure_ascii )
134- response = self ._request ('POST' , self .__url .path , postdata .encode ('utf-8' ))
136+ response , status = self ._request ('POST' , self .__url .path , postdata .encode ('utf-8' ))
135137 if response ['error' ] is not None :
136- raise JSONRPCException (response ['error' ])
138+ raise JSONRPCException (response ['error' ], status )
137139 elif 'result' not in response :
138140 raise JSONRPCException ({
139- 'code' : - 343 , 'message' : 'missing JSON-RPC result' })
141+ 'code' : - 343 , 'message' : 'missing JSON-RPC result' }, status )
142+ elif status != HTTPStatus .OK :
143+ raise JSONRPCException ({
144+ 'code' : - 342 , 'message' : 'non-200 HTTP status code but no JSON-RPC error' }, status )
140145 else :
141146 return response ['result' ]
142147
143148 def batch (self , rpc_call_list ):
144149 postdata = json .dumps (list (rpc_call_list ), default = EncodeDecimal , ensure_ascii = self .ensure_ascii )
145150 log .debug ("--> " + postdata )
146- return self ._request ('POST' , self .__url .path , postdata .encode ('utf-8' ))
151+ response , status = self ._request ('POST' , self .__url .path , postdata .encode ('utf-8' ))
152+ if status != HTTPStatus .OK :
153+ raise JSONRPCException ({
154+ 'code' : - 342 , 'message' : 'non-200 HTTP status code but no JSON-RPC error' }, status )
155+ return response
147156
148157 def _get_response (self ):
149158 req_start_time = time .time ()
@@ -162,8 +171,9 @@ def _get_response(self):
162171
163172 content_type = http_response .getheader ('Content-Type' )
164173 if content_type != 'application/json' :
165- raise JSONRPCException ({
166- 'code' : - 342 , 'message' : 'non-JSON HTTP response with \' %i %s\' from server' % (http_response .status , http_response .reason )})
174+ raise JSONRPCException (
175+ {'code' : - 342 , 'message' : 'non-JSON HTTP response with \' %i %s\' from server' % (http_response .status , http_response .reason )},
176+ http_response .status )
167177
168178 responsedata = http_response .read ().decode ('utf8' )
169179 response = json .loads (responsedata , parse_float = decimal .Decimal )
@@ -172,7 +182,7 @@ def _get_response(self):
172182 log .debug ("<-%s- [%.6f] %s" % (response ["id" ], elapsed , json .dumps (response ["result" ], default = EncodeDecimal , ensure_ascii = self .ensure_ascii )))
173183 else :
174184 log .debug ("<-- [%.6f] %s" % (elapsed , responsedata ))
175- return response
185+ return response , http_response . status
176186
177187 def __truediv__ (self , relative_uri ):
178188 return AuthServiceProxy ("{}/{}" .format (self .__service_url , relative_uri ), self ._service_name , connection = self .__conn )
0 commit comments