[go: nahoru, domu]

Skip to content

Commit

Permalink
bpo-35153: Add headers parameter to xmlrpc.client.ServerProxy (GH-10308)
Browse files Browse the repository at this point in the history
Allow to add HTTP headers to XML-RPC requests sent to the server.
  • Loading branch information
cedk authored and vstinner committed Feb 19, 2019
1 parent 513e9b4 commit beda52e
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 11 deletions.
14 changes: 10 additions & 4 deletions Doc/library/xmlrpc.client.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,7 @@ between conformable Python objects and XML on the wire.

.. class:: ServerProxy(uri, transport=None, encoding=None, verbose=False, \
allow_none=False, use_datetime=False, \
use_builtin_types=False, *, context=None)
.. versionchanged:: 3.3
The *use_builtin_types* flag was added.
use_builtin_types=False, *, headers=(), context=None)
A :class:`ServerProxy` instance is an object that manages communication with a
remote XML-RPC server. The required first argument is a URI (Uniform Resource
Expand All @@ -59,9 +56,18 @@ between conformable Python objects and XML on the wire.
presented as :class:`bytes` objects; this flag is false by default.
:class:`datetime.datetime`, :class:`bytes` and :class:`bytearray` objects
may be passed to calls.
The *headers* parameter is an optional sequence of HTTP headers to send with
each request, expressed as a sequence of 2-tuples representing the header
name and value. (e.g. `[('Header-Name', 'value')]`).
The obsolete *use_datetime* flag is similar to *use_builtin_types* but it
applies only to date/time values.

.. versionchanged:: 3.3
The *use_builtin_types* flag was added.

.. versionchanged:: 3.8
The *headers* parameter was added.

Both the HTTP and HTTPS transports support the URL syntax extension for HTTP
Basic Authentication: ``http://user:pass@host:port/path``. The ``user:pass``
portion will be base64-encoded as an HTTP 'Authorization' header, and sent to
Expand Down
63 changes: 62 additions & 1 deletion Lib/test/test_xmlrpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1170,6 +1170,67 @@ def test_gzip_decode_limit(self):
xmlrpclib.gzip_decode(encoded, max_decode=-1)


class HeadersServerTestCase(BaseServerTestCase):
class RequestHandler(xmlrpc.server.SimpleXMLRPCRequestHandler):
test_headers = None

def do_POST(self):
self.__class__.test_headers = self.headers
return super().do_POST()
requestHandler = RequestHandler
standard_headers = [
'Host', 'Accept-Encoding', 'Content-Type', 'User-Agent',
'Content-Length']

def setUp(self):
self.RequestHandler.test_headers = None
return super().setUp()

def assertContainsAdditionalHeaders(self, headers, additional):
expected_keys = sorted(self.standard_headers + list(additional.keys()))
self.assertListEqual(sorted(headers.keys()), expected_keys)

for key, value in additional.items():
self.assertEqual(headers.get(key), value)

def test_header(self):
p = xmlrpclib.ServerProxy(URL, headers=[('X-Test', 'foo')])
self.assertEqual(p.pow(6, 8), 6**8)

headers = self.RequestHandler.test_headers
self.assertContainsAdditionalHeaders(headers, {'X-Test': 'foo'})

def test_header_many(self):
p = xmlrpclib.ServerProxy(
URL, headers=[('X-Test', 'foo'), ('X-Test-Second', 'bar')])
self.assertEqual(p.pow(6, 8), 6**8)

headers = self.RequestHandler.test_headers
self.assertContainsAdditionalHeaders(
headers, {'X-Test': 'foo', 'X-Test-Second': 'bar'})

def test_header_empty(self):
p = xmlrpclib.ServerProxy(URL, headers=[])
self.assertEqual(p.pow(6, 8), 6**8)

headers = self.RequestHandler.test_headers
self.assertContainsAdditionalHeaders(headers, {})

def test_header_tuple(self):
p = xmlrpclib.ServerProxy(URL, headers=(('X-Test', 'foo'),))
self.assertEqual(p.pow(6, 8), 6**8)

headers = self.RequestHandler.test_headers
self.assertContainsAdditionalHeaders(headers, {'X-Test': 'foo'})

def test_header_items(self):
p = xmlrpclib.ServerProxy(URL, headers={'X-Test': 'foo'}.items())
self.assertEqual(p.pow(6, 8), 6**8)

headers = self.RequestHandler.test_headers
self.assertContainsAdditionalHeaders(headers, {'X-Test': 'foo'})


#Test special attributes of the ServerProxy object
class ServerProxyTestCase(unittest.TestCase):
def setUp(self):
Expand Down Expand Up @@ -1396,7 +1457,7 @@ def test_main():
BinaryTestCase, FaultTestCase, UseBuiltinTypesTestCase,
SimpleServerTestCase, SimpleServerEncodingTestCase,
KeepaliveServerTestCase1, KeepaliveServerTestCase2,
GzipServerTestCase, GzipUtilTestCase,
GzipServerTestCase, GzipUtilTestCase, HeadersServerTestCase,
MultiPathServerTestCase, ServerProxyTestCase, FailingServerTestCase,
CGIHandlerTestCase, SimpleXMLRPCDispatcherTestCase)

Expand Down
17 changes: 11 additions & 6 deletions Lib/xmlrpc/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1131,10 +1131,12 @@ class Transport:
# that they can decode such a request
encode_threshold = None #None = don't encode

def __init__(self, use_datetime=False, use_builtin_types=False):
def __init__(self, use_datetime=False, use_builtin_types=False,
*, headers=()):
self._use_datetime = use_datetime
self._use_builtin_types = use_builtin_types
self._connection = (None, None)
self._headers = list(headers)
self._extra_headers = []

##
Expand Down Expand Up @@ -1265,7 +1267,7 @@ def close(self):

def send_request(self, host, handler, request_body, debug):
connection = self.make_connection(host)
headers = self._extra_headers[:]
headers = self._headers + self._extra_headers
if debug:
connection.set_debuglevel(1)
if self.accept_gzip_encoding and gzip:
Expand Down Expand Up @@ -1347,9 +1349,11 @@ def parse_response(self, response):
class SafeTransport(Transport):
"""Handles an HTTPS transaction to an XML-RPC server."""

def __init__(self, use_datetime=False, use_builtin_types=False, *,
context=None):
super().__init__(use_datetime=use_datetime, use_builtin_types=use_builtin_types)
def __init__(self, use_datetime=False, use_builtin_types=False,
*, headers=(), context=None):
super().__init__(use_datetime=use_datetime,
use_builtin_types=use_builtin_types,
headers=headers)
self.context = context

# FIXME: mostly untested
Expand Down Expand Up @@ -1409,7 +1413,7 @@ class ServerProxy:

def __init__(self, uri, transport=None, encoding=None, verbose=False,
allow_none=False, use_datetime=False, use_builtin_types=False,
*, context=None):
*, headers=(), context=None):
# establish a "logical" server connection

# get the url
Expand All @@ -1429,6 +1433,7 @@ def __init__(self, uri, transport=None, encoding=None, verbose=False,
extra_kwargs = {}
transport = handler(use_datetime=use_datetime,
use_builtin_types=use_builtin_types,
headers=headers,
**extra_kwargs)
self.__transport = transport

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Add *headers* optional keyword-only parameter to
:class:`xmlrpc.client.ServerProxy`, :class:`xmlrpc.client.Transport` and
:class:`xmlrpc.client.SafeTransport`. Patch by Cédric Krier.

0 comments on commit beda52e

Please sign in to comment.