blob: 99be297340b06e0c4a34968af1bd90bd661852eb [file] [log] [blame]
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001import base64
Fred Drakeba613c32005-02-10 18:33:30 +00002import datetime
Skip Montanaro3e7bba92001-10-19 16:06:52 +00003import sys
Guido van Rossumb5a755e2007-07-18 18:15:48 +00004import time
Skip Montanaro419abda2001-10-01 17:47:44 +00005import unittest
Georg Brandl38eceaa2008-05-26 11:14:17 +00006import xmlrpc.client as xmlrpclib
7import xmlrpc.server
Georg Brandl24420152008-05-26 16:32:26 +00008import http.client
Christian Heimes255f53b2007-12-08 15:33:56 +00009import socket
10import os
Senthil Kumaranb3af08f2009-04-01 20:20:43 +000011import re
R. David Murray0548ce02009-10-26 08:24:14 +000012import io
13import contextlib
Benjamin Petersonee8712c2008-05-20 21:35:26 +000014from test import support
Skip Montanaro419abda2001-10-01 17:47:44 +000015
Victor Stinner45df8202010-04-28 22:31:17 +000016try:
Brett Cannon603dcf22013-06-12 20:04:19 -040017 import gzip
18except ModuleNotFoundError:
19 gzip = None
20try:
Victor Stinner45df8202010-04-28 22:31:17 +000021 import threading
Brett Cannon603dcf22013-06-12 20:04:19 -040022except ModuleNotFoundError:
Victor Stinner45df8202010-04-28 22:31:17 +000023 threading = None
24
Skip Montanaro419abda2001-10-01 17:47:44 +000025alist = [{'astring': 'foo@bar.baz.spam',
26 'afloat': 7283.43,
Skip Montanaro3e7bba92001-10-19 16:06:52 +000027 'anint': 2**20,
Guido van Rossume2a383d2007-01-15 16:59:06 +000028 'ashortlong': 2,
Skip Montanaro419abda2001-10-01 17:47:44 +000029 'anotherlist': ['.zyx.41'],
Guido van Rossum54a40cb2007-08-27 22:27:41 +000030 'abase64': xmlrpclib.Binary(b"my dog has fleas"),
Florent Xicluna61665192011-11-15 20:53:25 +010031 'b64bytes': b"my dog has fleas",
32 'b64bytearray': bytearray(b"my dog has fleas"),
Guido van Rossume7ba4952007-06-06 23:52:48 +000033 'boolean': False,
Guido van Rossumef87d6e2007-05-02 19:09:54 +000034 'unicode': '\u4000\u6000\u8000',
35 'ukey\u4000': 'regular value',
Fred Drakeba613c32005-02-10 18:33:30 +000036 'datetime1': xmlrpclib.DateTime('20050210T11:41:23'),
37 'datetime2': xmlrpclib.DateTime(
Guido van Rossumcd16bf62007-06-13 18:07:49 +000038 (2005, 2, 10, 11, 41, 23, 0, 1, -1)),
Fred Drakeba613c32005-02-10 18:33:30 +000039 'datetime3': xmlrpclib.DateTime(
Guido van Rossumcd16bf62007-06-13 18:07:49 +000040 datetime.datetime(2005, 2, 10, 11, 41, 23)),
Skip Montanaro419abda2001-10-01 17:47:44 +000041 }]
42
43class XMLRPCTestCase(unittest.TestCase):
44
45 def test_dump_load(self):
Guido van Rossum54a40cb2007-08-27 22:27:41 +000046 dump = xmlrpclib.dumps((alist,))
47 load = xmlrpclib.loads(dump)
Ezio Melottib3aedd42010-11-20 19:04:17 +000048 self.assertEqual(alist, load[0][0])
Skip Montanaro419abda2001-10-01 17:47:44 +000049
Fred Drakeba613c32005-02-10 18:33:30 +000050 def test_dump_bare_datetime(self):
Skip Montanaro174dd222005-05-14 20:54:16 +000051 # This checks that an unwrapped datetime.date object can be handled
52 # by the marshalling code. This can't be done via test_dump_load()
Florent Xicluna61665192011-11-15 20:53:25 +010053 # since with use_builtin_types set to 1 the unmarshaller would create
Skip Montanaro174dd222005-05-14 20:54:16 +000054 # datetime objects for the 'datetime[123]' keys as well
Guido van Rossumcd16bf62007-06-13 18:07:49 +000055 dt = datetime.datetime(2005, 2, 10, 11, 41, 23)
Florent Xicluna61665192011-11-15 20:53:25 +010056 self.assertEqual(dt, xmlrpclib.DateTime('20050210T11:41:23'))
Fred Drakeba613c32005-02-10 18:33:30 +000057 s = xmlrpclib.dumps((dt,))
Fred Drakeba613c32005-02-10 18:33:30 +000058
Florent Xicluna61665192011-11-15 20:53:25 +010059 result, m = xmlrpclib.loads(s, use_builtin_types=True)
60 (newdt,) = result
61 self.assertEqual(newdt, dt)
62 self.assertIs(type(newdt), datetime.datetime)
63 self.assertIsNone(m)
64
65 result, m = xmlrpclib.loads(s, use_builtin_types=False)
66 (newdt,) = result
67 self.assertEqual(newdt, dt)
68 self.assertIs(type(newdt), xmlrpclib.DateTime)
69 self.assertIsNone(m)
70
71 result, m = xmlrpclib.loads(s, use_datetime=True)
72 (newdt,) = result
73 self.assertEqual(newdt, dt)
74 self.assertIs(type(newdt), datetime.datetime)
75 self.assertIsNone(m)
76
77 result, m = xmlrpclib.loads(s, use_datetime=False)
78 (newdt,) = result
79 self.assertEqual(newdt, dt)
80 self.assertIs(type(newdt), xmlrpclib.DateTime)
81 self.assertIsNone(m)
82
Skip Montanaro174dd222005-05-14 20:54:16 +000083
Christian Heimesdae2a892008-04-19 00:55:37 +000084 def test_datetime_before_1900(self):
Christian Heimes81ee3ef2008-05-04 22:42:01 +000085 # same as before but with a date before 1900
Christian Heimesdae2a892008-04-19 00:55:37 +000086 dt = datetime.datetime(1, 2, 10, 11, 41, 23)
Florent Xicluna61665192011-11-15 20:53:25 +010087 self.assertEqual(dt, xmlrpclib.DateTime('00010210T11:41:23'))
Christian Heimesdae2a892008-04-19 00:55:37 +000088 s = xmlrpclib.dumps((dt,))
Christian Heimesdae2a892008-04-19 00:55:37 +000089
Florent Xicluna61665192011-11-15 20:53:25 +010090 result, m = xmlrpclib.loads(s, use_builtin_types=True)
91 (newdt,) = result
92 self.assertEqual(newdt, dt)
93 self.assertIs(type(newdt), datetime.datetime)
94 self.assertIsNone(m)
95
96 result, m = xmlrpclib.loads(s, use_builtin_types=False)
97 (newdt,) = result
98 self.assertEqual(newdt, dt)
99 self.assertIs(type(newdt), xmlrpclib.DateTime)
100 self.assertIsNone(m)
Christian Heimesdae2a892008-04-19 00:55:37 +0000101
Andrew M. Kuchlingbdb39012005-12-04 19:11:17 +0000102 def test_bug_1164912 (self):
103 d = xmlrpclib.DateTime()
Tim Peters536cf992005-12-25 23:18:31 +0000104 ((new_d,), dummy) = xmlrpclib.loads(xmlrpclib.dumps((d,),
Andrew M. Kuchlingbdb39012005-12-04 19:11:17 +0000105 methodresponse=True))
Ezio Melottie9615932010-01-24 19:26:24 +0000106 self.assertIsInstance(new_d.value, str)
Andrew M. Kuchlingbdb39012005-12-04 19:11:17 +0000107
108 # Check that the output of dumps() is still an 8-bit string
109 s = xmlrpclib.dumps((new_d,), methodresponse=True)
Ezio Melottie9615932010-01-24 19:26:24 +0000110 self.assertIsInstance(s, str)
Andrew M. Kuchlingbdb39012005-12-04 19:11:17 +0000111
Thomas Wouters89f507f2006-12-13 04:49:30 +0000112 def test_newstyle_class(self):
113 class T(object):
114 pass
115 t = T()
116 t.x = 100
117 t.y = "Hello"
118 ((t2,), dummy) = xmlrpclib.loads(xmlrpclib.dumps((t,)))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000119 self.assertEqual(t2, t.__dict__)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000120
Skip Montanaro3e7bba92001-10-19 16:06:52 +0000121 def test_dump_big_long(self):
Guido van Rossume2a383d2007-01-15 16:59:06 +0000122 self.assertRaises(OverflowError, xmlrpclib.dumps, (2**99,))
Skip Montanaro3e7bba92001-10-19 16:06:52 +0000123
124 def test_dump_bad_dict(self):
125 self.assertRaises(TypeError, xmlrpclib.dumps, ({(1,2,3): 1},))
126
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000127 def test_dump_recursive_seq(self):
128 l = [1,2,3]
129 t = [3,4,5,l]
130 l.append(t)
131 self.assertRaises(TypeError, xmlrpclib.dumps, (l,))
132
133 def test_dump_recursive_dict(self):
134 d = {'1':1, '2':1}
135 t = {'3':3, 'd':d}
136 d['t'] = t
137 self.assertRaises(TypeError, xmlrpclib.dumps, (d,))
138
Skip Montanaro3e7bba92001-10-19 16:06:52 +0000139 def test_dump_big_int(self):
Christian Heimesa37d4c62007-12-04 23:02:19 +0000140 if sys.maxsize > 2**31-1:
Skip Montanaro3e7bba92001-10-19 16:06:52 +0000141 self.assertRaises(OverflowError, xmlrpclib.dumps,
Guido van Rossume2a383d2007-01-15 16:59:06 +0000142 (int(2**34),))
Skip Montanaro3e7bba92001-10-19 16:06:52 +0000143
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000144 xmlrpclib.dumps((xmlrpclib.MAXINT, xmlrpclib.MININT))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000145 self.assertRaises(OverflowError, xmlrpclib.dumps,
146 (xmlrpclib.MAXINT+1,))
147 self.assertRaises(OverflowError, xmlrpclib.dumps,
148 (xmlrpclib.MININT-1,))
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000149
150 def dummy_write(s):
151 pass
152
153 m = xmlrpclib.Marshaller()
154 m.dump_int(xmlrpclib.MAXINT, dummy_write)
155 m.dump_int(xmlrpclib.MININT, dummy_write)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000156 self.assertRaises(OverflowError, m.dump_int,
157 xmlrpclib.MAXINT+1, dummy_write)
158 self.assertRaises(OverflowError, m.dump_int,
159 xmlrpclib.MININT-1, dummy_write)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000160
Florent Xicluna1917ea92012-07-07 17:03:25 +0200161 def test_dump_double(self):
162 xmlrpclib.dumps((float(2 ** 34),))
163 xmlrpclib.dumps((float(xmlrpclib.MAXINT),
164 float(xmlrpclib.MININT)))
165 xmlrpclib.dumps((float(xmlrpclib.MAXINT + 42),
166 float(xmlrpclib.MININT - 42)))
167
168 def dummy_write(s):
169 pass
170
171 m = xmlrpclib.Marshaller()
172 m.dump_double(xmlrpclib.MAXINT, dummy_write)
173 m.dump_double(xmlrpclib.MININT, dummy_write)
174 m.dump_double(xmlrpclib.MAXINT + 42, dummy_write)
175 m.dump_double(xmlrpclib.MININT - 42, dummy_write)
176
Andrew M. Kuchling0b852032003-04-25 00:27:24 +0000177 def test_dump_none(self):
178 value = alist + [None]
179 arg1 = (alist + [None],)
180 strg = xmlrpclib.dumps(arg1, allow_none=True)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000181 self.assertEqual(value,
Andrew M. Kuchling0b852032003-04-25 00:27:24 +0000182 xmlrpclib.loads(strg)[0][0])
183 self.assertRaises(TypeError, xmlrpclib.dumps, (arg1,))
184
Florent Xicluna61665192011-11-15 20:53:25 +0100185 def test_dump_bytes(self):
186 sample = b"my dog has fleas"
187 self.assertEqual(sample, xmlrpclib.Binary(sample))
188 for type_ in bytes, bytearray, xmlrpclib.Binary:
189 value = type_(sample)
190 s = xmlrpclib.dumps((value,))
191
192 result, m = xmlrpclib.loads(s, use_builtin_types=True)
193 (newvalue,) = result
194 self.assertEqual(newvalue, sample)
195 self.assertIs(type(newvalue), bytes)
196 self.assertIsNone(m)
197
198 result, m = xmlrpclib.loads(s, use_builtin_types=False)
199 (newvalue,) = result
200 self.assertEqual(newvalue, sample)
201 self.assertIs(type(newvalue), xmlrpclib.Binary)
202 self.assertIsNone(m)
203
Georg Brandlc8dcfb62009-02-13 10:50:01 +0000204 def test_get_host_info(self):
205 # see bug #3613, this raised a TypeError
206 transp = xmlrpc.client.Transport()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000207 self.assertEqual(transp.get_host_info("user@host.tld"),
Georg Brandlc8dcfb62009-02-13 10:50:01 +0000208 ('host.tld',
209 [('Authorization', 'Basic dXNlcg==')], {}))
210
Senthil Kumaran8ce1f1f2010-11-18 15:00:53 +0000211 def test_ssl_presence(self):
Senthil Kumaran6a0b5c42010-11-18 17:08:48 +0000212 try:
213 import ssl
Antoine Pitrou98b644f2010-11-19 20:07:52 +0000214 except ImportError:
215 has_ssl = False
Senthil Kumaran8ce1f1f2010-11-18 15:00:53 +0000216 else:
Senthil Kumaran6a0b5c42010-11-18 17:08:48 +0000217 has_ssl = True
Senthil Kumaran8ce1f1f2010-11-18 15:00:53 +0000218 try:
219 xmlrpc.client.ServerProxy('https://localhost:9999').bad_function()
Senthil Kumaran6a0b5c42010-11-18 17:08:48 +0000220 except NotImplementedError:
221 self.assertFalse(has_ssl, "xmlrpc client's error with SSL support")
Andrew Svetlov0832af62012-12-18 23:10:48 +0200222 except OSError:
Senthil Kumaran6a0b5c42010-11-18 17:08:48 +0000223 self.assertTrue(has_ssl)
Ezio Melottie9615932010-01-24 19:26:24 +0000224
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000225class HelperTestCase(unittest.TestCase):
226 def test_escape(self):
227 self.assertEqual(xmlrpclib.escape("a&b"), "a&b")
228 self.assertEqual(xmlrpclib.escape("a<b"), "a&lt;b")
229 self.assertEqual(xmlrpclib.escape("a>b"), "a&gt;b")
230
231class FaultTestCase(unittest.TestCase):
232 def test_repr(self):
233 f = xmlrpclib.Fault(42, 'Test Fault')
234 self.assertEqual(repr(f), "<Fault 42: 'Test Fault'>")
235 self.assertEqual(repr(f), str(f))
236
237 def test_dump_fault(self):
238 f = xmlrpclib.Fault(42, 'Test Fault')
239 s = xmlrpclib.dumps((f,))
240 (newf,), m = xmlrpclib.loads(s)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000241 self.assertEqual(newf, {'faultCode': 42, 'faultString': 'Test Fault'})
242 self.assertEqual(m, None)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000243
244 s = xmlrpclib.Marshaller().dumps(f)
245 self.assertRaises(xmlrpclib.Fault, xmlrpclib.loads, s)
246
Christian Heimeseda9e2b2007-12-08 22:32:47 +0000247 def test_dotted_attribute(self):
Florent Xiclunac4fec932011-10-30 20:19:32 +0100248 # this will raise AttributeError because code don't want us to use
Christian Heimeseda9e2b2007-12-08 22:32:47 +0000249 # private methods
250 self.assertRaises(AttributeError,
Georg Brandl38eceaa2008-05-26 11:14:17 +0000251 xmlrpc.server.resolve_dotted_attribute, str, '__add')
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000252 self.assertTrue(xmlrpc.server.resolve_dotted_attribute(str, 'title'))
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000253
254class DateTimeTestCase(unittest.TestCase):
255 def test_default(self):
256 t = xmlrpclib.DateTime()
257
258 def test_time(self):
259 d = 1181399930.036952
260 t = xmlrpclib.DateTime(d)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000261 self.assertEqual(str(t),
262 time.strftime("%Y%m%dT%H:%M:%S", time.localtime(d)))
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000263
264 def test_time_tuple(self):
265 d = (2007,6,9,10,38,50,5,160,0)
266 t = xmlrpclib.DateTime(d)
267 self.assertEqual(str(t), '20070609T10:38:50')
268
269 def test_time_struct(self):
270 d = time.localtime(1181399930.036952)
271 t = xmlrpclib.DateTime(d)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000272 self.assertEqual(str(t), time.strftime("%Y%m%dT%H:%M:%S", d))
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000273
274 def test_datetime_datetime(self):
275 d = datetime.datetime(2007,1,2,3,4,5)
276 t = xmlrpclib.DateTime(d)
277 self.assertEqual(str(t), '20070102T03:04:05')
278
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000279 def test_repr(self):
280 d = datetime.datetime(2007,1,2,3,4,5)
281 t = xmlrpclib.DateTime(d)
282 val ="<DateTime '20070102T03:04:05' at %x>" % id(t)
283 self.assertEqual(repr(t), val)
284
285 def test_decode(self):
286 d = ' 20070908T07:11:13 '
287 t1 = xmlrpclib.DateTime()
288 t1.decode(d)
289 tref = xmlrpclib.DateTime(datetime.datetime(2007,9,8,7,11,13))
290 self.assertEqual(t1, tref)
291
292 t2 = xmlrpclib._datetime(d)
293 self.assertEqual(t1, tref)
294
Florent Xicluna3fa29f72011-10-30 20:18:50 +0100295 def test_comparison(self):
296 now = datetime.datetime.now()
297 dtime = xmlrpclib.DateTime(now.timetuple())
298
299 # datetime vs. DateTime
300 self.assertTrue(dtime == now)
301 self.assertTrue(now == dtime)
302 then = now + datetime.timedelta(seconds=4)
303 self.assertTrue(then >= dtime)
304 self.assertTrue(dtime < then)
305
306 # str vs. DateTime
307 dstr = now.strftime("%Y%m%dT%H:%M:%S")
308 self.assertTrue(dtime == dstr)
309 self.assertTrue(dstr == dtime)
310 dtime_then = xmlrpclib.DateTime(then.timetuple())
311 self.assertTrue(dtime_then >= dstr)
312 self.assertTrue(dstr < dtime_then)
313
314 # some other types
315 dbytes = dstr.encode('ascii')
316 dtuple = now.timetuple()
317 with self.assertRaises(TypeError):
318 dtime == 1970
319 with self.assertRaises(TypeError):
320 dtime != dbytes
321 with self.assertRaises(TypeError):
322 dtime == bytearray(dbytes)
323 with self.assertRaises(TypeError):
324 dtime != dtuple
325 with self.assertRaises(TypeError):
326 dtime < float(1970)
327 with self.assertRaises(TypeError):
328 dtime > dbytes
329 with self.assertRaises(TypeError):
330 dtime <= bytearray(dbytes)
331 with self.assertRaises(TypeError):
332 dtime >= dtuple
333
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000334class BinaryTestCase(unittest.TestCase):
Guido van Rossum54a40cb2007-08-27 22:27:41 +0000335
336 # XXX What should str(Binary(b"\xff")) return? I'm chosing "\xff"
337 # for now (i.e. interpreting the binary data as Latin-1-encoded
338 # text). But this feels very unsatisfactory. Perhaps we should
339 # only define repr(), and return r"Binary(b'\xff')" instead?
340
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000341 def test_default(self):
342 t = xmlrpclib.Binary()
343 self.assertEqual(str(t), '')
344
345 def test_string(self):
Guido van Rossum54a40cb2007-08-27 22:27:41 +0000346 d = b'\x01\x02\x03abc123\xff\xfe'
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000347 t = xmlrpclib.Binary(d)
Guido van Rossum54a40cb2007-08-27 22:27:41 +0000348 self.assertEqual(str(t), str(d, "latin-1"))
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000349
350 def test_decode(self):
Guido van Rossum54a40cb2007-08-27 22:27:41 +0000351 d = b'\x01\x02\x03abc123\xff\xfe'
Georg Brandlb54d8012009-06-04 09:11:51 +0000352 de = base64.encodebytes(d)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000353 t1 = xmlrpclib.Binary()
354 t1.decode(de)
Guido van Rossum54a40cb2007-08-27 22:27:41 +0000355 self.assertEqual(str(t1), str(d, "latin-1"))
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000356
357 t2 = xmlrpclib._binary(de)
Guido van Rossum54a40cb2007-08-27 22:27:41 +0000358 self.assertEqual(str(t2), str(d, "latin-1"))
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000359
360
Benjamin Petersone1cdfd72009-01-18 21:02:37 +0000361ADDR = PORT = URL = None
Skip Montanaro419abda2001-10-01 17:47:44 +0000362
Christian Heimesaf98da12008-01-27 15:18:18 +0000363# The evt is set twice. First when the server is ready to serve.
364# Second when the server has been shutdown. The user must clear
365# the event after it has been set the first time to catch the second set.
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000366def http_server(evt, numrequests, requestHandler=None):
Guido van Rossumaf554a02007-08-16 23:48:43 +0000367 class TestInstanceClass:
368 def div(self, x, y):
Guido van Rossumaf554a02007-08-16 23:48:43 +0000369 return x // y
370
Christian Heimes255f53b2007-12-08 15:33:56 +0000371 def _methodHelp(self, name):
372 if name == 'div':
373 return 'This is the div function'
374
375 def my_function():
376 '''This is my function'''
377 return True
378
Georg Brandl38eceaa2008-05-26 11:14:17 +0000379 class MyXMLRPCServer(xmlrpc.server.SimpleXMLRPCServer):
Christian Heimesbbe741d2008-03-28 10:53:29 +0000380 def get_request(self):
381 # Ensure the socket is always non-blocking. On Linux, socket
382 # attributes are not inherited like they are on *BSD and Windows.
383 s, port = self.socket.accept()
384 s.setblocking(True)
385 return s, port
386
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000387 if not requestHandler:
388 requestHandler = xmlrpc.server.SimpleXMLRPCRequestHandler
389 serv = MyXMLRPCServer(("localhost", 0), requestHandler,
Benjamin Petersone1cdfd72009-01-18 21:02:37 +0000390 logRequests=False, bind_and_activate=False)
Guido van Rossumaf554a02007-08-16 23:48:43 +0000391 try:
Guido van Rossumaf554a02007-08-16 23:48:43 +0000392 serv.server_bind()
Benjamin Petersone1cdfd72009-01-18 21:02:37 +0000393 global ADDR, PORT, URL
394 ADDR, PORT = serv.socket.getsockname()
395 #connect to IP address directly. This avoids socket.create_connection()
Ezio Melottie130a522011-10-19 10:58:56 +0300396 #trying to connect to "localhost" using all address families, which
Benjamin Petersone1cdfd72009-01-18 21:02:37 +0000397 #causes slowdown e.g. on vista which supports AF_INET6. The server listens
398 #on AF_INET only.
399 URL = "http://%s:%d"%(ADDR, PORT)
Guido van Rossumaf554a02007-08-16 23:48:43 +0000400 serv.server_activate()
401 serv.register_introspection_functions()
402 serv.register_multicall_functions()
403 serv.register_function(pow)
404 serv.register_function(lambda x,y: x+y, 'add')
Christian Heimes255f53b2007-12-08 15:33:56 +0000405 serv.register_function(my_function)
Guido van Rossumaf554a02007-08-16 23:48:43 +0000406 serv.register_instance(TestInstanceClass())
Christian Heimesaf98da12008-01-27 15:18:18 +0000407 evt.set()
Guido van Rossumaf554a02007-08-16 23:48:43 +0000408
409 # handle up to 'numrequests' requests
410 while numrequests > 0:
411 serv.handle_request()
412 numrequests -= 1
413
414 except socket.timeout:
415 pass
416 finally:
417 serv.socket.close()
418 PORT = None
419 evt.set()
420
Kristján Valur Jónsson1f2a1ae2009-12-16 10:50:44 +0000421def http_multi_server(evt, numrequests, requestHandler=None):
422 class TestInstanceClass:
423 def div(self, x, y):
424 return x // y
425
426 def _methodHelp(self, name):
427 if name == 'div':
428 return 'This is the div function'
429
430 def my_function():
431 '''This is my function'''
432 return True
433
434 class MyXMLRPCServer(xmlrpc.server.MultiPathXMLRPCServer):
435 def get_request(self):
436 # Ensure the socket is always non-blocking. On Linux, socket
437 # attributes are not inherited like they are on *BSD and Windows.
438 s, port = self.socket.accept()
439 s.setblocking(True)
440 return s, port
441
442 if not requestHandler:
443 requestHandler = xmlrpc.server.SimpleXMLRPCRequestHandler
444 class MyRequestHandler(requestHandler):
445 rpc_paths = []
446
Florent Xicluna3fa29f72011-10-30 20:18:50 +0100447 class BrokenDispatcher:
448 def _marshaled_dispatch(self, data, dispatch_method=None, path=None):
449 raise RuntimeError("broken dispatcher")
450
Kristján Valur Jónsson1f2a1ae2009-12-16 10:50:44 +0000451 serv = MyXMLRPCServer(("localhost", 0), MyRequestHandler,
452 logRequests=False, bind_and_activate=False)
453 serv.socket.settimeout(3)
454 serv.server_bind()
455 try:
456 global ADDR, PORT, URL
457 ADDR, PORT = serv.socket.getsockname()
458 #connect to IP address directly. This avoids socket.create_connection()
Ezio Melottie130a522011-10-19 10:58:56 +0300459 #trying to connect to "localhost" using all address families, which
Kristján Valur Jónsson1f2a1ae2009-12-16 10:50:44 +0000460 #causes slowdown e.g. on vista which supports AF_INET6. The server listens
461 #on AF_INET only.
462 URL = "http://%s:%d"%(ADDR, PORT)
463 serv.server_activate()
464 paths = ["/foo", "/foo/bar"]
465 for path in paths:
466 d = serv.add_dispatcher(path, xmlrpc.server.SimpleXMLRPCDispatcher())
467 d.register_introspection_functions()
468 d.register_multicall_functions()
469 serv.get_dispatcher(paths[0]).register_function(pow)
470 serv.get_dispatcher(paths[1]).register_function(lambda x,y: x+y, 'add')
Florent Xicluna3fa29f72011-10-30 20:18:50 +0100471 serv.add_dispatcher("/is/broken", BrokenDispatcher())
Kristján Valur Jónsson1f2a1ae2009-12-16 10:50:44 +0000472 evt.set()
473
474 # handle up to 'numrequests' requests
475 while numrequests > 0:
476 serv.handle_request()
477 numrequests -= 1
478
479 except socket.timeout:
480 pass
481 finally:
482 serv.socket.close()
483 PORT = None
484 evt.set()
485
Christian Heimesaf98da12008-01-27 15:18:18 +0000486# This function prevents errors like:
487# <ProtocolError for localhost:57527/RPC2: 500 Internal Server Error>
488def is_unavailable_exception(e):
489 '''Returns True if the given ProtocolError is the product of a server-side
490 exception caused by the 'temporarily unavailable' response sometimes
491 given by operations on non-blocking sockets.'''
492
493 # sometimes we get a -1 error code and/or empty headers
Christian Heimes26855632008-01-27 23:50:43 +0000494 try:
495 if e.errcode == -1 or e.headers is None:
496 return True
497 exc_mess = e.headers.get('X-exception')
498 except AttributeError:
Andrew Svetlov0832af62012-12-18 23:10:48 +0200499 # Ignore OSErrors here.
Christian Heimes26855632008-01-27 23:50:43 +0000500 exc_mess = str(e)
Guido van Rossumaf554a02007-08-16 23:48:43 +0000501
Christian Heimes26855632008-01-27 23:50:43 +0000502 if exc_mess and 'temporarily unavailable' in exc_mess.lower():
503 return True
Thomas Woutersed03b412007-08-28 21:37:11 +0000504
R. David Murray378c0cf2010-02-24 01:46:21 +0000505def make_request_and_skipIf(condition, reason):
506 # If we skip the test, we have to make a request because the
507 # the server created in setUp blocks expecting one to come in.
508 if not condition:
509 return lambda func: func
510 def decorator(func):
511 def make_request_and_skip(self):
512 try:
513 xmlrpclib.ServerProxy(URL).my_function()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200514 except (xmlrpclib.ProtocolError, OSError) as e:
R. David Murray378c0cf2010-02-24 01:46:21 +0000515 if not is_unavailable_exception(e):
516 raise
517 raise unittest.SkipTest(reason)
518 return make_request_and_skip
519 return decorator
520
Victor Stinner45df8202010-04-28 22:31:17 +0000521@unittest.skipUnless(threading, 'Threading required for this test.')
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000522class BaseServerTestCase(unittest.TestCase):
523 requestHandler = None
Kristján Valur Jónssonf6087ca2009-07-12 22:45:18 +0000524 request_count = 1
Kristján Valur Jónsson1f2a1ae2009-12-16 10:50:44 +0000525 threadFunc = staticmethod(http_server)
Victor Stinner45df8202010-04-28 22:31:17 +0000526
Guido van Rossumaf554a02007-08-16 23:48:43 +0000527 def setUp(self):
Guido van Rossum61e21b52007-08-20 19:06:03 +0000528 # enable traceback reporting
Georg Brandl38eceaa2008-05-26 11:14:17 +0000529 xmlrpc.server.SimpleXMLRPCServer._send_traceback_header = True
Guido van Rossum61e21b52007-08-20 19:06:03 +0000530
Guido van Rossumaf554a02007-08-16 23:48:43 +0000531 self.evt = threading.Event()
Guido van Rossum61e21b52007-08-20 19:06:03 +0000532 # start server thread to handle requests
Kristján Valur Jónssonf6087ca2009-07-12 22:45:18 +0000533 serv_args = (self.evt, self.request_count, self.requestHandler)
Kristján Valur Jónsson1f2a1ae2009-12-16 10:50:44 +0000534 threading.Thread(target=self.threadFunc, args=serv_args).start()
Guido van Rossumaf554a02007-08-16 23:48:43 +0000535
Christian Heimesaf98da12008-01-27 15:18:18 +0000536 # wait for the server to be ready
537 self.evt.wait()
538 self.evt.clear()
Guido van Rossumaf554a02007-08-16 23:48:43 +0000539
540 def tearDown(self):
541 # wait on the server thread to terminate
Charles-François Natalicd96b4f2012-02-18 14:53:41 +0100542 self.evt.wait()
Guido van Rossumaf554a02007-08-16 23:48:43 +0000543
Guido van Rossum61e21b52007-08-20 19:06:03 +0000544 # disable traceback reporting
Georg Brandl38eceaa2008-05-26 11:14:17 +0000545 xmlrpc.server.SimpleXMLRPCServer._send_traceback_header = False
Guido van Rossum61e21b52007-08-20 19:06:03 +0000546
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000547class SimpleServerTestCase(BaseServerTestCase):
Guido van Rossumaf554a02007-08-16 23:48:43 +0000548 def test_simple1(self):
Guido van Rossum04110fb2007-08-24 16:32:05 +0000549 try:
Benjamin Petersone1cdfd72009-01-18 21:02:37 +0000550 p = xmlrpclib.ServerProxy(URL)
Guido van Rossum04110fb2007-08-24 16:32:05 +0000551 self.assertEqual(p.pow(6,8), 6**8)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200552 except (xmlrpclib.ProtocolError, OSError) as e:
Christian Heimes412dc9c2008-01-27 18:55:54 +0000553 # ignore failures due to non-blocking socket 'unavailable' errors
554 if not is_unavailable_exception(e):
555 # protocol error; provide additional information in test output
Christian Heimes26855632008-01-27 23:50:43 +0000556 self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
Guido van Rossumaf554a02007-08-16 23:48:43 +0000557
Senthil Kumaranb3af08f2009-04-01 20:20:43 +0000558 def test_nonascii(self):
559 start_string = 'P\N{LATIN SMALL LETTER Y WITH CIRCUMFLEX}t'
560 end_string = 'h\N{LATIN SMALL LETTER O WITH HORN}n'
561 try:
562 p = xmlrpclib.ServerProxy(URL)
563 self.assertEqual(p.add(start_string, end_string),
564 start_string + end_string)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200565 except (xmlrpclib.ProtocolError, OSError) as e:
Senthil Kumaranb3af08f2009-04-01 20:20:43 +0000566 # ignore failures due to non-blocking socket 'unavailable' errors
567 if not is_unavailable_exception(e):
568 # protocol error; provide additional information in test output
569 self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
570
Georg Brandlfceab5a2008-01-19 20:08:23 +0000571 # [ch] The test 404 is causing lots of false alarms.
572 def XXXtest_404(self):
Georg Brandl24420152008-05-26 16:32:26 +0000573 # send POST with http.client, it should return 404 header and
Christian Heimes255f53b2007-12-08 15:33:56 +0000574 # 'Not Found' message.
Benjamin Petersone1cdfd72009-01-18 21:02:37 +0000575 conn = httplib.client.HTTPConnection(ADDR, PORT)
Christian Heimes99d73f22007-12-08 16:13:06 +0000576 conn.request('POST', '/this-is-not-valid')
Christian Heimes255f53b2007-12-08 15:33:56 +0000577 response = conn.getresponse()
578 conn.close()
579
580 self.assertEqual(response.status, 404)
581 self.assertEqual(response.reason, 'Not Found')
582
Guido van Rossumaf554a02007-08-16 23:48:43 +0000583 def test_introspection1(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000584 expected_methods = set(['pow', 'div', 'my_function', 'add',
585 'system.listMethods', 'system.methodHelp',
586 'system.methodSignature', 'system.multicall'])
Guido van Rossum04110fb2007-08-24 16:32:05 +0000587 try:
Benjamin Petersone1cdfd72009-01-18 21:02:37 +0000588 p = xmlrpclib.ServerProxy(URL)
Guido van Rossum04110fb2007-08-24 16:32:05 +0000589 meth = p.system.listMethods()
Guido van Rossum04110fb2007-08-24 16:32:05 +0000590 self.assertEqual(set(meth), expected_methods)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200591 except (xmlrpclib.ProtocolError, OSError) as e:
Christian Heimes412dc9c2008-01-27 18:55:54 +0000592 # ignore failures due to non-blocking socket 'unavailable' errors
593 if not is_unavailable_exception(e):
594 # protocol error; provide additional information in test output
Christian Heimes26855632008-01-27 23:50:43 +0000595 self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
Christian Heimes412dc9c2008-01-27 18:55:54 +0000596
Guido van Rossumaf554a02007-08-16 23:48:43 +0000597
598 def test_introspection2(self):
Guido van Rossum04110fb2007-08-24 16:32:05 +0000599 try:
Christian Heimes255f53b2007-12-08 15:33:56 +0000600 # test _methodHelp()
Benjamin Petersone1cdfd72009-01-18 21:02:37 +0000601 p = xmlrpclib.ServerProxy(URL)
Guido van Rossum04110fb2007-08-24 16:32:05 +0000602 divhelp = p.system.methodHelp('div')
603 self.assertEqual(divhelp, 'This is the div function')
Andrew Svetlov0832af62012-12-18 23:10:48 +0200604 except (xmlrpclib.ProtocolError, OSError) as e:
Christian Heimes412dc9c2008-01-27 18:55:54 +0000605 # ignore failures due to non-blocking socket 'unavailable' errors
606 if not is_unavailable_exception(e):
607 # protocol error; provide additional information in test output
Christian Heimes26855632008-01-27 23:50:43 +0000608 self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
Guido van Rossumaf554a02007-08-16 23:48:43 +0000609
R. David Murray378c0cf2010-02-24 01:46:21 +0000610 @make_request_and_skipIf(sys.flags.optimize >= 2,
611 "Docstrings are omitted with -O2 and above")
Guido van Rossumaf554a02007-08-16 23:48:43 +0000612 def test_introspection3(self):
Christian Heimes255f53b2007-12-08 15:33:56 +0000613 try:
614 # test native doc
Benjamin Petersone1cdfd72009-01-18 21:02:37 +0000615 p = xmlrpclib.ServerProxy(URL)
Christian Heimes255f53b2007-12-08 15:33:56 +0000616 myfunction = p.system.methodHelp('my_function')
617 self.assertEqual(myfunction, 'This is my function')
Andrew Svetlov0832af62012-12-18 23:10:48 +0200618 except (xmlrpclib.ProtocolError, OSError) as e:
Christian Heimes255f53b2007-12-08 15:33:56 +0000619 # ignore failures due to non-blocking socket 'unavailable' errors
620 if not is_unavailable_exception(e):
621 # protocol error; provide additional information in test output
Christian Heimes26855632008-01-27 23:50:43 +0000622 self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
Christian Heimes255f53b2007-12-08 15:33:56 +0000623
624 def test_introspection4(self):
Guido van Rossumaf554a02007-08-16 23:48:43 +0000625 # the SimpleXMLRPCServer doesn't support signatures, but
Thomas Woutersed03b412007-08-28 21:37:11 +0000626 # at least check that we can try making the call
Guido van Rossum04110fb2007-08-24 16:32:05 +0000627 try:
Benjamin Petersone1cdfd72009-01-18 21:02:37 +0000628 p = xmlrpclib.ServerProxy(URL)
Guido van Rossum04110fb2007-08-24 16:32:05 +0000629 divsig = p.system.methodSignature('div')
630 self.assertEqual(divsig, 'signatures not supported')
Andrew Svetlov0832af62012-12-18 23:10:48 +0200631 except (xmlrpclib.ProtocolError, OSError) as e:
Christian Heimes412dc9c2008-01-27 18:55:54 +0000632 # ignore failures due to non-blocking socket 'unavailable' errors
633 if not is_unavailable_exception(e):
634 # protocol error; provide additional information in test output
Christian Heimes26855632008-01-27 23:50:43 +0000635 self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
Guido van Rossumaf554a02007-08-16 23:48:43 +0000636
637 def test_multicall(self):
Guido van Rossum04110fb2007-08-24 16:32:05 +0000638 try:
Benjamin Petersone1cdfd72009-01-18 21:02:37 +0000639 p = xmlrpclib.ServerProxy(URL)
Guido van Rossum04110fb2007-08-24 16:32:05 +0000640 multicall = xmlrpclib.MultiCall(p)
641 multicall.add(2,3)
642 multicall.pow(6,8)
643 multicall.div(127,42)
644 add_result, pow_result, div_result = multicall()
645 self.assertEqual(add_result, 2+3)
646 self.assertEqual(pow_result, 6**8)
647 self.assertEqual(div_result, 127//42)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200648 except (xmlrpclib.ProtocolError, OSError) as e:
Christian Heimes412dc9c2008-01-27 18:55:54 +0000649 # ignore failures due to non-blocking socket 'unavailable' errors
650 if not is_unavailable_exception(e):
651 # protocol error; provide additional information in test output
Christian Heimes26855632008-01-27 23:50:43 +0000652 self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
Guido van Rossumaf554a02007-08-16 23:48:43 +0000653
Christian Heimes255f53b2007-12-08 15:33:56 +0000654 def test_non_existing_multicall(self):
655 try:
Benjamin Petersone1cdfd72009-01-18 21:02:37 +0000656 p = xmlrpclib.ServerProxy(URL)
Christian Heimes255f53b2007-12-08 15:33:56 +0000657 multicall = xmlrpclib.MultiCall(p)
658 multicall.this_is_not_exists()
659 result = multicall()
660
661 # result.results contains;
Martin v. Löwis250ad612008-04-07 05:43:42 +0000662 # [{'faultCode': 1, 'faultString': '<class \'exceptions.Exception\'>:'
Christian Heimes255f53b2007-12-08 15:33:56 +0000663 # 'method "this_is_not_exists" is not supported'>}]
664
665 self.assertEqual(result.results[0]['faultCode'], 1)
666 self.assertEqual(result.results[0]['faultString'],
Martin v. Löwis250ad612008-04-07 05:43:42 +0000667 '<class \'Exception\'>:method "this_is_not_exists" '
Christian Heimes255f53b2007-12-08 15:33:56 +0000668 'is not supported')
Andrew Svetlov0832af62012-12-18 23:10:48 +0200669 except (xmlrpclib.ProtocolError, OSError) as e:
Christian Heimes255f53b2007-12-08 15:33:56 +0000670 # ignore failures due to non-blocking socket 'unavailable' errors
671 if not is_unavailable_exception(e):
672 # protocol error; provide additional information in test output
Christian Heimes26855632008-01-27 23:50:43 +0000673 self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
Christian Heimes255f53b2007-12-08 15:33:56 +0000674
Christian Heimesfe337bf2008-03-23 21:54:12 +0000675 def test_dotted_attribute(self):
676 # Raises an AttributeError because private methods are not allowed.
677 self.assertRaises(AttributeError,
Georg Brandl38eceaa2008-05-26 11:14:17 +0000678 xmlrpc.server.resolve_dotted_attribute, str, '__add')
Christian Heimesfe337bf2008-03-23 21:54:12 +0000679
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000680 self.assertTrue(xmlrpc.server.resolve_dotted_attribute(str, 'title'))
Christian Heimesfe337bf2008-03-23 21:54:12 +0000681 # Get the test to run faster by sending a request with test_simple1.
682 # This avoids waiting for the socket timeout.
683 self.test_simple1()
684
Victor Stinnerda6eb532011-09-23 01:29:44 +0200685 def test_unicode_host(self):
686 server = xmlrpclib.ServerProxy("http://%s:%d/RPC2" % (ADDR, PORT))
687 self.assertEqual(server.add("a", "\xe9"), "a\xe9")
688
Charles-François Natalicd96b4f2012-02-18 14:53:41 +0100689 def test_partial_post(self):
690 # Check that a partial POST doesn't make the server loop: issue #14001.
691 conn = http.client.HTTPConnection(ADDR, PORT)
692 conn.request('POST', '/RPC2 HTTP/1.0\r\nContent-Length: 100\r\n\r\nbye')
693 conn.close()
694
695
Kristján Valur Jónsson1f2a1ae2009-12-16 10:50:44 +0000696class MultiPathServerTestCase(BaseServerTestCase):
697 threadFunc = staticmethod(http_multi_server)
698 request_count = 2
699 def test_path1(self):
700 p = xmlrpclib.ServerProxy(URL+"/foo")
701 self.assertEqual(p.pow(6,8), 6**8)
702 self.assertRaises(xmlrpclib.Fault, p.add, 6, 8)
Florent Xicluna3fa29f72011-10-30 20:18:50 +0100703
Kristján Valur Jónsson1f2a1ae2009-12-16 10:50:44 +0000704 def test_path2(self):
705 p = xmlrpclib.ServerProxy(URL+"/foo/bar")
706 self.assertEqual(p.add(6,8), 6+8)
707 self.assertRaises(xmlrpclib.Fault, p.pow, 6, 8)
708
Florent Xicluna3fa29f72011-10-30 20:18:50 +0100709 def test_path3(self):
710 p = xmlrpclib.ServerProxy(URL+"/is/broken")
711 self.assertRaises(xmlrpclib.Fault, p.add, 6, 8)
712
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000713#A test case that verifies that a server using the HTTP/1.1 keep-alive mechanism
714#does indeed serve subsequent requests on the same connection
Kristján Valur Jónssonf6087ca2009-07-12 22:45:18 +0000715class BaseKeepaliveServerTestCase(BaseServerTestCase):
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000716 #a request handler that supports keep-alive and logs requests into a
717 #class variable
718 class RequestHandler(xmlrpc.server.SimpleXMLRPCRequestHandler):
719 parentClass = xmlrpc.server.SimpleXMLRPCRequestHandler
720 protocol_version = 'HTTP/1.1'
721 myRequests = []
722 def handle(self):
723 self.myRequests.append([])
Kristján Valur Jónssonf6087ca2009-07-12 22:45:18 +0000724 self.reqidx = len(self.myRequests)-1
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000725 return self.parentClass.handle(self)
726 def handle_one_request(self):
727 result = self.parentClass.handle_one_request(self)
Kristján Valur Jónssonf6087ca2009-07-12 22:45:18 +0000728 self.myRequests[self.reqidx].append(self.raw_requestline)
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000729 return result
730
731 requestHandler = RequestHandler
732 def setUp(self):
733 #clear request log
734 self.RequestHandler.myRequests = []
735 return BaseServerTestCase.setUp(self)
736
Kristján Valur Jónssonf6087ca2009-07-12 22:45:18 +0000737#A test case that verifies that a server using the HTTP/1.1 keep-alive mechanism
738#does indeed serve subsequent requests on the same connection
739class KeepaliveServerTestCase1(BaseKeepaliveServerTestCase):
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000740 def test_two(self):
741 p = xmlrpclib.ServerProxy(URL)
Kristján Valur Jónsson1bbb19a2009-07-11 21:57:16 +0000742 #do three requests.
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000743 self.assertEqual(p.pow(6,8), 6**8)
744 self.assertEqual(p.pow(6,8), 6**8)
Kristján Valur Jónsson1bbb19a2009-07-11 21:57:16 +0000745 self.assertEqual(p.pow(6,8), 6**8)
Victor Stinnera935e8f2011-01-03 14:30:44 +0000746 p("close")()
Kristján Valur Jónsson1bbb19a2009-07-11 21:57:16 +0000747
748 #they should have all been handled by a single request handler
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000749 self.assertEqual(len(self.RequestHandler.myRequests), 1)
Kristján Valur Jónsson1bbb19a2009-07-11 21:57:16 +0000750
751 #check that we did at least two (the third may be pending append
752 #due to thread scheduling)
753 self.assertGreaterEqual(len(self.RequestHandler.myRequests[-1]), 2)
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000754
Victor Stinnera935e8f2011-01-03 14:30:44 +0000755
Kristján Valur Jónssonf6087ca2009-07-12 22:45:18 +0000756#test special attribute access on the serverproxy, through the __call__
757#function.
758class KeepaliveServerTestCase2(BaseKeepaliveServerTestCase):
759 #ask for two keepalive requests to be handled.
760 request_count=2
761
762 def test_close(self):
763 p = xmlrpclib.ServerProxy(URL)
764 #do some requests with close.
765 self.assertEqual(p.pow(6,8), 6**8)
766 self.assertEqual(p.pow(6,8), 6**8)
767 self.assertEqual(p.pow(6,8), 6**8)
768 p("close")() #this should trigger a new keep-alive request
769 self.assertEqual(p.pow(6,8), 6**8)
770 self.assertEqual(p.pow(6,8), 6**8)
771 self.assertEqual(p.pow(6,8), 6**8)
Victor Stinnera935e8f2011-01-03 14:30:44 +0000772 p("close")()
Kristján Valur Jónssonf6087ca2009-07-12 22:45:18 +0000773
774 #they should have all been two request handlers, each having logged at least
775 #two complete requests
776 self.assertEqual(len(self.RequestHandler.myRequests), 2)
777 self.assertGreaterEqual(len(self.RequestHandler.myRequests[-1]), 2)
778 self.assertGreaterEqual(len(self.RequestHandler.myRequests[-2]), 2)
779
Victor Stinnera935e8f2011-01-03 14:30:44 +0000780
Kristján Valur Jónssonf6087ca2009-07-12 22:45:18 +0000781 def test_transport(self):
782 p = xmlrpclib.ServerProxy(URL)
783 #do some requests with close.
784 self.assertEqual(p.pow(6,8), 6**8)
785 p("transport").close() #same as above, really.
786 self.assertEqual(p.pow(6,8), 6**8)
Victor Stinnera935e8f2011-01-03 14:30:44 +0000787 p("close")()
Kristján Valur Jónssonf6087ca2009-07-12 22:45:18 +0000788 self.assertEqual(len(self.RequestHandler.myRequests), 2)
789
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000790#A test case that verifies that gzip encoding works in both directions
791#(for a request and the response)
Brett Cannon603dcf22013-06-12 20:04:19 -0400792@unittest.skipIf(gzip is None, 'requires gzip')
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000793class GzipServerTestCase(BaseServerTestCase):
794 #a request handler that supports keep-alive and logs requests into a
795 #class variable
796 class RequestHandler(xmlrpc.server.SimpleXMLRPCRequestHandler):
797 parentClass = xmlrpc.server.SimpleXMLRPCRequestHandler
798 protocol_version = 'HTTP/1.1'
799
800 def do_POST(self):
801 #store content of last request in class
802 self.__class__.content_length = int(self.headers["content-length"])
803 return self.parentClass.do_POST(self)
804 requestHandler = RequestHandler
805
806 class Transport(xmlrpclib.Transport):
807 #custom transport, stores the response length for our perusal
808 fake_gzip = False
809 def parse_response(self, response):
810 self.response_length=int(response.getheader("content-length", 0))
811 return xmlrpclib.Transport.parse_response(self, response)
812
813 def send_content(self, connection, body):
814 if self.fake_gzip:
815 #add a lone gzip header to induce decode error remotely
816 connection.putheader("Content-Encoding", "gzip")
817 return xmlrpclib.Transport.send_content(self, connection, body)
818
Victor Stinner45df8202010-04-28 22:31:17 +0000819 def setUp(self):
820 BaseServerTestCase.setUp(self)
821
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000822 def test_gzip_request(self):
823 t = self.Transport()
824 t.encode_threshold = None
825 p = xmlrpclib.ServerProxy(URL, transport=t)
826 self.assertEqual(p.pow(6,8), 6**8)
827 a = self.RequestHandler.content_length
828 t.encode_threshold = 0 #turn on request encoding
829 self.assertEqual(p.pow(6,8), 6**8)
830 b = self.RequestHandler.content_length
831 self.assertTrue(a>b)
Victor Stinnera935e8f2011-01-03 14:30:44 +0000832 p("close")()
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000833
834 def test_bad_gzip_request(self):
835 t = self.Transport()
836 t.encode_threshold = None
837 t.fake_gzip = True
838 p = xmlrpclib.ServerProxy(URL, transport=t)
Ezio Melottied3a7d22010-12-01 02:32:32 +0000839 cm = self.assertRaisesRegex(xmlrpclib.ProtocolError,
840 re.compile(r"\b400\b"))
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000841 with cm:
842 p.pow(6, 8)
Victor Stinnera935e8f2011-01-03 14:30:44 +0000843 p("close")()
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000844
845 def test_gsip_response(self):
846 t = self.Transport()
847 p = xmlrpclib.ServerProxy(URL, transport=t)
848 old = self.requestHandler.encode_threshold
849 self.requestHandler.encode_threshold = None #no encoding
850 self.assertEqual(p.pow(6,8), 6**8)
851 a = t.response_length
852 self.requestHandler.encode_threshold = 0 #always encode
853 self.assertEqual(p.pow(6,8), 6**8)
Victor Stinnera935e8f2011-01-03 14:30:44 +0000854 p("close")()
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000855 b = t.response_length
856 self.requestHandler.encode_threshold = old
857 self.assertTrue(a>b)
858
859#Test special attributes of the ServerProxy object
860class ServerProxyTestCase(unittest.TestCase):
Victor Stinner45df8202010-04-28 22:31:17 +0000861 def setUp(self):
862 unittest.TestCase.setUp(self)
863 if threading:
864 self.url = URL
865 else:
866 # Without threading, http_server() and http_multi_server() will not
867 # be executed and URL is still equal to None. 'http://' is a just
868 # enough to choose the scheme (HTTP)
869 self.url = 'http://'
870
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000871 def test_close(self):
Victor Stinner45df8202010-04-28 22:31:17 +0000872 p = xmlrpclib.ServerProxy(self.url)
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000873 self.assertEqual(p('close')(), None)
874
875 def test_transport(self):
876 t = xmlrpclib.Transport()
Victor Stinner45df8202010-04-28 22:31:17 +0000877 p = xmlrpclib.ServerProxy(self.url, transport=t)
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000878 self.assertEqual(p('transport'), t)
879
Guido van Rossum61e21b52007-08-20 19:06:03 +0000880# This is a contrived way to make a failure occur on the server side
881# in order to test the _send_traceback_header flag on the server
Barry Warsaw820c1202008-06-12 04:06:45 +0000882class FailingMessageClass(http.client.HTTPMessage):
883 def get(self, key, failobj=None):
Guido van Rossum61e21b52007-08-20 19:06:03 +0000884 key = key.lower()
885 if key == 'content-length':
886 return 'I am broken'
Barry Warsaw820c1202008-06-12 04:06:45 +0000887 return super().get(key, failobj)
Guido van Rossum61e21b52007-08-20 19:06:03 +0000888
889
Victor Stinner45df8202010-04-28 22:31:17 +0000890@unittest.skipUnless(threading, 'Threading required for this test.')
Guido van Rossum61e21b52007-08-20 19:06:03 +0000891class FailingServerTestCase(unittest.TestCase):
892 def setUp(self):
893 self.evt = threading.Event()
894 # start server thread to handle requests
Guido van Rossum15c97462007-11-02 16:10:06 +0000895 serv_args = (self.evt, 1)
Guido van Rossum61e21b52007-08-20 19:06:03 +0000896 threading.Thread(target=http_server, args=serv_args).start()
897
Christian Heimesaf98da12008-01-27 15:18:18 +0000898 # wait for the server to be ready
899 self.evt.wait()
900 self.evt.clear()
Guido van Rossum61e21b52007-08-20 19:06:03 +0000901
902 def tearDown(self):
903 # wait on the server thread to terminate
904 self.evt.wait()
905 # reset flag
Georg Brandl38eceaa2008-05-26 11:14:17 +0000906 xmlrpc.server.SimpleXMLRPCServer._send_traceback_header = False
Guido van Rossum61e21b52007-08-20 19:06:03 +0000907 # reset message class
Barry Warsaw820c1202008-06-12 04:06:45 +0000908 default_class = http.client.HTTPMessage
909 xmlrpc.server.SimpleXMLRPCRequestHandler.MessageClass = default_class
Guido van Rossum61e21b52007-08-20 19:06:03 +0000910
911 def test_basic(self):
912 # check that flag is false by default
Georg Brandl38eceaa2008-05-26 11:14:17 +0000913 flagval = xmlrpc.server.SimpleXMLRPCServer._send_traceback_header
Guido van Rossum61e21b52007-08-20 19:06:03 +0000914 self.assertEqual(flagval, False)
915
Guido van Rossum04110fb2007-08-24 16:32:05 +0000916 # enable traceback reporting
Georg Brandl38eceaa2008-05-26 11:14:17 +0000917 xmlrpc.server.SimpleXMLRPCServer._send_traceback_header = True
Guido van Rossum04110fb2007-08-24 16:32:05 +0000918
919 # test a call that shouldn't fail just as a smoke test
920 try:
Benjamin Petersone1cdfd72009-01-18 21:02:37 +0000921 p = xmlrpclib.ServerProxy(URL)
Guido van Rossum04110fb2007-08-24 16:32:05 +0000922 self.assertEqual(p.pow(6,8), 6**8)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200923 except (xmlrpclib.ProtocolError, OSError) as e:
Christian Heimes412dc9c2008-01-27 18:55:54 +0000924 # ignore failures due to non-blocking socket 'unavailable' errors
925 if not is_unavailable_exception(e):
926 # protocol error; provide additional information in test output
Christian Heimes26855632008-01-27 23:50:43 +0000927 self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
Guido van Rossum61e21b52007-08-20 19:06:03 +0000928
929 def test_fail_no_info(self):
930 # use the broken message class
Georg Brandl38eceaa2008-05-26 11:14:17 +0000931 xmlrpc.server.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
Guido van Rossum61e21b52007-08-20 19:06:03 +0000932
933 try:
Benjamin Petersone1cdfd72009-01-18 21:02:37 +0000934 p = xmlrpclib.ServerProxy(URL)
Guido van Rossum61e21b52007-08-20 19:06:03 +0000935 p.pow(6,8)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200936 except (xmlrpclib.ProtocolError, OSError) as e:
Christian Heimes412dc9c2008-01-27 18:55:54 +0000937 # ignore failures due to non-blocking socket 'unavailable' errors
Christian Heimes26855632008-01-27 23:50:43 +0000938 if not is_unavailable_exception(e) and hasattr(e, "headers"):
Christian Heimes412dc9c2008-01-27 18:55:54 +0000939 # The two server-side error headers shouldn't be sent back in this case
940 self.assertTrue(e.headers.get("X-exception") is None)
941 self.assertTrue(e.headers.get("X-traceback") is None)
Guido van Rossum61e21b52007-08-20 19:06:03 +0000942 else:
943 self.fail('ProtocolError not raised')
944
945 def test_fail_with_info(self):
946 # use the broken message class
Georg Brandl38eceaa2008-05-26 11:14:17 +0000947 xmlrpc.server.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
Guido van Rossum61e21b52007-08-20 19:06:03 +0000948
949 # Check that errors in the server send back exception/traceback
950 # info when flag is set
Georg Brandl38eceaa2008-05-26 11:14:17 +0000951 xmlrpc.server.SimpleXMLRPCServer._send_traceback_header = True
Guido van Rossum61e21b52007-08-20 19:06:03 +0000952
953 try:
Benjamin Petersone1cdfd72009-01-18 21:02:37 +0000954 p = xmlrpclib.ServerProxy(URL)
Guido van Rossum61e21b52007-08-20 19:06:03 +0000955 p.pow(6,8)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200956 except (xmlrpclib.ProtocolError, OSError) as e:
Christian Heimes412dc9c2008-01-27 18:55:54 +0000957 # ignore failures due to non-blocking socket 'unavailable' errors
Christian Heimes26855632008-01-27 23:50:43 +0000958 if not is_unavailable_exception(e) and hasattr(e, "headers"):
Christian Heimes412dc9c2008-01-27 18:55:54 +0000959 # We should get error info in the response
960 expected_err = "invalid literal for int() with base 10: 'I am broken'"
Barry Warsaw820c1202008-06-12 04:06:45 +0000961 self.assertEqual(e.headers.get("X-exception"), expected_err)
962 self.assertTrue(e.headers.get("X-traceback") is not None)
Guido van Rossum61e21b52007-08-20 19:06:03 +0000963 else:
964 self.fail('ProtocolError not raised')
965
R. David Murray0548ce02009-10-26 08:24:14 +0000966
967@contextlib.contextmanager
968def captured_stdout(encoding='utf-8'):
969 """A variation on support.captured_stdout() which gives a text stream
970 having a `buffer` attribute.
971 """
972 import io
973 orig_stdout = sys.stdout
974 sys.stdout = io.TextIOWrapper(io.BytesIO(), encoding=encoding)
975 try:
976 yield sys.stdout
977 finally:
978 sys.stdout = orig_stdout
979
980
Christian Heimes255f53b2007-12-08 15:33:56 +0000981class CGIHandlerTestCase(unittest.TestCase):
982 def setUp(self):
Georg Brandl38eceaa2008-05-26 11:14:17 +0000983 self.cgi = xmlrpc.server.CGIXMLRPCRequestHandler()
Christian Heimes255f53b2007-12-08 15:33:56 +0000984
985 def tearDown(self):
986 self.cgi = None
987
988 def test_cgi_get(self):
Walter Dörwaldb525e182009-04-26 21:39:21 +0000989 with support.EnvironmentVarGuard() as env:
Walter Dörwald155374d2009-05-01 19:58:58 +0000990 env['REQUEST_METHOD'] = 'GET'
Walter Dörwaldb525e182009-04-26 21:39:21 +0000991 # if the method is GET and no request_text is given, it runs handle_get
992 # get sysout output
R. David Murray0548ce02009-10-26 08:24:14 +0000993 with captured_stdout(encoding=self.cgi.encoding) as data_out:
Nick Coghlan6ead5522009-10-18 13:19:33 +0000994 self.cgi.handle_request()
Christian Heimes255f53b2007-12-08 15:33:56 +0000995
Walter Dörwaldb525e182009-04-26 21:39:21 +0000996 # parse Status header
Nick Coghlan6ead5522009-10-18 13:19:33 +0000997 data_out.seek(0)
998 handle = data_out.read()
Walter Dörwaldb525e182009-04-26 21:39:21 +0000999 status = handle.split()[1]
1000 message = ' '.join(handle.split()[2:4])
Christian Heimes255f53b2007-12-08 15:33:56 +00001001
Walter Dörwaldb525e182009-04-26 21:39:21 +00001002 self.assertEqual(status, '400')
1003 self.assertEqual(message, 'Bad Request')
Christian Heimes255f53b2007-12-08 15:33:56 +00001004
Christian Heimes255f53b2007-12-08 15:33:56 +00001005
1006 def test_cgi_xmlrpc_response(self):
1007 data = """<?xml version='1.0'?>
Nick Coghlan6ead5522009-10-18 13:19:33 +00001008 <methodCall>
1009 <methodName>test_method</methodName>
1010 <params>
1011 <param>
1012 <value><string>foo</string></value>
1013 </param>
1014 <param>
1015 <value><string>bar</string></value>
1016 </param>
1017 </params>
1018 </methodCall>
1019 """
Christian Heimes255f53b2007-12-08 15:33:56 +00001020
Nick Coghlan6ead5522009-10-18 13:19:33 +00001021 with support.EnvironmentVarGuard() as env, \
R. David Murray0548ce02009-10-26 08:24:14 +00001022 captured_stdout(encoding=self.cgi.encoding) as data_out, \
Nick Coghlan6ead5522009-10-18 13:19:33 +00001023 support.captured_stdin() as data_in:
1024 data_in.write(data)
1025 data_in.seek(0)
Walter Dörwald155374d2009-05-01 19:58:58 +00001026 env['CONTENT_LENGTH'] = str(len(data))
Georg Brandlc7485062009-04-01 15:53:15 +00001027 self.cgi.handle_request()
Nick Coghlan6ead5522009-10-18 13:19:33 +00001028 data_out.seek(0)
Christian Heimes255f53b2007-12-08 15:33:56 +00001029
1030 # will respond exception, if so, our goal is achieved ;)
Nick Coghlan6ead5522009-10-18 13:19:33 +00001031 handle = data_out.read()
Christian Heimes255f53b2007-12-08 15:33:56 +00001032
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001033 # start with 44th char so as not to get http header, we just
1034 # need only xml
Christian Heimes255f53b2007-12-08 15:33:56 +00001035 self.assertRaises(xmlrpclib.Fault, xmlrpclib.loads, handle[44:])
1036
Senthil Kumaranb3af08f2009-04-01 20:20:43 +00001037 # Also test the content-length returned by handle_request
1038 # Using the same test method inorder to avoid all the datapassing
1039 # boilerplate code.
1040 # Test for bug: http://bugs.python.org/issue5040
1041
1042 content = handle[handle.find("<?xml"):]
1043
Ezio Melottib3aedd42010-11-20 19:04:17 +00001044 self.assertEqual(
Senthil Kumaranb3af08f2009-04-01 20:20:43 +00001045 int(re.search('Content-Length: (\d+)', handle).group(1)),
1046 len(content))
1047
Senthil Kumaranb3af08f2009-04-01 20:20:43 +00001048
Florent Xicluna1b7458b2011-12-09 22:35:06 +01001049class UseBuiltinTypesTestCase(unittest.TestCase):
1050
1051 def test_use_builtin_types(self):
1052 # SimpleXMLRPCDispatcher.__init__ accepts use_builtin_types, which
1053 # makes all dispatch of binary data as bytes instances, and all
1054 # dispatch of datetime argument as datetime.datetime instances.
1055 self.log = []
1056 expected_bytes = b"my dog has fleas"
1057 expected_date = datetime.datetime(2008, 5, 26, 18, 25, 12)
1058 marshaled = xmlrpclib.dumps((expected_bytes, expected_date), 'foobar')
1059 def foobar(*args):
1060 self.log.extend(args)
1061 handler = xmlrpc.server.SimpleXMLRPCDispatcher(
1062 allow_none=True, encoding=None, use_builtin_types=True)
1063 handler.register_function(foobar)
1064 handler._marshaled_dispatch(marshaled)
1065 self.assertEqual(len(self.log), 2)
1066 mybytes, mydate = self.log
1067 self.assertEqual(self.log, [expected_bytes, expected_date])
1068 self.assertIs(type(mydate), datetime.datetime)
1069 self.assertIs(type(mybytes), bytes)
1070
1071 def test_cgihandler_has_use_builtin_types_flag(self):
1072 handler = xmlrpc.server.CGIXMLRPCRequestHandler(use_builtin_types=True)
1073 self.assertTrue(handler.use_builtin_types)
1074
1075 def test_xmlrpcserver_has_use_builtin_types_flag(self):
1076 server = xmlrpc.server.SimpleXMLRPCServer(("localhost", 0),
1077 use_builtin_types=True)
1078 server.server_close()
1079 self.assertTrue(server.use_builtin_types)
1080
1081
Brett Cannone382b582013-06-12 21:25:23 -04001082@support.reap_threads
1083def test_main():
1084 support.run_unittest(XMLRPCTestCase, HelperTestCase, DateTimeTestCase,
1085 BinaryTestCase, FaultTestCase, UseBuiltinTypesTestCase,
1086 SimpleServerTestCase, KeepaliveServerTestCase1,
1087 KeepaliveServerTestCase2, GzipServerTestCase,
1088 MultiPathServerTestCase, ServerProxyTestCase, FailingServerTestCase,
1089 CGIHandlerTestCase)
1090
1091
Skip Montanaro419abda2001-10-01 17:47:44 +00001092if __name__ == "__main__":
Brett Cannone382b582013-06-12 21:25:23 -04001093 test_main()