Skip to content

Commit dfa25e9

Browse files
committed
Return 400 Bad Request if the XML-RPC request body is invalid
1 parent d9bfe2d commit dfa25e9

File tree

3 files changed

+51
-7
lines changed

3 files changed

+51
-7
lines changed

CHANGES.txt

+4
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131
- Files included via the ``[include]`` section are now logged at the ``INFO``
3232
level instead of ``WARN``. Patch by Daniel Hahler.
3333

34+
- ``400 Bad Request`` is now returned if an XML-RPC request is received with
35+
invalid body data. In previous versions, ``500 Internal Server Error``
36+
was returned.
37+
3438
3.2.2 (2016-03-04)
3539
------------------
3640

supervisor/tests/test_xmlrpc.py

+33-4
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,37 @@ def test_continue_request_400_if_method_name_is_empty(self):
153153
handler.continue_request(data, request)
154154
logdata = supervisor.options.logger.data
155155
self.assertEqual(len(logdata), 1)
156-
self.assertEqual(logdata[0],
157-
'XML-RPC request received with no method name')
158-
self.assertEqual(len(request.producers), 0)
156+
self.assertTrue(logdata[0].startswith('XML-RPC request data'))
157+
self.assertTrue(repr(data) in logdata[0])
158+
self.assertTrue(logdata[0].endswith('is invalid: no method name'))
159+
self.assertEqual(request._error, 400)
160+
161+
def test_continue_request_400_if_loads_raises_not_xml(self):
162+
supervisor = DummySupervisor()
163+
subinterfaces = [('supervisor', DummySupervisorRPCNamespace())]
164+
handler = self._makeOne(supervisor, subinterfaces)
165+
data = 'this is not an xml-rpc request body'
166+
request = DummyRequest('/what/ever', None, None, None)
167+
handler.continue_request(data, request)
168+
logdata = supervisor.options.logger.data
169+
self.assertEqual(len(logdata), 1)
170+
self.assertTrue(logdata[0].startswith('XML-RPC request data'))
171+
self.assertTrue(repr(data) in logdata[0])
172+
self.assertTrue(logdata[0].endswith('is invalid: unmarshallable'))
173+
self.assertEqual(request._error, 400)
174+
175+
def test_continue_request_400_if_loads_raises_weird_xml(self):
176+
supervisor = DummySupervisor()
177+
subinterfaces = [('supervisor', DummySupervisorRPCNamespace())]
178+
handler = self._makeOne(supervisor, subinterfaces)
179+
data = '<methodName></methodName><junk></junk>'
180+
request = DummyRequest('/what/ever', None, None, None)
181+
handler.continue_request(data, request)
182+
logdata = supervisor.options.logger.data
183+
self.assertEqual(len(logdata), 1)
184+
self.assertTrue(logdata[0].startswith('XML-RPC request data'))
185+
self.assertTrue(repr(data) in logdata[0])
186+
self.assertTrue(logdata[0].endswith('is invalid: unmarshallable'))
159187
self.assertEqual(request._error, 400)
160188

161189
def test_continue_request_500_if_rpcinterface_method_call_raises(self):
@@ -173,6 +201,7 @@ def test_continue_request_500_if_rpcinterface_method_call_raises(self):
173201
self.assertTrue(repr(data) in logdata[1])
174202
self.assertTrue("Traceback" in logdata[1])
175203
self.assertTrue("ValueError: error" in logdata[1])
204+
self.assertEqual(request._error, 500)
176205

177206
def test_continue_request_500_if_xmlrpc_dumps_raises(self):
178207
supervisor = DummySupervisor()
@@ -192,7 +221,7 @@ def test_continue_request_500_if_xmlrpc_dumps_raises(self):
192221
self.assertTrue(repr(data) in logdata[2])
193222
self.assertTrue("Traceback" in logdata[2])
194223
self.assertTrue("TypeError: cannot marshal" in logdata[2])
195-
224+
self.assertEqual(request._error, 500)
196225

197226
def test_continue_request_value_is_function(self):
198227
class DummyRPCNamespace(object):

supervisor/xmlrpc.py

+14-3
Original file line numberDiff line numberDiff line change
@@ -377,15 +377,26 @@ def loads(self, data):
377377
def match(self, request):
378378
return request.uri.startswith(self.path)
379379

380-
def continue_request (self, data, request):
380+
def continue_request(self, data, request):
381381
logger = self.supervisord.options.logger
382382

383383
try:
384-
params, method = self.loads(data)
384+
try:
385+
params, method = self.loads(data)
386+
except:
387+
logger.error(
388+
'XML-RPC request data %r is invalid: unmarshallable' %
389+
(data,)
390+
)
391+
request.error(400)
392+
return
385393

386394
# no <methodName> in the request or name is an empty string
387395
if not method:
388-
logger.trace('XML-RPC request received with no method name')
396+
logger.error(
397+
'XML-RPC request data %r is invalid: no method name' %
398+
(data,)
399+
)
389400
request.error(400)
390401
return
391402

0 commit comments

Comments
 (0)