test_xmlrpc.py 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525
  1. import base64
  2. import datetime
  3. import decimal
  4. import sys
  5. import time
  6. import unittest
  7. from unittest import mock
  8. import xmlrpc.client as xmlrpclib
  9. import xmlrpc.server
  10. import http.client
  11. import http, http.server
  12. import socket
  13. import threading
  14. import re
  15. import io
  16. import contextlib
  17. from test import support
  18. from test.support import os_helper
  19. from test.support import socket_helper
  20. from test.support import threading_helper
  21. from test.support import ALWAYS_EQ, LARGEST, SMALLEST
  22. try:
  23. import gzip
  24. except ImportError:
  25. gzip = None
  26. support.requires_working_socket(module=True)
  27. alist = [{'astring': 'foo@bar.baz.spam',
  28. 'afloat': 7283.43,
  29. 'anint': 2**20,
  30. 'ashortlong': 2,
  31. 'anotherlist': ['.zyx.41'],
  32. 'abase64': xmlrpclib.Binary(b"my dog has fleas"),
  33. 'b64bytes': b"my dog has fleas",
  34. 'b64bytearray': bytearray(b"my dog has fleas"),
  35. 'boolean': False,
  36. 'unicode': '\u4000\u6000\u8000',
  37. 'ukey\u4000': 'regular value',
  38. 'datetime1': xmlrpclib.DateTime('20050210T11:41:23'),
  39. 'datetime2': xmlrpclib.DateTime(
  40. (2005, 2, 10, 11, 41, 23, 0, 1, -1)),
  41. 'datetime3': xmlrpclib.DateTime(
  42. datetime.datetime(2005, 2, 10, 11, 41, 23)),
  43. }]
  44. class XMLRPCTestCase(unittest.TestCase):
  45. def test_dump_load(self):
  46. dump = xmlrpclib.dumps((alist,))
  47. load = xmlrpclib.loads(dump)
  48. self.assertEqual(alist, load[0][0])
  49. def test_dump_bare_datetime(self):
  50. # This checks that an unwrapped datetime.date object can be handled
  51. # by the marshalling code. This can't be done via test_dump_load()
  52. # since with use_builtin_types set to 1 the unmarshaller would create
  53. # datetime objects for the 'datetime[123]' keys as well
  54. dt = datetime.datetime(2005, 2, 10, 11, 41, 23)
  55. self.assertEqual(dt, xmlrpclib.DateTime('20050210T11:41:23'))
  56. s = xmlrpclib.dumps((dt,))
  57. result, m = xmlrpclib.loads(s, use_builtin_types=True)
  58. (newdt,) = result
  59. self.assertEqual(newdt, dt)
  60. self.assertIs(type(newdt), datetime.datetime)
  61. self.assertIsNone(m)
  62. result, m = xmlrpclib.loads(s, use_builtin_types=False)
  63. (newdt,) = result
  64. self.assertEqual(newdt, dt)
  65. self.assertIs(type(newdt), xmlrpclib.DateTime)
  66. self.assertIsNone(m)
  67. result, m = xmlrpclib.loads(s, use_datetime=True)
  68. (newdt,) = result
  69. self.assertEqual(newdt, dt)
  70. self.assertIs(type(newdt), datetime.datetime)
  71. self.assertIsNone(m)
  72. result, m = xmlrpclib.loads(s, use_datetime=False)
  73. (newdt,) = result
  74. self.assertEqual(newdt, dt)
  75. self.assertIs(type(newdt), xmlrpclib.DateTime)
  76. self.assertIsNone(m)
  77. def test_datetime_before_1900(self):
  78. # same as before but with a date before 1900
  79. dt = datetime.datetime(1, 2, 10, 11, 41, 23)
  80. self.assertEqual(dt, xmlrpclib.DateTime('00010210T11:41:23'))
  81. s = xmlrpclib.dumps((dt,))
  82. result, m = xmlrpclib.loads(s, use_builtin_types=True)
  83. (newdt,) = result
  84. self.assertEqual(newdt, dt)
  85. self.assertIs(type(newdt), datetime.datetime)
  86. self.assertIsNone(m)
  87. result, m = xmlrpclib.loads(s, use_builtin_types=False)
  88. (newdt,) = result
  89. self.assertEqual(newdt, dt)
  90. self.assertIs(type(newdt), xmlrpclib.DateTime)
  91. self.assertIsNone(m)
  92. def test_bug_1164912 (self):
  93. d = xmlrpclib.DateTime()
  94. ((new_d,), dummy) = xmlrpclib.loads(xmlrpclib.dumps((d,),
  95. methodresponse=True))
  96. self.assertIsInstance(new_d.value, str)
  97. # Check that the output of dumps() is still an 8-bit string
  98. s = xmlrpclib.dumps((new_d,), methodresponse=True)
  99. self.assertIsInstance(s, str)
  100. def test_newstyle_class(self):
  101. class T(object):
  102. pass
  103. t = T()
  104. t.x = 100
  105. t.y = "Hello"
  106. ((t2,), dummy) = xmlrpclib.loads(xmlrpclib.dumps((t,)))
  107. self.assertEqual(t2, t.__dict__)
  108. def test_dump_big_long(self):
  109. self.assertRaises(OverflowError, xmlrpclib.dumps, (2**99,))
  110. def test_dump_bad_dict(self):
  111. self.assertRaises(TypeError, xmlrpclib.dumps, ({(1,2,3): 1},))
  112. def test_dump_recursive_seq(self):
  113. l = [1,2,3]
  114. t = [3,4,5,l]
  115. l.append(t)
  116. self.assertRaises(TypeError, xmlrpclib.dumps, (l,))
  117. def test_dump_recursive_dict(self):
  118. d = {'1':1, '2':1}
  119. t = {'3':3, 'd':d}
  120. d['t'] = t
  121. self.assertRaises(TypeError, xmlrpclib.dumps, (d,))
  122. def test_dump_big_int(self):
  123. if sys.maxsize > 2**31-1:
  124. self.assertRaises(OverflowError, xmlrpclib.dumps,
  125. (int(2**34),))
  126. xmlrpclib.dumps((xmlrpclib.MAXINT, xmlrpclib.MININT))
  127. self.assertRaises(OverflowError, xmlrpclib.dumps,
  128. (xmlrpclib.MAXINT+1,))
  129. self.assertRaises(OverflowError, xmlrpclib.dumps,
  130. (xmlrpclib.MININT-1,))
  131. def dummy_write(s):
  132. pass
  133. m = xmlrpclib.Marshaller()
  134. m.dump_int(xmlrpclib.MAXINT, dummy_write)
  135. m.dump_int(xmlrpclib.MININT, dummy_write)
  136. self.assertRaises(OverflowError, m.dump_int,
  137. xmlrpclib.MAXINT+1, dummy_write)
  138. self.assertRaises(OverflowError, m.dump_int,
  139. xmlrpclib.MININT-1, dummy_write)
  140. def test_dump_double(self):
  141. xmlrpclib.dumps((float(2 ** 34),))
  142. xmlrpclib.dumps((float(xmlrpclib.MAXINT),
  143. float(xmlrpclib.MININT)))
  144. xmlrpclib.dumps((float(xmlrpclib.MAXINT + 42),
  145. float(xmlrpclib.MININT - 42)))
  146. def dummy_write(s):
  147. pass
  148. m = xmlrpclib.Marshaller()
  149. m.dump_double(xmlrpclib.MAXINT, dummy_write)
  150. m.dump_double(xmlrpclib.MININT, dummy_write)
  151. m.dump_double(xmlrpclib.MAXINT + 42, dummy_write)
  152. m.dump_double(xmlrpclib.MININT - 42, dummy_write)
  153. def test_dump_none(self):
  154. value = alist + [None]
  155. arg1 = (alist + [None],)
  156. strg = xmlrpclib.dumps(arg1, allow_none=True)
  157. self.assertEqual(value,
  158. xmlrpclib.loads(strg)[0][0])
  159. self.assertRaises(TypeError, xmlrpclib.dumps, (arg1,))
  160. def test_dump_encoding(self):
  161. value = {'key\u20ac\xa4':
  162. 'value\u20ac\xa4'}
  163. strg = xmlrpclib.dumps((value,), encoding='iso-8859-15')
  164. strg = "<?xml version='1.0' encoding='iso-8859-15'?>" + strg
  165. self.assertEqual(xmlrpclib.loads(strg)[0][0], value)
  166. strg = strg.encode('iso-8859-15', 'xmlcharrefreplace')
  167. self.assertEqual(xmlrpclib.loads(strg)[0][0], value)
  168. strg = xmlrpclib.dumps((value,), encoding='iso-8859-15',
  169. methodresponse=True)
  170. self.assertEqual(xmlrpclib.loads(strg)[0][0], value)
  171. strg = strg.encode('iso-8859-15', 'xmlcharrefreplace')
  172. self.assertEqual(xmlrpclib.loads(strg)[0][0], value)
  173. methodname = 'method\u20ac\xa4'
  174. strg = xmlrpclib.dumps((value,), encoding='iso-8859-15',
  175. methodname=methodname)
  176. self.assertEqual(xmlrpclib.loads(strg)[0][0], value)
  177. self.assertEqual(xmlrpclib.loads(strg)[1], methodname)
  178. def test_dump_bytes(self):
  179. sample = b"my dog has fleas"
  180. self.assertEqual(sample, xmlrpclib.Binary(sample))
  181. for type_ in bytes, bytearray, xmlrpclib.Binary:
  182. value = type_(sample)
  183. s = xmlrpclib.dumps((value,))
  184. result, m = xmlrpclib.loads(s, use_builtin_types=True)
  185. (newvalue,) = result
  186. self.assertEqual(newvalue, sample)
  187. self.assertIs(type(newvalue), bytes)
  188. self.assertIsNone(m)
  189. result, m = xmlrpclib.loads(s, use_builtin_types=False)
  190. (newvalue,) = result
  191. self.assertEqual(newvalue, sample)
  192. self.assertIs(type(newvalue), xmlrpclib.Binary)
  193. self.assertIsNone(m)
  194. def test_loads_unsupported(self):
  195. ResponseError = xmlrpclib.ResponseError
  196. data = '<params><param><value><spam/></value></param></params>'
  197. self.assertRaises(ResponseError, xmlrpclib.loads, data)
  198. data = ('<params><param><value><array>'
  199. '<value><spam/></value>'
  200. '</array></value></param></params>')
  201. self.assertRaises(ResponseError, xmlrpclib.loads, data)
  202. data = ('<params><param><value><struct>'
  203. '<member><name>a</name><value><spam/></value></member>'
  204. '<member><name>b</name><value><spam/></value></member>'
  205. '</struct></value></param></params>')
  206. self.assertRaises(ResponseError, xmlrpclib.loads, data)
  207. def check_loads(self, s, value, **kwargs):
  208. dump = '<params><param><value>%s</value></param></params>' % s
  209. result, m = xmlrpclib.loads(dump, **kwargs)
  210. (newvalue,) = result
  211. self.assertEqual(newvalue, value)
  212. self.assertIs(type(newvalue), type(value))
  213. self.assertIsNone(m)
  214. def test_load_standard_types(self):
  215. check = self.check_loads
  216. check('string', 'string')
  217. check('<string>string</string>', 'string')
  218. check('<string>𝔘𝔫𝔦𝔠𝔬𝔡𝔢 string</string>', '𝔘𝔫𝔦𝔠𝔬𝔡𝔢 string')
  219. check('<int>2056183947</int>', 2056183947)
  220. check('<int>-2056183947</int>', -2056183947)
  221. check('<i4>2056183947</i4>', 2056183947)
  222. check('<double>46093.78125</double>', 46093.78125)
  223. check('<boolean>0</boolean>', False)
  224. check('<base64>AGJ5dGUgc3RyaW5n/w==</base64>',
  225. xmlrpclib.Binary(b'\x00byte string\xff'))
  226. check('<base64>AGJ5dGUgc3RyaW5n/w==</base64>',
  227. b'\x00byte string\xff', use_builtin_types=True)
  228. check('<dateTime.iso8601>20050210T11:41:23</dateTime.iso8601>',
  229. xmlrpclib.DateTime('20050210T11:41:23'))
  230. check('<dateTime.iso8601>20050210T11:41:23</dateTime.iso8601>',
  231. datetime.datetime(2005, 2, 10, 11, 41, 23),
  232. use_builtin_types=True)
  233. check('<array><data>'
  234. '<value><int>1</int></value><value><int>2</int></value>'
  235. '</data></array>', [1, 2])
  236. check('<struct>'
  237. '<member><name>b</name><value><int>2</int></value></member>'
  238. '<member><name>a</name><value><int>1</int></value></member>'
  239. '</struct>', {'a': 1, 'b': 2})
  240. def test_load_extension_types(self):
  241. check = self.check_loads
  242. check('<nil/>', None)
  243. check('<ex:nil/>', None)
  244. check('<i1>205</i1>', 205)
  245. check('<i2>20561</i2>', 20561)
  246. check('<i8>9876543210</i8>', 9876543210)
  247. check('<biginteger>98765432100123456789</biginteger>',
  248. 98765432100123456789)
  249. check('<float>93.78125</float>', 93.78125)
  250. check('<bigdecimal>9876543210.0123456789</bigdecimal>',
  251. decimal.Decimal('9876543210.0123456789'))
  252. def test_limit_int(self):
  253. check = self.check_loads
  254. maxdigits = 5000
  255. with support.adjust_int_max_str_digits(maxdigits):
  256. s = '1' * (maxdigits + 1)
  257. with self.assertRaises(ValueError):
  258. check(f'<int>{s}</int>', None)
  259. with self.assertRaises(ValueError):
  260. check(f'<biginteger>{s}</biginteger>', None)
  261. def test_get_host_info(self):
  262. # see bug #3613, this raised a TypeError
  263. transp = xmlrpc.client.Transport()
  264. self.assertEqual(transp.get_host_info("user@host.tld"),
  265. ('host.tld',
  266. [('Authorization', 'Basic dXNlcg==')], {}))
  267. def test_ssl_presence(self):
  268. try:
  269. import ssl
  270. except ImportError:
  271. has_ssl = False
  272. else:
  273. has_ssl = True
  274. try:
  275. xmlrpc.client.ServerProxy('https://localhost:9999').bad_function()
  276. except NotImplementedError:
  277. self.assertFalse(has_ssl, "xmlrpc client's error with SSL support")
  278. except OSError:
  279. self.assertTrue(has_ssl)
  280. def test_keepalive_disconnect(self):
  281. class RequestHandler(http.server.BaseHTTPRequestHandler):
  282. protocol_version = "HTTP/1.1"
  283. handled = False
  284. def do_POST(self):
  285. length = int(self.headers.get("Content-Length"))
  286. self.rfile.read(length)
  287. if self.handled:
  288. self.close_connection = True
  289. return
  290. response = xmlrpclib.dumps((5,), methodresponse=True)
  291. response = response.encode()
  292. self.send_response(http.HTTPStatus.OK)
  293. self.send_header("Content-Length", len(response))
  294. self.end_headers()
  295. self.wfile.write(response)
  296. self.handled = True
  297. self.close_connection = False
  298. def log_message(self, format, *args):
  299. # don't clobber sys.stderr
  300. pass
  301. def run_server():
  302. server.socket.settimeout(float(1)) # Don't hang if client fails
  303. server.handle_request() # First request and attempt at second
  304. server.handle_request() # Retried second request
  305. server = http.server.HTTPServer((socket_helper.HOST, 0), RequestHandler)
  306. self.addCleanup(server.server_close)
  307. thread = threading.Thread(target=run_server)
  308. thread.start()
  309. self.addCleanup(thread.join)
  310. url = "http://{}:{}/".format(*server.server_address)
  311. with xmlrpclib.ServerProxy(url) as p:
  312. self.assertEqual(p.method(), 5)
  313. self.assertEqual(p.method(), 5)
  314. class SimpleXMLRPCDispatcherTestCase(unittest.TestCase):
  315. class DispatchExc(Exception):
  316. """Raised inside the dispatched functions when checking for
  317. chained exceptions"""
  318. def test_call_registered_func(self):
  319. """Calls explicitly registered function"""
  320. # Makes sure any exception raised inside the function has no other
  321. # exception chained to it
  322. exp_params = 1, 2, 3
  323. def dispatched_func(*params):
  324. raise self.DispatchExc(params)
  325. dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
  326. dispatcher.register_function(dispatched_func)
  327. with self.assertRaises(self.DispatchExc) as exc_ctx:
  328. dispatcher._dispatch('dispatched_func', exp_params)
  329. self.assertEqual(exc_ctx.exception.args, (exp_params,))
  330. self.assertIsNone(exc_ctx.exception.__cause__)
  331. self.assertIsNone(exc_ctx.exception.__context__)
  332. def test_call_instance_func(self):
  333. """Calls a registered instance attribute as a function"""
  334. # Makes sure any exception raised inside the function has no other
  335. # exception chained to it
  336. exp_params = 1, 2, 3
  337. class DispatchedClass:
  338. def dispatched_func(self, *params):
  339. raise SimpleXMLRPCDispatcherTestCase.DispatchExc(params)
  340. dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
  341. dispatcher.register_instance(DispatchedClass())
  342. with self.assertRaises(self.DispatchExc) as exc_ctx:
  343. dispatcher._dispatch('dispatched_func', exp_params)
  344. self.assertEqual(exc_ctx.exception.args, (exp_params,))
  345. self.assertIsNone(exc_ctx.exception.__cause__)
  346. self.assertIsNone(exc_ctx.exception.__context__)
  347. def test_call_dispatch_func(self):
  348. """Calls the registered instance's `_dispatch` function"""
  349. # Makes sure any exception raised inside the function has no other
  350. # exception chained to it
  351. exp_method = 'method'
  352. exp_params = 1, 2, 3
  353. class TestInstance:
  354. def _dispatch(self, method, params):
  355. raise SimpleXMLRPCDispatcherTestCase.DispatchExc(
  356. method, params)
  357. dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
  358. dispatcher.register_instance(TestInstance())
  359. with self.assertRaises(self.DispatchExc) as exc_ctx:
  360. dispatcher._dispatch(exp_method, exp_params)
  361. self.assertEqual(exc_ctx.exception.args, (exp_method, exp_params))
  362. self.assertIsNone(exc_ctx.exception.__cause__)
  363. self.assertIsNone(exc_ctx.exception.__context__)
  364. def test_registered_func_is_none(self):
  365. """Calls explicitly registered function which is None"""
  366. dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
  367. dispatcher.register_function(None, name='method')
  368. with self.assertRaisesRegex(Exception, 'method'):
  369. dispatcher._dispatch('method', ('param',))
  370. def test_instance_has_no_func(self):
  371. """Attempts to call nonexistent function on a registered instance"""
  372. dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
  373. dispatcher.register_instance(object())
  374. with self.assertRaisesRegex(Exception, 'method'):
  375. dispatcher._dispatch('method', ('param',))
  376. def test_cannot_locate_func(self):
  377. """Calls a function that the dispatcher cannot locate"""
  378. dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
  379. with self.assertRaisesRegex(Exception, 'method'):
  380. dispatcher._dispatch('method', ('param',))
  381. class HelperTestCase(unittest.TestCase):
  382. def test_escape(self):
  383. self.assertEqual(xmlrpclib.escape("a&b"), "a&amp;b")
  384. self.assertEqual(xmlrpclib.escape("a<b"), "a&lt;b")
  385. self.assertEqual(xmlrpclib.escape("a>b"), "a&gt;b")
  386. class FaultTestCase(unittest.TestCase):
  387. def test_repr(self):
  388. f = xmlrpclib.Fault(42, 'Test Fault')
  389. self.assertEqual(repr(f), "<Fault 42: 'Test Fault'>")
  390. self.assertEqual(repr(f), str(f))
  391. def test_dump_fault(self):
  392. f = xmlrpclib.Fault(42, 'Test Fault')
  393. s = xmlrpclib.dumps((f,))
  394. (newf,), m = xmlrpclib.loads(s)
  395. self.assertEqual(newf, {'faultCode': 42, 'faultString': 'Test Fault'})
  396. self.assertEqual(m, None)
  397. s = xmlrpclib.Marshaller().dumps(f)
  398. self.assertRaises(xmlrpclib.Fault, xmlrpclib.loads, s)
  399. def test_dotted_attribute(self):
  400. # this will raise AttributeError because code don't want us to use
  401. # private methods
  402. self.assertRaises(AttributeError,
  403. xmlrpc.server.resolve_dotted_attribute, str, '__add')
  404. self.assertTrue(xmlrpc.server.resolve_dotted_attribute(str, 'title'))
  405. class DateTimeTestCase(unittest.TestCase):
  406. def test_default(self):
  407. with mock.patch('time.localtime') as localtime_mock:
  408. time_struct = time.struct_time(
  409. [2013, 7, 15, 0, 24, 49, 0, 196, 0])
  410. localtime_mock.return_value = time_struct
  411. localtime = time.localtime()
  412. t = xmlrpclib.DateTime()
  413. self.assertEqual(str(t),
  414. time.strftime("%Y%m%dT%H:%M:%S", localtime))
  415. def test_time(self):
  416. d = 1181399930.036952
  417. t = xmlrpclib.DateTime(d)
  418. self.assertEqual(str(t),
  419. time.strftime("%Y%m%dT%H:%M:%S", time.localtime(d)))
  420. def test_time_tuple(self):
  421. d = (2007,6,9,10,38,50,5,160,0)
  422. t = xmlrpclib.DateTime(d)
  423. self.assertEqual(str(t), '20070609T10:38:50')
  424. def test_time_struct(self):
  425. d = time.localtime(1181399930.036952)
  426. t = xmlrpclib.DateTime(d)
  427. self.assertEqual(str(t), time.strftime("%Y%m%dT%H:%M:%S", d))
  428. def test_datetime_datetime(self):
  429. d = datetime.datetime(2007,1,2,3,4,5)
  430. t = xmlrpclib.DateTime(d)
  431. self.assertEqual(str(t), '20070102T03:04:05')
  432. def test_repr(self):
  433. d = datetime.datetime(2007,1,2,3,4,5)
  434. t = xmlrpclib.DateTime(d)
  435. val ="<DateTime '20070102T03:04:05' at %#x>" % id(t)
  436. self.assertEqual(repr(t), val)
  437. def test_decode(self):
  438. d = ' 20070908T07:11:13 '
  439. t1 = xmlrpclib.DateTime()
  440. t1.decode(d)
  441. tref = xmlrpclib.DateTime(datetime.datetime(2007,9,8,7,11,13))
  442. self.assertEqual(t1, tref)
  443. t2 = xmlrpclib._datetime(d)
  444. self.assertEqual(t2, tref)
  445. def test_comparison(self):
  446. now = datetime.datetime.now()
  447. dtime = xmlrpclib.DateTime(now.timetuple())
  448. # datetime vs. DateTime
  449. self.assertTrue(dtime == now)
  450. self.assertTrue(now == dtime)
  451. then = now + datetime.timedelta(seconds=4)
  452. self.assertTrue(then >= dtime)
  453. self.assertTrue(dtime < then)
  454. # str vs. DateTime
  455. dstr = now.strftime("%Y%m%dT%H:%M:%S")
  456. self.assertTrue(dtime == dstr)
  457. self.assertTrue(dstr == dtime)
  458. dtime_then = xmlrpclib.DateTime(then.timetuple())
  459. self.assertTrue(dtime_then >= dstr)
  460. self.assertTrue(dstr < dtime_then)
  461. # some other types
  462. dbytes = dstr.encode('ascii')
  463. dtuple = now.timetuple()
  464. self.assertFalse(dtime == 1970)
  465. self.assertTrue(dtime != dbytes)
  466. self.assertFalse(dtime == bytearray(dbytes))
  467. self.assertTrue(dtime != dtuple)
  468. with self.assertRaises(TypeError):
  469. dtime < float(1970)
  470. with self.assertRaises(TypeError):
  471. dtime > dbytes
  472. with self.assertRaises(TypeError):
  473. dtime <= bytearray(dbytes)
  474. with self.assertRaises(TypeError):
  475. dtime >= dtuple
  476. self.assertTrue(dtime == ALWAYS_EQ)
  477. self.assertFalse(dtime != ALWAYS_EQ)
  478. self.assertTrue(dtime < LARGEST)
  479. self.assertFalse(dtime > LARGEST)
  480. self.assertTrue(dtime <= LARGEST)
  481. self.assertFalse(dtime >= LARGEST)
  482. self.assertFalse(dtime < SMALLEST)
  483. self.assertTrue(dtime > SMALLEST)
  484. self.assertFalse(dtime <= SMALLEST)
  485. self.assertTrue(dtime >= SMALLEST)
  486. class BinaryTestCase(unittest.TestCase):
  487. # XXX What should str(Binary(b"\xff")) return? I'm choosing "\xff"
  488. # for now (i.e. interpreting the binary data as Latin-1-encoded
  489. # text). But this feels very unsatisfactory. Perhaps we should
  490. # only define repr(), and return r"Binary(b'\xff')" instead?
  491. def test_default(self):
  492. t = xmlrpclib.Binary()
  493. self.assertEqual(str(t), '')
  494. def test_string(self):
  495. d = b'\x01\x02\x03abc123\xff\xfe'
  496. t = xmlrpclib.Binary(d)
  497. self.assertEqual(str(t), str(d, "latin-1"))
  498. def test_decode(self):
  499. d = b'\x01\x02\x03abc123\xff\xfe'
  500. de = base64.encodebytes(d)
  501. t1 = xmlrpclib.Binary()
  502. t1.decode(de)
  503. self.assertEqual(str(t1), str(d, "latin-1"))
  504. t2 = xmlrpclib._binary(de)
  505. self.assertEqual(str(t2), str(d, "latin-1"))
  506. ADDR = PORT = URL = None
  507. # The evt is set twice. First when the server is ready to serve.
  508. # Second when the server has been shutdown. The user must clear
  509. # the event after it has been set the first time to catch the second set.
  510. def http_server(evt, numrequests, requestHandler=None, encoding=None):
  511. class TestInstanceClass:
  512. def div(self, x, y):
  513. return x // y
  514. def _methodHelp(self, name):
  515. if name == 'div':
  516. return 'This is the div function'
  517. class Fixture:
  518. @staticmethod
  519. def getData():
  520. return '42'
  521. class MyXMLRPCServer(xmlrpc.server.SimpleXMLRPCServer):
  522. def get_request(self):
  523. # Ensure the socket is always non-blocking. On Linux, socket
  524. # attributes are not inherited like they are on *BSD and Windows.
  525. s, port = self.socket.accept()
  526. s.setblocking(True)
  527. return s, port
  528. if not requestHandler:
  529. requestHandler = xmlrpc.server.SimpleXMLRPCRequestHandler
  530. serv = MyXMLRPCServer(("localhost", 0), requestHandler,
  531. encoding=encoding,
  532. logRequests=False, bind_and_activate=False)
  533. try:
  534. serv.server_bind()
  535. global ADDR, PORT, URL
  536. ADDR, PORT = serv.socket.getsockname()
  537. #connect to IP address directly. This avoids socket.create_connection()
  538. #trying to connect to "localhost" using all address families, which
  539. #causes slowdown e.g. on vista which supports AF_INET6. The server listens
  540. #on AF_INET only.
  541. URL = "http://%s:%d"%(ADDR, PORT)
  542. serv.server_activate()
  543. serv.register_introspection_functions()
  544. serv.register_multicall_functions()
  545. serv.register_function(pow)
  546. serv.register_function(lambda x: x, 'têšt')
  547. @serv.register_function
  548. def my_function():
  549. '''This is my function'''
  550. return True
  551. @serv.register_function(name='add')
  552. def _(x, y):
  553. return x + y
  554. testInstance = TestInstanceClass()
  555. serv.register_instance(testInstance, allow_dotted_names=True)
  556. evt.set()
  557. # handle up to 'numrequests' requests
  558. while numrequests > 0:
  559. serv.handle_request()
  560. numrequests -= 1
  561. except TimeoutError:
  562. pass
  563. finally:
  564. serv.socket.close()
  565. PORT = None
  566. evt.set()
  567. def http_multi_server(evt, numrequests, requestHandler=None):
  568. class TestInstanceClass:
  569. def div(self, x, y):
  570. return x // y
  571. def _methodHelp(self, name):
  572. if name == 'div':
  573. return 'This is the div function'
  574. def my_function():
  575. '''This is my function'''
  576. return True
  577. class MyXMLRPCServer(xmlrpc.server.MultiPathXMLRPCServer):
  578. def get_request(self):
  579. # Ensure the socket is always non-blocking. On Linux, socket
  580. # attributes are not inherited like they are on *BSD and Windows.
  581. s, port = self.socket.accept()
  582. s.setblocking(True)
  583. return s, port
  584. if not requestHandler:
  585. requestHandler = xmlrpc.server.SimpleXMLRPCRequestHandler
  586. class MyRequestHandler(requestHandler):
  587. rpc_paths = []
  588. class BrokenDispatcher:
  589. def _marshaled_dispatch(self, data, dispatch_method=None, path=None):
  590. raise RuntimeError("broken dispatcher")
  591. serv = MyXMLRPCServer(("localhost", 0), MyRequestHandler,
  592. logRequests=False, bind_and_activate=False)
  593. serv.socket.settimeout(3)
  594. serv.server_bind()
  595. try:
  596. global ADDR, PORT, URL
  597. ADDR, PORT = serv.socket.getsockname()
  598. #connect to IP address directly. This avoids socket.create_connection()
  599. #trying to connect to "localhost" using all address families, which
  600. #causes slowdown e.g. on vista which supports AF_INET6. The server listens
  601. #on AF_INET only.
  602. URL = "http://%s:%d"%(ADDR, PORT)
  603. serv.server_activate()
  604. paths = [
  605. "/foo", "/foo/bar",
  606. "/foo?k=v", "/foo#frag", "/foo?k=v#frag",
  607. "", "/", "/RPC2", "?k=v", "#frag",
  608. ]
  609. for path in paths:
  610. d = serv.add_dispatcher(path, xmlrpc.server.SimpleXMLRPCDispatcher())
  611. d.register_introspection_functions()
  612. d.register_multicall_functions()
  613. d.register_function(lambda p=path: p, 'test')
  614. serv.get_dispatcher(paths[0]).register_function(pow)
  615. serv.get_dispatcher(paths[1]).register_function(lambda x,y: x+y, 'add')
  616. serv.add_dispatcher("/is/broken", BrokenDispatcher())
  617. evt.set()
  618. # handle up to 'numrequests' requests
  619. while numrequests > 0:
  620. serv.handle_request()
  621. numrequests -= 1
  622. except TimeoutError:
  623. pass
  624. finally:
  625. serv.socket.close()
  626. PORT = None
  627. evt.set()
  628. # This function prevents errors like:
  629. # <ProtocolError for localhost:57527/RPC2: 500 Internal Server Error>
  630. def is_unavailable_exception(e):
  631. '''Returns True if the given ProtocolError is the product of a server-side
  632. exception caused by the 'temporarily unavailable' response sometimes
  633. given by operations on non-blocking sockets.'''
  634. # sometimes we get a -1 error code and/or empty headers
  635. try:
  636. if e.errcode == -1 or e.headers is None:
  637. return True
  638. exc_mess = e.headers.get('X-exception')
  639. except AttributeError:
  640. # Ignore OSErrors here.
  641. exc_mess = str(e)
  642. if exc_mess and 'temporarily unavailable' in exc_mess.lower():
  643. return True
  644. def make_request_and_skipIf(condition, reason):
  645. # If we skip the test, we have to make a request because
  646. # the server created in setUp blocks expecting one to come in.
  647. if not condition:
  648. return lambda func: func
  649. def decorator(func):
  650. def make_request_and_skip(self):
  651. try:
  652. xmlrpclib.ServerProxy(URL).my_function()
  653. except (xmlrpclib.ProtocolError, OSError) as e:
  654. if not is_unavailable_exception(e):
  655. raise
  656. raise unittest.SkipTest(reason)
  657. return make_request_and_skip
  658. return decorator
  659. class BaseServerTestCase(unittest.TestCase):
  660. requestHandler = None
  661. request_count = 1
  662. threadFunc = staticmethod(http_server)
  663. def setUp(self):
  664. # enable traceback reporting
  665. xmlrpc.server.SimpleXMLRPCServer._send_traceback_header = True
  666. self.evt = threading.Event()
  667. # start server thread to handle requests
  668. serv_args = (self.evt, self.request_count, self.requestHandler)
  669. thread = threading.Thread(target=self.threadFunc, args=serv_args)
  670. thread.start()
  671. self.addCleanup(thread.join)
  672. # wait for the server to be ready
  673. self.evt.wait()
  674. self.evt.clear()
  675. def tearDown(self):
  676. # wait on the server thread to terminate
  677. self.evt.wait()
  678. # disable traceback reporting
  679. xmlrpc.server.SimpleXMLRPCServer._send_traceback_header = False
  680. class SimpleServerTestCase(BaseServerTestCase):
  681. def test_simple1(self):
  682. try:
  683. p = xmlrpclib.ServerProxy(URL)
  684. self.assertEqual(p.pow(6,8), 6**8)
  685. except (xmlrpclib.ProtocolError, OSError) as e:
  686. # ignore failures due to non-blocking socket 'unavailable' errors
  687. if not is_unavailable_exception(e):
  688. # protocol error; provide additional information in test output
  689. self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
  690. def test_nonascii(self):
  691. start_string = 'P\N{LATIN SMALL LETTER Y WITH CIRCUMFLEX}t'
  692. end_string = 'h\N{LATIN SMALL LETTER O WITH HORN}n'
  693. try:
  694. p = xmlrpclib.ServerProxy(URL)
  695. self.assertEqual(p.add(start_string, end_string),
  696. start_string + end_string)
  697. except (xmlrpclib.ProtocolError, OSError) as e:
  698. # ignore failures due to non-blocking socket 'unavailable' errors
  699. if not is_unavailable_exception(e):
  700. # protocol error; provide additional information in test output
  701. self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
  702. def test_client_encoding(self):
  703. start_string = '\u20ac'
  704. end_string = '\xa4'
  705. try:
  706. p = xmlrpclib.ServerProxy(URL, encoding='iso-8859-15')
  707. self.assertEqual(p.add(start_string, end_string),
  708. start_string + end_string)
  709. except (xmlrpclib.ProtocolError, socket.error) as e:
  710. # ignore failures due to non-blocking socket unavailable errors.
  711. if not is_unavailable_exception(e):
  712. # protocol error; provide additional information in test output
  713. self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
  714. def test_nonascii_methodname(self):
  715. try:
  716. p = xmlrpclib.ServerProxy(URL, encoding='ascii')
  717. self.assertEqual(p.têšt(42), 42)
  718. except (xmlrpclib.ProtocolError, socket.error) as e:
  719. # ignore failures due to non-blocking socket unavailable errors.
  720. if not is_unavailable_exception(e):
  721. # protocol error; provide additional information in test output
  722. self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
  723. def test_404(self):
  724. # send POST with http.client, it should return 404 header and
  725. # 'Not Found' message.
  726. with contextlib.closing(http.client.HTTPConnection(ADDR, PORT)) as conn:
  727. conn.request('POST', '/this-is-not-valid')
  728. response = conn.getresponse()
  729. self.assertEqual(response.status, 404)
  730. self.assertEqual(response.reason, 'Not Found')
  731. def test_introspection1(self):
  732. expected_methods = set(['pow', 'div', 'my_function', 'add', 'têšt',
  733. 'system.listMethods', 'system.methodHelp',
  734. 'system.methodSignature', 'system.multicall',
  735. 'Fixture'])
  736. try:
  737. p = xmlrpclib.ServerProxy(URL)
  738. meth = p.system.listMethods()
  739. self.assertEqual(set(meth), expected_methods)
  740. except (xmlrpclib.ProtocolError, OSError) as e:
  741. # ignore failures due to non-blocking socket 'unavailable' errors
  742. if not is_unavailable_exception(e):
  743. # protocol error; provide additional information in test output
  744. self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
  745. def test_introspection2(self):
  746. try:
  747. # test _methodHelp()
  748. p = xmlrpclib.ServerProxy(URL)
  749. divhelp = p.system.methodHelp('div')
  750. self.assertEqual(divhelp, 'This is the div function')
  751. except (xmlrpclib.ProtocolError, OSError) as e:
  752. # ignore failures due to non-blocking socket 'unavailable' errors
  753. if not is_unavailable_exception(e):
  754. # protocol error; provide additional information in test output
  755. self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
  756. @make_request_and_skipIf(sys.flags.optimize >= 2,
  757. "Docstrings are omitted with -O2 and above")
  758. def test_introspection3(self):
  759. try:
  760. # test native doc
  761. p = xmlrpclib.ServerProxy(URL)
  762. myfunction = p.system.methodHelp('my_function')
  763. self.assertEqual(myfunction, 'This is my function')
  764. except (xmlrpclib.ProtocolError, OSError) as e:
  765. # ignore failures due to non-blocking socket 'unavailable' errors
  766. if not is_unavailable_exception(e):
  767. # protocol error; provide additional information in test output
  768. self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
  769. def test_introspection4(self):
  770. # the SimpleXMLRPCServer doesn't support signatures, but
  771. # at least check that we can try making the call
  772. try:
  773. p = xmlrpclib.ServerProxy(URL)
  774. divsig = p.system.methodSignature('div')
  775. self.assertEqual(divsig, 'signatures not supported')
  776. except (xmlrpclib.ProtocolError, OSError) as e:
  777. # ignore failures due to non-blocking socket 'unavailable' errors
  778. if not is_unavailable_exception(e):
  779. # protocol error; provide additional information in test output
  780. self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
  781. def test_multicall(self):
  782. try:
  783. p = xmlrpclib.ServerProxy(URL)
  784. multicall = xmlrpclib.MultiCall(p)
  785. multicall.add(2,3)
  786. multicall.pow(6,8)
  787. multicall.div(127,42)
  788. add_result, pow_result, div_result = multicall()
  789. self.assertEqual(add_result, 2+3)
  790. self.assertEqual(pow_result, 6**8)
  791. self.assertEqual(div_result, 127//42)
  792. except (xmlrpclib.ProtocolError, OSError) as e:
  793. # ignore failures due to non-blocking socket 'unavailable' errors
  794. if not is_unavailable_exception(e):
  795. # protocol error; provide additional information in test output
  796. self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
  797. def test_non_existing_multicall(self):
  798. try:
  799. p = xmlrpclib.ServerProxy(URL)
  800. multicall = xmlrpclib.MultiCall(p)
  801. multicall.this_is_not_exists()
  802. result = multicall()
  803. # result.results contains;
  804. # [{'faultCode': 1, 'faultString': '<class \'exceptions.Exception\'>:'
  805. # 'method "this_is_not_exists" is not supported'>}]
  806. self.assertEqual(result.results[0]['faultCode'], 1)
  807. self.assertEqual(result.results[0]['faultString'],
  808. '<class \'Exception\'>:method "this_is_not_exists" '
  809. 'is not supported')
  810. except (xmlrpclib.ProtocolError, OSError) as e:
  811. # ignore failures due to non-blocking socket 'unavailable' errors
  812. if not is_unavailable_exception(e):
  813. # protocol error; provide additional information in test output
  814. self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
  815. def test_dotted_attribute(self):
  816. # Raises an AttributeError because private methods are not allowed.
  817. self.assertRaises(AttributeError,
  818. xmlrpc.server.resolve_dotted_attribute, str, '__add')
  819. self.assertTrue(xmlrpc.server.resolve_dotted_attribute(str, 'title'))
  820. # Get the test to run faster by sending a request with test_simple1.
  821. # This avoids waiting for the socket timeout.
  822. self.test_simple1()
  823. def test_allow_dotted_names_true(self):
  824. # XXX also need allow_dotted_names_false test.
  825. server = xmlrpclib.ServerProxy("http://%s:%d/RPC2" % (ADDR, PORT))
  826. data = server.Fixture.getData()
  827. self.assertEqual(data, '42')
  828. def test_unicode_host(self):
  829. server = xmlrpclib.ServerProxy("http://%s:%d/RPC2" % (ADDR, PORT))
  830. self.assertEqual(server.add("a", "\xe9"), "a\xe9")
  831. def test_partial_post(self):
  832. # Check that a partial POST doesn't make the server loop: issue #14001.
  833. with contextlib.closing(socket.create_connection((ADDR, PORT))) as conn:
  834. conn.send('POST /RPC2 HTTP/1.0\r\n'
  835. 'Content-Length: 100\r\n\r\n'
  836. 'bye HTTP/1.1\r\n'
  837. f'Host: {ADDR}:{PORT}\r\n'
  838. 'Accept-Encoding: identity\r\n'
  839. 'Content-Length: 0\r\n\r\n'.encode('ascii'))
  840. def test_context_manager(self):
  841. with xmlrpclib.ServerProxy(URL) as server:
  842. server.add(2, 3)
  843. self.assertNotEqual(server('transport')._connection,
  844. (None, None))
  845. self.assertEqual(server('transport')._connection,
  846. (None, None))
  847. def test_context_manager_method_error(self):
  848. try:
  849. with xmlrpclib.ServerProxy(URL) as server:
  850. server.add(2, "a")
  851. except xmlrpclib.Fault:
  852. pass
  853. self.assertEqual(server('transport')._connection,
  854. (None, None))
  855. class SimpleServerEncodingTestCase(BaseServerTestCase):
  856. @staticmethod
  857. def threadFunc(evt, numrequests, requestHandler=None, encoding=None):
  858. http_server(evt, numrequests, requestHandler, 'iso-8859-15')
  859. def test_server_encoding(self):
  860. start_string = '\u20ac'
  861. end_string = '\xa4'
  862. try:
  863. p = xmlrpclib.ServerProxy(URL)
  864. self.assertEqual(p.add(start_string, end_string),
  865. start_string + end_string)
  866. except (xmlrpclib.ProtocolError, socket.error) as e:
  867. # ignore failures due to non-blocking socket unavailable errors.
  868. if not is_unavailable_exception(e):
  869. # protocol error; provide additional information in test output
  870. self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
  871. class MultiPathServerTestCase(BaseServerTestCase):
  872. threadFunc = staticmethod(http_multi_server)
  873. request_count = 2
  874. def test_path1(self):
  875. p = xmlrpclib.ServerProxy(URL+"/foo")
  876. self.assertEqual(p.pow(6,8), 6**8)
  877. self.assertRaises(xmlrpclib.Fault, p.add, 6, 8)
  878. def test_path2(self):
  879. p = xmlrpclib.ServerProxy(URL+"/foo/bar")
  880. self.assertEqual(p.add(6,8), 6+8)
  881. self.assertRaises(xmlrpclib.Fault, p.pow, 6, 8)
  882. def test_path3(self):
  883. p = xmlrpclib.ServerProxy(URL+"/is/broken")
  884. self.assertRaises(xmlrpclib.Fault, p.add, 6, 8)
  885. def test_invalid_path(self):
  886. p = xmlrpclib.ServerProxy(URL+"/invalid")
  887. self.assertRaises(xmlrpclib.Fault, p.add, 6, 8)
  888. def test_path_query_fragment(self):
  889. p = xmlrpclib.ServerProxy(URL+"/foo?k=v#frag")
  890. self.assertEqual(p.test(), "/foo?k=v#frag")
  891. def test_path_fragment(self):
  892. p = xmlrpclib.ServerProxy(URL+"/foo#frag")
  893. self.assertEqual(p.test(), "/foo#frag")
  894. def test_path_query(self):
  895. p = xmlrpclib.ServerProxy(URL+"/foo?k=v")
  896. self.assertEqual(p.test(), "/foo?k=v")
  897. def test_empty_path(self):
  898. p = xmlrpclib.ServerProxy(URL)
  899. self.assertEqual(p.test(), "/RPC2")
  900. def test_root_path(self):
  901. p = xmlrpclib.ServerProxy(URL + "/")
  902. self.assertEqual(p.test(), "/")
  903. def test_empty_path_query(self):
  904. p = xmlrpclib.ServerProxy(URL + "?k=v")
  905. self.assertEqual(p.test(), "?k=v")
  906. def test_empty_path_fragment(self):
  907. p = xmlrpclib.ServerProxy(URL + "#frag")
  908. self.assertEqual(p.test(), "#frag")
  909. #A test case that verifies that a server using the HTTP/1.1 keep-alive mechanism
  910. #does indeed serve subsequent requests on the same connection
  911. class BaseKeepaliveServerTestCase(BaseServerTestCase):
  912. #a request handler that supports keep-alive and logs requests into a
  913. #class variable
  914. class RequestHandler(xmlrpc.server.SimpleXMLRPCRequestHandler):
  915. parentClass = xmlrpc.server.SimpleXMLRPCRequestHandler
  916. protocol_version = 'HTTP/1.1'
  917. myRequests = []
  918. def handle(self):
  919. self.myRequests.append([])
  920. self.reqidx = len(self.myRequests)-1
  921. return self.parentClass.handle(self)
  922. def handle_one_request(self):
  923. result = self.parentClass.handle_one_request(self)
  924. self.myRequests[self.reqidx].append(self.raw_requestline)
  925. return result
  926. requestHandler = RequestHandler
  927. def setUp(self):
  928. #clear request log
  929. self.RequestHandler.myRequests = []
  930. return BaseServerTestCase.setUp(self)
  931. #A test case that verifies that a server using the HTTP/1.1 keep-alive mechanism
  932. #does indeed serve subsequent requests on the same connection
  933. class KeepaliveServerTestCase1(BaseKeepaliveServerTestCase):
  934. def test_two(self):
  935. p = xmlrpclib.ServerProxy(URL)
  936. #do three requests.
  937. self.assertEqual(p.pow(6,8), 6**8)
  938. self.assertEqual(p.pow(6,8), 6**8)
  939. self.assertEqual(p.pow(6,8), 6**8)
  940. p("close")()
  941. #they should have all been handled by a single request handler
  942. self.assertEqual(len(self.RequestHandler.myRequests), 1)
  943. #check that we did at least two (the third may be pending append
  944. #due to thread scheduling)
  945. self.assertGreaterEqual(len(self.RequestHandler.myRequests[-1]), 2)
  946. #test special attribute access on the serverproxy, through the __call__
  947. #function.
  948. class KeepaliveServerTestCase2(BaseKeepaliveServerTestCase):
  949. #ask for two keepalive requests to be handled.
  950. request_count=2
  951. def test_close(self):
  952. p = xmlrpclib.ServerProxy(URL)
  953. #do some requests with close.
  954. self.assertEqual(p.pow(6,8), 6**8)
  955. self.assertEqual(p.pow(6,8), 6**8)
  956. self.assertEqual(p.pow(6,8), 6**8)
  957. p("close")() #this should trigger a new keep-alive request
  958. self.assertEqual(p.pow(6,8), 6**8)
  959. self.assertEqual(p.pow(6,8), 6**8)
  960. self.assertEqual(p.pow(6,8), 6**8)
  961. p("close")()
  962. #they should have all been two request handlers, each having logged at least
  963. #two complete requests
  964. self.assertEqual(len(self.RequestHandler.myRequests), 2)
  965. self.assertGreaterEqual(len(self.RequestHandler.myRequests[-1]), 2)
  966. self.assertGreaterEqual(len(self.RequestHandler.myRequests[-2]), 2)
  967. def test_transport(self):
  968. p = xmlrpclib.ServerProxy(URL)
  969. #do some requests with close.
  970. self.assertEqual(p.pow(6,8), 6**8)
  971. p("transport").close() #same as above, really.
  972. self.assertEqual(p.pow(6,8), 6**8)
  973. p("close")()
  974. self.assertEqual(len(self.RequestHandler.myRequests), 2)
  975. #A test case that verifies that gzip encoding works in both directions
  976. #(for a request and the response)
  977. @unittest.skipIf(gzip is None, 'requires gzip')
  978. class GzipServerTestCase(BaseServerTestCase):
  979. #a request handler that supports keep-alive and logs requests into a
  980. #class variable
  981. class RequestHandler(xmlrpc.server.SimpleXMLRPCRequestHandler):
  982. parentClass = xmlrpc.server.SimpleXMLRPCRequestHandler
  983. protocol_version = 'HTTP/1.1'
  984. def do_POST(self):
  985. #store content of last request in class
  986. self.__class__.content_length = int(self.headers["content-length"])
  987. return self.parentClass.do_POST(self)
  988. requestHandler = RequestHandler
  989. class Transport(xmlrpclib.Transport):
  990. #custom transport, stores the response length for our perusal
  991. fake_gzip = False
  992. def parse_response(self, response):
  993. self.response_length=int(response.getheader("content-length", 0))
  994. return xmlrpclib.Transport.parse_response(self, response)
  995. def send_content(self, connection, body):
  996. if self.fake_gzip:
  997. #add a lone gzip header to induce decode error remotely
  998. connection.putheader("Content-Encoding", "gzip")
  999. return xmlrpclib.Transport.send_content(self, connection, body)
  1000. def setUp(self):
  1001. BaseServerTestCase.setUp(self)
  1002. def test_gzip_request(self):
  1003. t = self.Transport()
  1004. t.encode_threshold = None
  1005. p = xmlrpclib.ServerProxy(URL, transport=t)
  1006. self.assertEqual(p.pow(6,8), 6**8)
  1007. a = self.RequestHandler.content_length
  1008. t.encode_threshold = 0 #turn on request encoding
  1009. self.assertEqual(p.pow(6,8), 6**8)
  1010. b = self.RequestHandler.content_length
  1011. self.assertTrue(a>b)
  1012. p("close")()
  1013. def test_bad_gzip_request(self):
  1014. t = self.Transport()
  1015. t.encode_threshold = None
  1016. t.fake_gzip = True
  1017. p = xmlrpclib.ServerProxy(URL, transport=t)
  1018. cm = self.assertRaisesRegex(xmlrpclib.ProtocolError,
  1019. re.compile(r"\b400\b"))
  1020. with cm:
  1021. p.pow(6, 8)
  1022. p("close")()
  1023. def test_gzip_response(self):
  1024. t = self.Transport()
  1025. p = xmlrpclib.ServerProxy(URL, transport=t)
  1026. old = self.requestHandler.encode_threshold
  1027. self.requestHandler.encode_threshold = None #no encoding
  1028. self.assertEqual(p.pow(6,8), 6**8)
  1029. a = t.response_length
  1030. self.requestHandler.encode_threshold = 0 #always encode
  1031. self.assertEqual(p.pow(6,8), 6**8)
  1032. p("close")()
  1033. b = t.response_length
  1034. self.requestHandler.encode_threshold = old
  1035. self.assertTrue(a>b)
  1036. @unittest.skipIf(gzip is None, 'requires gzip')
  1037. class GzipUtilTestCase(unittest.TestCase):
  1038. def test_gzip_decode_limit(self):
  1039. max_gzip_decode = 20 * 1024 * 1024
  1040. data = b'\0' * max_gzip_decode
  1041. encoded = xmlrpclib.gzip_encode(data)
  1042. decoded = xmlrpclib.gzip_decode(encoded)
  1043. self.assertEqual(len(decoded), max_gzip_decode)
  1044. data = b'\0' * (max_gzip_decode + 1)
  1045. encoded = xmlrpclib.gzip_encode(data)
  1046. with self.assertRaisesRegex(ValueError,
  1047. "max gzipped payload length exceeded"):
  1048. xmlrpclib.gzip_decode(encoded)
  1049. xmlrpclib.gzip_decode(encoded, max_decode=-1)
  1050. class HeadersServerTestCase(BaseServerTestCase):
  1051. class RequestHandler(xmlrpc.server.SimpleXMLRPCRequestHandler):
  1052. test_headers = None
  1053. def do_POST(self):
  1054. self.__class__.test_headers = self.headers
  1055. return super().do_POST()
  1056. requestHandler = RequestHandler
  1057. standard_headers = [
  1058. 'Host', 'Accept-Encoding', 'Content-Type', 'User-Agent',
  1059. 'Content-Length']
  1060. def setUp(self):
  1061. self.RequestHandler.test_headers = None
  1062. return super().setUp()
  1063. def assertContainsAdditionalHeaders(self, headers, additional):
  1064. expected_keys = sorted(self.standard_headers + list(additional.keys()))
  1065. self.assertListEqual(sorted(headers.keys()), expected_keys)
  1066. for key, value in additional.items():
  1067. self.assertEqual(headers.get(key), value)
  1068. def test_header(self):
  1069. p = xmlrpclib.ServerProxy(URL, headers=[('X-Test', 'foo')])
  1070. self.assertEqual(p.pow(6, 8), 6**8)
  1071. headers = self.RequestHandler.test_headers
  1072. self.assertContainsAdditionalHeaders(headers, {'X-Test': 'foo'})
  1073. def test_header_many(self):
  1074. p = xmlrpclib.ServerProxy(
  1075. URL, headers=[('X-Test', 'foo'), ('X-Test-Second', 'bar')])
  1076. self.assertEqual(p.pow(6, 8), 6**8)
  1077. headers = self.RequestHandler.test_headers
  1078. self.assertContainsAdditionalHeaders(
  1079. headers, {'X-Test': 'foo', 'X-Test-Second': 'bar'})
  1080. def test_header_empty(self):
  1081. p = xmlrpclib.ServerProxy(URL, headers=[])
  1082. self.assertEqual(p.pow(6, 8), 6**8)
  1083. headers = self.RequestHandler.test_headers
  1084. self.assertContainsAdditionalHeaders(headers, {})
  1085. def test_header_tuple(self):
  1086. p = xmlrpclib.ServerProxy(URL, headers=(('X-Test', 'foo'),))
  1087. self.assertEqual(p.pow(6, 8), 6**8)
  1088. headers = self.RequestHandler.test_headers
  1089. self.assertContainsAdditionalHeaders(headers, {'X-Test': 'foo'})
  1090. def test_header_items(self):
  1091. p = xmlrpclib.ServerProxy(URL, headers={'X-Test': 'foo'}.items())
  1092. self.assertEqual(p.pow(6, 8), 6**8)
  1093. headers = self.RequestHandler.test_headers
  1094. self.assertContainsAdditionalHeaders(headers, {'X-Test': 'foo'})
  1095. #Test special attributes of the ServerProxy object
  1096. class ServerProxyTestCase(unittest.TestCase):
  1097. def setUp(self):
  1098. unittest.TestCase.setUp(self)
  1099. # Actual value of the URL doesn't matter if it is a string in
  1100. # the correct format.
  1101. self.url = 'http://fake.localhost'
  1102. def test_close(self):
  1103. p = xmlrpclib.ServerProxy(self.url)
  1104. self.assertEqual(p('close')(), None)
  1105. def test_transport(self):
  1106. t = xmlrpclib.Transport()
  1107. p = xmlrpclib.ServerProxy(self.url, transport=t)
  1108. self.assertEqual(p('transport'), t)
  1109. # This is a contrived way to make a failure occur on the server side
  1110. # in order to test the _send_traceback_header flag on the server
  1111. class FailingMessageClass(http.client.HTTPMessage):
  1112. def get(self, key, failobj=None):
  1113. key = key.lower()
  1114. if key == 'content-length':
  1115. return 'I am broken'
  1116. return super().get(key, failobj)
  1117. class FailingServerTestCase(unittest.TestCase):
  1118. def setUp(self):
  1119. self.evt = threading.Event()
  1120. # start server thread to handle requests
  1121. serv_args = (self.evt, 1)
  1122. thread = threading.Thread(target=http_server, args=serv_args)
  1123. thread.start()
  1124. self.addCleanup(thread.join)
  1125. # wait for the server to be ready
  1126. self.evt.wait()
  1127. self.evt.clear()
  1128. def tearDown(self):
  1129. # wait on the server thread to terminate
  1130. self.evt.wait()
  1131. # reset flag
  1132. xmlrpc.server.SimpleXMLRPCServer._send_traceback_header = False
  1133. # reset message class
  1134. default_class = http.client.HTTPMessage
  1135. xmlrpc.server.SimpleXMLRPCRequestHandler.MessageClass = default_class
  1136. def test_basic(self):
  1137. # check that flag is false by default
  1138. flagval = xmlrpc.server.SimpleXMLRPCServer._send_traceback_header
  1139. self.assertEqual(flagval, False)
  1140. # enable traceback reporting
  1141. xmlrpc.server.SimpleXMLRPCServer._send_traceback_header = True
  1142. # test a call that shouldn't fail just as a smoke test
  1143. try:
  1144. p = xmlrpclib.ServerProxy(URL)
  1145. self.assertEqual(p.pow(6,8), 6**8)
  1146. except (xmlrpclib.ProtocolError, OSError) as e:
  1147. # ignore failures due to non-blocking socket 'unavailable' errors
  1148. if not is_unavailable_exception(e):
  1149. # protocol error; provide additional information in test output
  1150. self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
  1151. def test_fail_no_info(self):
  1152. # use the broken message class
  1153. xmlrpc.server.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
  1154. try:
  1155. p = xmlrpclib.ServerProxy(URL)
  1156. p.pow(6,8)
  1157. except (xmlrpclib.ProtocolError, OSError) as e:
  1158. # ignore failures due to non-blocking socket 'unavailable' errors
  1159. if not is_unavailable_exception(e) and hasattr(e, "headers"):
  1160. # The two server-side error headers shouldn't be sent back in this case
  1161. self.assertTrue(e.headers.get("X-exception") is None)
  1162. self.assertTrue(e.headers.get("X-traceback") is None)
  1163. else:
  1164. self.fail('ProtocolError not raised')
  1165. def test_fail_with_info(self):
  1166. # use the broken message class
  1167. xmlrpc.server.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
  1168. # Check that errors in the server send back exception/traceback
  1169. # info when flag is set
  1170. xmlrpc.server.SimpleXMLRPCServer._send_traceback_header = True
  1171. try:
  1172. p = xmlrpclib.ServerProxy(URL)
  1173. p.pow(6,8)
  1174. except (xmlrpclib.ProtocolError, OSError) as e:
  1175. # ignore failures due to non-blocking socket 'unavailable' errors
  1176. if not is_unavailable_exception(e) and hasattr(e, "headers"):
  1177. # We should get error info in the response
  1178. expected_err = "invalid literal for int() with base 10: 'I am broken'"
  1179. self.assertEqual(e.headers.get("X-exception"), expected_err)
  1180. self.assertTrue(e.headers.get("X-traceback") is not None)
  1181. else:
  1182. self.fail('ProtocolError not raised')
  1183. @contextlib.contextmanager
  1184. def captured_stdout(encoding='utf-8'):
  1185. """A variation on support.captured_stdout() which gives a text stream
  1186. having a `buffer` attribute.
  1187. """
  1188. orig_stdout = sys.stdout
  1189. sys.stdout = io.TextIOWrapper(io.BytesIO(), encoding=encoding)
  1190. try:
  1191. yield sys.stdout
  1192. finally:
  1193. sys.stdout = orig_stdout
  1194. class CGIHandlerTestCase(unittest.TestCase):
  1195. def setUp(self):
  1196. self.cgi = xmlrpc.server.CGIXMLRPCRequestHandler()
  1197. def tearDown(self):
  1198. self.cgi = None
  1199. def test_cgi_get(self):
  1200. with os_helper.EnvironmentVarGuard() as env:
  1201. env['REQUEST_METHOD'] = 'GET'
  1202. # if the method is GET and no request_text is given, it runs handle_get
  1203. # get sysout output
  1204. with captured_stdout(encoding=self.cgi.encoding) as data_out:
  1205. self.cgi.handle_request()
  1206. # parse Status header
  1207. data_out.seek(0)
  1208. handle = data_out.read()
  1209. status = handle.split()[1]
  1210. message = ' '.join(handle.split()[2:4])
  1211. self.assertEqual(status, '400')
  1212. self.assertEqual(message, 'Bad Request')
  1213. def test_cgi_xmlrpc_response(self):
  1214. data = """<?xml version='1.0'?>
  1215. <methodCall>
  1216. <methodName>test_method</methodName>
  1217. <params>
  1218. <param>
  1219. <value><string>foo</string></value>
  1220. </param>
  1221. <param>
  1222. <value><string>bar</string></value>
  1223. </param>
  1224. </params>
  1225. </methodCall>
  1226. """
  1227. with os_helper.EnvironmentVarGuard() as env, \
  1228. captured_stdout(encoding=self.cgi.encoding) as data_out, \
  1229. support.captured_stdin() as data_in:
  1230. data_in.write(data)
  1231. data_in.seek(0)
  1232. env['CONTENT_LENGTH'] = str(len(data))
  1233. self.cgi.handle_request()
  1234. data_out.seek(0)
  1235. # will respond exception, if so, our goal is achieved ;)
  1236. handle = data_out.read()
  1237. # start with 44th char so as not to get http header, we just
  1238. # need only xml
  1239. self.assertRaises(xmlrpclib.Fault, xmlrpclib.loads, handle[44:])
  1240. # Also test the content-length returned by handle_request
  1241. # Using the same test method inorder to avoid all the datapassing
  1242. # boilerplate code.
  1243. # Test for bug: http://bugs.python.org/issue5040
  1244. content = handle[handle.find("<?xml"):]
  1245. self.assertEqual(
  1246. int(re.search(r'Content-Length: (\d+)', handle).group(1)),
  1247. len(content))
  1248. class UseBuiltinTypesTestCase(unittest.TestCase):
  1249. def test_use_builtin_types(self):
  1250. # SimpleXMLRPCDispatcher.__init__ accepts use_builtin_types, which
  1251. # makes all dispatch of binary data as bytes instances, and all
  1252. # dispatch of datetime argument as datetime.datetime instances.
  1253. self.log = []
  1254. expected_bytes = b"my dog has fleas"
  1255. expected_date = datetime.datetime(2008, 5, 26, 18, 25, 12)
  1256. marshaled = xmlrpclib.dumps((expected_bytes, expected_date), 'foobar')
  1257. def foobar(*args):
  1258. self.log.extend(args)
  1259. handler = xmlrpc.server.SimpleXMLRPCDispatcher(
  1260. allow_none=True, encoding=None, use_builtin_types=True)
  1261. handler.register_function(foobar)
  1262. handler._marshaled_dispatch(marshaled)
  1263. self.assertEqual(len(self.log), 2)
  1264. mybytes, mydate = self.log
  1265. self.assertEqual(self.log, [expected_bytes, expected_date])
  1266. self.assertIs(type(mydate), datetime.datetime)
  1267. self.assertIs(type(mybytes), bytes)
  1268. def test_cgihandler_has_use_builtin_types_flag(self):
  1269. handler = xmlrpc.server.CGIXMLRPCRequestHandler(use_builtin_types=True)
  1270. self.assertTrue(handler.use_builtin_types)
  1271. def test_xmlrpcserver_has_use_builtin_types_flag(self):
  1272. server = xmlrpc.server.SimpleXMLRPCServer(("localhost", 0),
  1273. use_builtin_types=True)
  1274. server.server_close()
  1275. self.assertTrue(server.use_builtin_types)
  1276. def setUpModule():
  1277. thread_info = threading_helper.threading_setup()
  1278. unittest.addModuleCleanup(threading_helper.threading_cleanup, *thread_info)
  1279. if __name__ == "__main__":
  1280. unittest.main()