512
512
:returns: A transport or None.
514
def relpath(abspath):
515
"""Returns the path relative to our base.
517
The constraints are weaker than the real relpath method because the
518
abspath is coming from the server and may slightly differ from our
519
base. We don't check the scheme, host, port, user, password parts,
520
relying on the caller to give us a proper url (i.e. one returned by
521
the server mirroring the one we sent).
523
parsed_url = self._split_url(abspath)
524
pl = len(self._parsed_url.path)
525
return parsed_url.path[pl:].strip('/')
527
relpath = relpath(source)
528
if not target.endswith(relpath):
514
parsed_source = self._split_url(source)
515
parsed_target = self._split_url(target)
516
pl = len(self._parsed_url.path)
517
# determine the excess tail - the relative path that was in
518
# the original request but not part of this transports' URL.
519
excess_tail = parsed_source.path[pl:].strip("/")
520
if not target.endswith(excess_tail):
529
521
# The final part of the url has been renamed, we can't handle the
533
parsed_url = self._split_url(target)
534
# Recalculate base path. This is needed to ensure that when the
535
# redirected transport will be used to re-try whatever request was
536
# redirected, we end up with the same url
537
base_path = parsed_url.path[:-len(relpath)]
538
if parsed_url.scheme in ('http', 'https'):
525
target_path = parsed_target.path
527
# Drop the tail that was in the redirect but not part of
528
# the path of this transport.
529
target_path = target_path[:-len(excess_tail)]
531
if parsed_target.scheme in ('http', 'https'):
539
532
# Same protocol family (i.e. http[s]), we will preserve the same
540
533
# http client implementation when a redirection occurs from one to
541
534
# the other (otherwise users may be surprised that bzr switches
542
535
# from one implementation to the other, and devs may suffer
544
if (parsed_url.scheme == self._unqualified_scheme
545
and parsed_url.host == self._parsed_url.host
546
and parsed_url.port == self._parsed_url.port
547
and (parsed_url.user is None or
548
parsed_url.user == self._parsed_url.user)):
537
if (parsed_target.scheme == self._unqualified_scheme
538
and parsed_target.host == self._parsed_url.host
539
and parsed_target.port == self._parsed_url.port
540
and (parsed_target.user is None or
541
parsed_target.user == self._parsed_url.user)):
549
542
# If a user is specified, it should match, we don't care about
550
543
# passwords, wrong passwords will be rejected anyway.
551
new_transport = self.clone(base_path)
544
return self.clone(target_path)
553
546
# Rebuild the url preserving the scheme qualification and the
554
547
# credentials (if they don't apply, the redirected to server
555
548
# will tell us, but if they do apply, we avoid prompting the
557
redir_scheme = parsed_url.scheme + '+' + self._impl_name
550
redir_scheme = parsed_target.scheme + '+' + self._impl_name
558
551
new_url = self._unsplit_url(redir_scheme,
559
self._parsed_url.user,
560
self._parsed_url.password,
561
parsed_url.host, parsed_url.port,
563
new_transport = transport.get_transport_from_url(
552
self._parsed_url.user,
553
self._parsed_url.password,
554
parsed_target.host, parsed_target.port,
556
return transport.get_transport_from_url(new_url)
566
558
# Redirected to a different protocol
567
new_url = self._unsplit_url(parsed_url.scheme,
568
parsed_url.user, parsed_url.password,
569
parsed_url.host, parsed_url.port,
571
new_transport = transport.get_transport_from_url(
559
new_url = self._unsplit_url(parsed_target.scheme,
561
parsed_target.password,
562
parsed_target.host, parsed_target.port,
564
return transport.get_transport_from_url(new_url)
576
567
# TODO: May be better located in smart/medium.py with the other