1"""
2Security enhancements for xmlrpc.
3"""
4from __future__ import print_function
5
6import sys
7
8try:
9    import xmlrpc.client as xmlrpclib
10except ImportError:
11    import xmlrpclib
12
13try:
14    import requests
15except ImportError:
16    print('python requests is required, please reinstall.', file=sys.stderr)
17    sys.exit(1)
18
19
20class RequestsTransport(xmlrpclib.Transport):
21    """
22    Drop in Transport for xmlrpclib that uses Requests instead of httplib
23    # https://gist.github.com/chrisguitarguy/2354951
24    # https://github.com/mardiros/pyshop/blob/master/pyshop/helpers/pypi.py
25    """
26
27    use_https = True
28
29    def __init__(self, use_datetime=0, host=None):
30        xmlrpclib.Transport.__init__(self, use_datetime)
31        if host:
32            self.use_https = 'https' in host
33
34    def request(self, host, handler, request_body, verbose):
35        """
36        Make an xmlrpc request.
37        """
38        headers = {'User-Agent': self.user_agent,
39                   'Accept': 'text/xml',
40                   'Content-Type': 'text/xml'}
41
42        url = self._build_url(host, handler)
43        try:
44            resp = requests.post(url, data=request_body, headers=headers)
45        except ValueError:
46            raise
47        except Exception:
48            raise  # something went wrong
49        else:
50            try:
51                resp.raise_for_status()
52            except requests.RequestException as e:
53                raise xmlrpclib.ProtocolError(url, resp.status_code,
54                                              str(e), resp.headers)
55            else:
56                return self.parse_response(resp)
57
58    def parse_response(self, resp):
59        """
60        Parse the xmlrpc response.
61        """
62        p, u = self.getparser()
63        p.feed(resp.content)
64        p.close()
65        return u.close()
66
67    def _build_url(self, host, handler):
68        """
69        Build a url for our request based on the host, handler and use_https
70        property
71        """
72        scheme = 'https' if self.use_https else 'http'
73        return '%s://%s%s' % (scheme, host, handler)
74