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