Skip to main content

Lib/xmlrpc/ (part 2)

Source:

cpython 3.14 @ ab2d84fe1023/Lib/xmlrpc/server.py

This annotation covers the server side. See lib_xmlrpc_detail for xmlrpc.client.ServerProxy, Fault, MultiCall, marshaling, and the XML encoding.

Map

LinesSymbolRole
1-100SimpleXMLRPCDispatcherBase class: method registry, dispatch, _dispatch
101-280SimpleXMLRPCServerTCPServer + dispatcher; handles one request at a time
281-420MultiPathXMLRPCServerRoute requests to different dispatchers by URL path
421-560CGIXMLRPCRequestHandlerHandle XML-RPC via CGI stdin/stdout
561-700Introspection (system.*)system.listMethods, system.methodHelp, system.methodSignature
701-800resolve_dotted_attributeSafely traverse attribute chains for method dispatch

Reading

SimpleXMLRPCDispatcher

# CPython: Lib/xmlrpc/server.py:120 SimpleXMLRPCDispatcher
class SimpleXMLRPCDispatcher:
def register_function(self, function, name=None):
"""Register a function to respond to XML-RPC requests.

name -- the XML-RPC name (default: function.__name__)
"""
if name is None:
name = function.__name__
self.funcs[name] = function

def register_instance(self, instance, allow_dotted_names=False):
"""Register an object as the handler for all methods not in self.funcs."""
self.instance = instance
self.allow_dotted_names = allow_dotted_names

register_function maps XML-RPC method names to Python callables. register_instance provides a fallback object whose methods are looked up by name. allow_dotted_names=True enables obj.subobj.method dispatch (a security risk if untrusted clients can call arbitrary attributes).

_dispatch

# CPython: Lib/xmlrpc/server.py:220 _dispatch
def _dispatch(self, method, params):
"""Dispatch an XML-RPC call to the appropriate Python function."""
func = self.funcs.get(method)
if func is None and self.instance is not None:
if self.allow_dotted_names:
func = resolve_dotted_attribute(self.instance, method)
elif hasattr(self.instance, '_dispatch'):
return self.instance._dispatch(method, params)
else:
func = getattr(self.instance, method, None)
if func is None:
raise Exception(f'method "{method}" is not supported')
return func(*params)

resolve_dotted_attribute

# CPython: Lib/xmlrpc/server.py:740 resolve_dotted_attribute
def resolve_dotted_attribute(obj, attr, allow_dotted_names=True):
"""Resolve a dotted attribute chain like 'a.b.c' on obj."""
attrs = attr.split('.')
for i in attrs:
if i.startswith('_'): # never resolve private/dunder attrs
raise AttributeError(f'attempt to access private attribute "{i}"')
obj = getattr(obj, i)
return obj

Private attributes (starting with _) are blocked to prevent clients from calling __class__.__mro__[0].__subclasses__() style attacks.

Introspection methods

# CPython: Lib/xmlrpc/server.py:565 register_introspection_functions
def register_introspection_functions(self):
self.funcs.update({
'system.listMethods': self.system_listMethods,
'system.methodSignature': self.system_methodSignature,
'system.methodHelp': self.system_methodHelp,
})

def system_listMethods(self):
"""Return a list of all callable method names."""
methods = set(self.funcs.keys())
if self.instance is not None:
methods |= set(m for m in dir(self.instance)
if not m.startswith('_'))
return sorted(methods)

system.listMethods is the XML-RPC introspection API. Clients like xmlrpc.client.ServerProxy can call it to discover available methods.

gopy notes

xmlrpc.server is pure Python. SimpleXMLRPCServer extends http.server.HTTPServer which uses module/http/server. _dispatch resolution uses objects.GetAttr. The XML encoding/decoding delegates to Lib/xmlrpc/client.py which is annotated in lib_xmlrpc_detail.