]> git.ipfire.org Git - people/ms/pakfire.git/blame - python/pakfire/client/transport.py
Use the HTTP proxy for HTTPS as well.
[people/ms/pakfire.git] / python / pakfire / client / transport.py
CommitLineData
c62d93f1
MT
1#!/usr/bin/python
2###############################################################################
3# #
4# Pakfire - The IPFire package management system #
5# Copyright (C) 2011 Pakfire development team #
6# #
7# This program is free software: you can redistribute it and/or modify #
8# it under the terms of the GNU General Public License as published by #
9# the Free Software Foundation, either version 3 of the License, or #
10# (at your option) any later version. #
11# #
12# This program is distributed in the hope that it will be useful, #
13# but WITHOUT ANY WARRANTY; without even the implied warranty of #
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15# GNU General Public License for more details. #
16# #
17# You should have received a copy of the GNU General Public License #
18# along with this program. If not, see <http://www.gnu.org/licenses/>. #
19# #
20###############################################################################
21
ae0bc1af 22import httplib
c62d93f1 23import socket
d5166686 24import ssl
c62d93f1
MT
25import time
26import xmlrpclib
27
28import logging
29log = logging.getLogger("pakfire.client")
30
31from pakfire.constants import *
32from pakfire.i18n import _
33
2dbaea05
MT
34# Set the default socket timeout to 30 seconds.
35socket.setdefaulttimeout(30)
36
c611f46b
MT
37
38
39
c62d93f1
MT
40class XMLRPCMixin:
41 user_agent = "pakfire/%s" % PAKFIRE_VERSION
42
43 def single_request(self, *args, **kwargs):
44 ret = None
45
46 # Tries can be passed to this method.
47 tries = kwargs.pop("tries", 100)
48 timeout = 1
49
50 while tries:
51 try:
52 ret = xmlrpclib.Transport.single_request(self, *args, **kwargs)
53
37ff3f8f 54 # Catch errors related to the connection. Just try again.
2dbaea05
MT
55 except (socket.error, ssl.SSLError), e:
56 log.warning("Exception: %s: %s" % (e.__class__.__name__, e))
c62d93f1 57
37ff3f8f
MT
58 # Presumably, the server closed the connection before sending anything.
59 except httplib.BadStatusLine:
2dbaea05
MT
60 # Try again immediately.
61 continue
37ff3f8f
MT
62
63 # The XML reponse could not be parsed.
2dbaea05
MT
64 except xmlrpclib.ResponseError, e:
65 log.warning("Exception: %s: %s" % (e.__class__.__name__, e))
37ff3f8f
MT
66
67 except xmlrpclib.ProtocolError, e:
68 if e.errcode == 403:
69 # Possibly, the user credentials are invalid.
70 # Cannot go on.
71 raise XMLRPCForbiddenError(e)
72
73 elif e.errcode == 404:
74 # Some invalid URL was called.
75 # Cannot go on.
76 raise XMLRPCNotFoundError(e)
77
e3eb9333
MT
78 elif e.errcode == 500:
79 # This could have various reasons, so we can not
80 # be sure to kill connections here.
81 # But to visualize the issue, we will raise an
82 # exception on the last try.
83 if tries == 1:
84 raise XMLRPCInternalServerError(e)
85
37ff3f8f
MT
86 elif e.errcode == 503:
87 # Possibly the hub is not running but the SSL proxy
88 # is. Just try again in a short time.
89 pass
90
91 else:
92 # Log all XMLRPC protocol errors.
93 log.error(_("XMLRPC protocol error:"))
94 log.error(" %s" % _("URL: %s") % e.url)
95 log.error(" %s" % _(" HTTP headers:"))
96 for header in e.headers.items():
97 log.error(" %s: %s" % header)
98 log.error(" %s" % _("Error code: %s") % e.errcode)
99 log.error(" %s" % _("Error message: %s") % e.errmsg)
100
101 # If an unhandled error code appeared, we raise an
102 # error.
103 raise
104
105 except xmlrpclib.Fault:
106 raise
107
c62d93f1
MT
108 else:
109 # If request was successful, we can break the loop.
110 break
111
112 # If the request was not successful, we wait a little time to try
113 # it again.
114 tries -= 1
115 timeout *= 2
116 if timeout > 60:
117 timeout = 60
118
4cdde79f
MT
119 log.warning(_("Trying again in %(timeout)s second(s). %(tries)s tries left.") \
120 % { "timeout" : timeout, "tries" : tries })
c62d93f1
MT
121 time.sleep(timeout)
122
123 else:
37ff3f8f 124 raise XMLRPCTransportError, _("Maximum number of tries was reached. Giving up.")
c62d93f1
MT
125
126 return ret
127
128
37ff3f8f 129
c62d93f1
MT
130class XMLRPCTransport(XMLRPCMixin, xmlrpclib.Transport):
131 """
132 Handles the XMLRPC connection over HTTP.
133 """
134 pass
135
136
137class SafeXMLRPCTransport(XMLRPCMixin, xmlrpclib.SafeTransport):
138 """
139 Handles the XMLRPC connection over HTTPS.
140 """
141 pass
142
143
144class Connection(xmlrpclib.ServerProxy):
145 """
146 Class wrapper that automatically chooses the right transport
147 method depending on the given URL.
148 """
149
150 def __init__(self, url):
151 # Create transport channel to the server.
152 if url.startswith("https://"):
153 transport = SafeXMLRPCTransport()
154 elif url.startswith("http://"):
155 transport = XMLRPCTransport()
156
157 xmlrpclib.ServerProxy.__init__(self, url, transport=transport,
158 allow_none=True)