~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/http/__init__.py

(jelmer) Fix some issues with http redirects. (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
511
511
 
512
512
        :returns: A transport or None.
513
513
        """
514
 
        def relpath(abspath):
515
 
            """Returns the path relative to our base.
516
 
 
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).
522
 
            """
523
 
            parsed_url = self._split_url(abspath)
524
 
            pl = len(self._parsed_url.path)
525
 
            return parsed_url.path[pl:].strip('/')
526
 
 
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
530
522
            # redirection.
531
523
            return None
532
 
        new_transport = None
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'):
 
524
 
 
525
        target_path = parsed_target.path
 
526
        if excess_tail:
 
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)]
 
530
 
 
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
543
536
            # debugging it).
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)
552
545
            else:
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
556
549
                # user)
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,
562
 
                                            base_path)
563
 
                new_transport = transport.get_transport_from_url(
564
 
                    new_url)
 
552
                    self._parsed_url.user,
 
553
                    self._parsed_url.password,
 
554
                    parsed_target.host, parsed_target.port,
 
555
                    target_path)
 
556
                return transport.get_transport_from_url(new_url)
565
557
        else:
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,
570
 
                                        base_path)
571
 
            new_transport = transport.get_transport_from_url(
572
 
                new_url)
573
 
        return new_transport
 
559
            new_url = self._unsplit_url(parsed_target.scheme,
 
560
                    parsed_target.user,
 
561
                    parsed_target.password,
 
562
                    parsed_target.host, parsed_target.port,
 
563
                    target_path)
 
564
            return transport.get_transport_from_url(new_url)
574
565
 
575
566
 
576
567
# TODO: May be better located in smart/medium.py with the other