~launchpad-pqm/launchpad/devel

8687.15.15 by Karl Fogel
Add the copyright header block to files under lib/lp/bugs/.
1
# Copyright 2009 Canonical Ltd.  This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
6604.1.2 by Tom Berger
use a new XMLRPC transport which uses urllib2, handles cookies and proxies
3
6604.1.12 by Tom Berger
post review and fixes
4
"""An XMLRPC transport which uses urllib2."""
6604.1.2 by Tom Berger
use a new XMLRPC transport which uses urllib2, handles cookies and proxies
5
6740.3.2 by Graham Binns
Added implementation for XMLRPCRedirectHandler.
6
__metaclass__ = type
7
__all__ = [
8
    'UrlLib2Transport',
12336.3.1 by Gavin Panella
Resurrect all the externalbugtracker stuff.
9
    'XMLRPCRedirectHandler',
6740.3.2 by Graham Binns
Added implementation for XMLRPCRedirectHandler.
10
    ]
11
6604.1.6 by Tom Berger
add some tests
12
13
from cookielib import Cookie
12336.3.1 by Gavin Panella
Resurrect all the externalbugtracker stuff.
14
from cStringIO import StringIO
6740.3.2 by Graham Binns
Added implementation for XMLRPCRedirectHandler.
15
from urllib2 import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
16
    build_opener,
17
    HTTPCookieProcessor,
18
    HTTPError,
19
    HTTPRedirectHandler,
20
    Request,
21
    )
22
from urlparse import (
23
    urlparse,
24
    urlunparse,
25
    )
26
from xmlrpclib import (
27
    ProtocolError,
28
    Transport,
29
    )
6604.1.2 by Tom Berger
use a new XMLRPC transport which uses urllib2, handles cookies and proxies
30
12336.3.1 by Gavin Panella
Resurrect all the externalbugtracker stuff.
31
from lp.services.utils import traceback_info
32
6740.3.2 by Graham Binns
Added implementation for XMLRPCRedirectHandler.
33
34
class XMLRPCRedirectHandler(HTTPRedirectHandler):
35
    """A handler for HTTP redirections of XML-RPC requests."""
36
37
    def redirect_request(self, req, fp, code, msg, headers, newurl):
38
        """Return a Request or None in response to a redirect.
39
40
        See `urllib2.HTTPRedirectHandler`.
41
42
        If the original request is a POST request, the request's payload
43
        will be preserved in the redirect and the returned request will
44
        also be a POST request.
45
        """
46
        # If we can't handle this redirect,
47
        # HTTPRedirectHandler.redirect_request() will raise an
6740.3.3 by Graham Binns
Added implementation for bug 249807 fix. Tests divn't work yet.
48
        # HTTPError. We call the superclass here in the old fashion
49
        # since HTTPRedirectHandler isn't a new-style class.
6740.3.2 by Graham Binns
Added implementation for XMLRPCRedirectHandler.
50
        new_request = HTTPRedirectHandler.redirect_request(
51
            self, req, fp, code, msg, headers, newurl)
52
53
        # If the old request is a POST request, the payload will be
54
        # preserved. Note that we don't need to test for the POST-ness
55
        # of the old request; if its data attribute - its payload - is
56
        # not None it's a POST request, if it's None it's a GET request.
57
        # We can therefore just copy the data from the old request to
58
        # the new without worrying about breaking things.
59
        new_request.data = req.data
60
        return new_request
61
62
6604.1.2 by Tom Berger
use a new XMLRPC transport which uses urllib2, handles cookies and proxies
63
class UrlLib2Transport(Transport):
6604.1.12 by Tom Berger
post review and fixes
64
    """An XMLRPC transport which uses urllib2.
6604.1.2 by Tom Berger
use a new XMLRPC transport which uses urllib2, handles cookies and proxies
65
9678.19.4 by Barry Warsaw
The test is bogus, so delete it. Delete also the comment about bug 7152 since
66
    This XMLRPC transport uses the Python urllib2 module to make the request,
67
    with proxying handled by that module's semantics (though underdocumented).
68
    It also handles cookies correctly, and in addition allows specifying the
69
    cookie explicitly by setting `self.auth_cookie`.
6604.1.2 by Tom Berger
use a new XMLRPC transport which uses urllib2, handles cookies and proxies
70
9678.19.4 by Barry Warsaw
The test is bogus, so delete it. Delete also the comment about bug 7152 since
71
    Note: this transport isn't fit for general XMLRPC use. It is just good
9678.19.5 by Barry Warsaw
spelling
72
    enough for some of our external bug tracker implementations.
6604.1.6 by Tom Berger
add some tests
73
74
    :param endpoint: The URL of the XMLRPC server.
6604.1.2 by Tom Berger
use a new XMLRPC transport which uses urllib2, handles cookies and proxies
75
    """
76
77
    verbose = False
78
7130.2.1 by Graham Binns
Urllib2Transport now accepts a CookieJar as a parameter.
79
    def __init__(self, endpoint, cookie_jar=None):
10060.1.1 by Gavin Panella
Force the use of datetime in the XML-RPC transport, and remove the workarounds in BugzillaAPI and BugzillaLPPlugin.
80
        Transport.__init__(self, use_datetime=True)
6604.1.6 by Tom Berger
add some tests
81
        self.scheme, self.host = urlparse(endpoint)[:2]
10060.1.2 by Gavin Panella
Fix lint.
82
        assert self.scheme in ('http', 'https'), (
9678.19.1 by Barry Warsaw
Port this to Python 2.5. There are two issues here:
83
            "Unsupported URL scheme: %s" % self.scheme)
7130.2.1 by Graham Binns
Urllib2Transport now accepts a CookieJar as a parameter.
84
        self.cookie_processor = HTTPCookieProcessor(cookie_jar)
6740.3.3 by Graham Binns
Added implementation for bug 249807 fix. Tests divn't work yet.
85
        self.redirect_handler = XMLRPCRedirectHandler()
86
        self.opener = build_opener(
87
            self.cookie_processor, self.redirect_handler)
6604.1.2 by Tom Berger
use a new XMLRPC transport which uses urllib2, handles cookies and proxies
88
6604.1.6 by Tom Berger
add some tests
89
    def setCookie(self, cookie_str):
6604.1.8 by Tom Berger
complete test for the base xml rpc transport
90
        """Set a cookie for the transport to use in future connections."""
6604.1.6 by Tom Berger
add some tests
91
        name, value = cookie_str.split('=')
92
        cookie = Cookie(
6604.1.12 by Tom Berger
post review and fixes
93
            version=0, name=name, value=value,
94
            port=None, port_specified=False,
95
            domain=self.host, domain_specified=True,
96
            domain_initial_dot=None,
6604.1.14 by Tom Berger
an additional fix, to get the probing done with the correct transport
97
            path='', path_specified=False,
6604.1.12 by Tom Berger
post review and fixes
98
            secure=False, expires=False, discard=None,
99
            comment=None, comment_url=None, rest=None)
6604.1.6 by Tom Berger
add some tests
100
        self.cookie_processor.cookiejar.set_cookie(cookie)
6604.1.4 by Tom Berger
add auth_cookie explicitly
101
6604.1.2 by Tom Berger
use a new XMLRPC transport which uses urllib2, handles cookies and proxies
102
    def request(self, host, handler, request_body, verbose=0):
103
        """Make an XMLRPC request.
104
105
        Uses the configured proxy server to make the connection.
106
        """
107
        url = urlunparse((self.scheme, host, handler, '', '', ''))
108
        headers = {'Content-type': 'text/xml'}
109
        request = Request(url, request_body, headers)
6604.1.14 by Tom Berger
an additional fix, to get the probing done with the correct transport
110
        try:
12336.3.1 by Gavin Panella
Resurrect all the externalbugtracker stuff.
111
            response = self.opener.open(request).read()
6604.1.14 by Tom Berger
an additional fix, to get the probing done with the correct transport
112
        except HTTPError, he:
113
            raise ProtocolError(
114
                request.get_full_url(), he.code, he.msg, he.hdrs)
12336.3.1 by Gavin Panella
Resurrect all the externalbugtracker stuff.
115
        else:
116
            traceback_info(response)
117
            return self._parse_response(StringIO(response), None)