1242
1244
(connection, credentials) = self._connection[0]
1243
1245
return self._connection[0][1]
1247
def _reuse_for(self, other_base):
1248
"""Returns a transport sharing the same connection if possible.
1250
Note: we share the connection if the expected credentials are the
1251
same: (host, port, user). Some protocols may disagree and redefine the
1252
criteria in daughter classes.
1254
Note: we don't compare the passwords here because other_base may have
1255
been obtained from an existing transport.base which do not mention the
1258
:param other_base: the URL we want to share the connection with.
1260
:return: A new transport or None if the connection cannot be shared.
1262
(scheme, user, password, host, port, path) = self._split_url(other_base)
1264
# Don't compare passwords, they may be absent from other_base
1267
host, port) == (self._scheme,
1269
self._host, self._port):
1270
if not path.endswith('/'):
1271
# This normally occurs at __init__ time, but it's easier to do
1272
# it now to avoid positives (creating two transports for the
1275
if self._path == path:
1276
# shortcut, it's really the same transport
1278
# We don't call clone here because the intent is different: we
1279
# build a new transport on a different base (which may be totally
1280
# unrelated) but we share the connection.
1281
transport = self.__class__(other_base, self)
1246
1286
# jam 20060426 For compatibility we copy the functions here
1247
1287
# TODO: The should be marked as deprecated
1248
1288
urlescape = urlutils.escape
1249
1289
urlunescape = urlutils.unescape
1250
_urlRE = re.compile(r'^(?P<proto>[^:/\\]+)://(?P<path>.*)$')
1290
# We try to recognize an url lazily (ignoring user, password, etc)
1291
_urlRE = re.compile(r'^(?P<proto>[^:/\\]+)://(?P<rest>.*)$')
1252
1293
def get_transport(base, possible_transports=None):
1253
1294
"""Open a transport to access a URL or directory.
1255
1296
:param base: either a URL or a directory name.
1256
:param transports: optional reusable transports list.
1298
:param transports: optional reusable transports list. If not None, created
1299
transports will be added to the list.
1301
:return: A new transport optionally sharing its connection with one of
1302
possible_transports.
1258
1304
if base is None:
1281
1327
transport = None
1282
1328
if possible_transports:
1283
1329
for t in possible_transports:
1287
if transport is None:
1288
for proto, factory_list in transport_list_registry.iteritems():
1289
if proto is not None and base.startswith(proto):
1290
transport, last_err = _try_transport_factories(base,
1294
if transport is None:
1295
# We tried all the different protocols, now try one last
1296
# time as a local protocol
1297
base = convert_path_to_url(base, 'Unsupported protocol: %s')
1299
# The default handler is the filesystem handler, stored
1301
factory_list = transport_list_registry.get(None)
1302
transport, last_err = _try_transport_factories(base, factory_list)
1330
t_same_connection = t._reuse_for(base)
1331
if t_same_connection is not None:
1332
# Add only new transports
1333
if t_same_connection not in possible_transports:
1334
possible_transports.append(t_same_connection)
1335
return t_same_connection
1337
for proto, factory_list in transport_list_registry.iteritems():
1338
if proto is not None and base.startswith(proto):
1339
transport, last_err = _try_transport_factories(base, factory_list)
1341
if possible_transports:
1342
assert transport not in possible_transports
1343
possible_transports.append(transport)
1346
# We tried all the different protocols, now try one last
1347
# time as a local protocol
1348
base = convert_path_to_url(base, 'Unsupported protocol: %s')
1350
# The default handler is the filesystem handler, stored
1352
factory_list = transport_list_registry.get(None)
1353
transport, last_err = _try_transport_factories(base, factory_list)
1303
1355
return transport
1358
def _try_transport_factories(base, factory_list):
1360
for factory in factory_list:
1362
return factory.get_obj()(base), None
1363
except errors.DependencyNotPresent, e:
1364
mutter("failed to instantiate transport %r for %r: %r" %
1368
return None, last_err
1306
1371
def do_catching_redirections(action, transport, redirected):
1307
1372
"""Execute an action with given transport catching redirections.
1345
1410
raise errors.TooManyRedirections
1348
def _try_transport_factories(base, factory_list):
1350
for factory in factory_list:
1352
return factory.get_obj()(base), None
1353
except errors.DependencyNotPresent, e:
1354
mutter("failed to instantiate transport %r for %r: %r" %
1358
return None, last_err
1361
1413
class Server(object):
1362
1414
"""A Transport Server.