Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(10)

Delta Between Two Patch Sets: Lib/test/test_xmlrpc.py

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

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+