~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Martin Packman
  • Date: 2012-01-05 09:50:04 UTC
  • mfrom: (6424 +trunk)
  • mto: This revision was merged to the branch mainline in revision 6426.
  • Revision ID: martin.packman@canonical.com-20120105095004-mia9xb7y0efmto0v
Merge bzr.dev to resolve conflicts in bzrlib.builtins

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
There are separate implementation modules for each http client implementation.
20
20
"""
21
21
 
 
22
from __future__ import absolute_import
 
23
 
22
24
from cStringIO import StringIO
23
 
import mimetools
24
25
import re
25
26
import urlparse
26
 
import urllib
27
27
import sys
28
28
import weakref
29
29
 
35
35
    urlutils,
36
36
    )
37
37
from bzrlib.smart import medium
38
 
from bzrlib.symbol_versioning import (
39
 
        deprecated_method,
40
 
        )
41
38
from bzrlib.trace import mutter
42
39
from bzrlib.transport import (
43
40
    ConnectedTransport,
44
 
    _CoalescedOffset,
45
 
    Transport,
46
41
    )
47
42
 
48
43
# TODO: This is not used anymore by HttpTransport_urllib
69
64
            host = netloc.split(':', 1)[0]
70
65
        else:
71
66
            host = netloc
72
 
        username = urllib.unquote(username)
 
67
        username = urlutils.unquote(username)
73
68
        if password is not None:
74
 
            password = urllib.unquote(password)
 
69
            password = urlutils.unquote(password)
75
70
        else:
76
71
            password = ui.ui_factory.get_password(
77
72
                prompt=u'HTTP %(user)s@%(host)s password',
517
512
 
518
513
        :returns: A transport or None.
519
514
        """
520
 
        def relpath(abspath):
521
 
            """Returns the path relative to our base.
522
 
 
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).
528
 
            """
529
 
            parsed_url = self._split_url(abspath)
530
 
            pl = len(self._parsed_url.path)
531
 
            return parsed_url.path[pl:].strip('/')
532
 
 
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
536
523
            # redirection.
537
524
            return None
538
 
        new_transport = None
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'):
 
525
 
 
526
        target_path = parsed_target.path
 
527
        if excess_tail:
 
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)]
 
531
 
 
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
549
537
            # debugging it).
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)
558
546
            else:
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
562
550
                # user)
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,
568
 
                                            base_path)
569
 
                new_transport = transport.get_transport_from_url(
570
 
                    new_url)
 
553
                    self._parsed_url.user,
 
554
                    self._parsed_url.password,
 
555
                    parsed_target.host, parsed_target.port,
 
556
                    target_path)
 
557
                return transport.get_transport_from_url(new_url)
571
558
        else:
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,
576
 
                                        base_path)
577
 
            new_transport = transport.get_transport_from_url(
578
 
                new_url)
579
 
        return new_transport
 
560
            new_url = self._unsplit_url(parsed_target.scheme,
 
561
                    parsed_target.user,
 
562
                    parsed_target.password,
 
563
                    parsed_target.host, parsed_target.port,
 
564
                    target_path)
 
565
            return transport.get_transport_from_url(new_url)
580
566
 
581
567
 
582
568
# TODO: May be better located in smart/medium.py with the other
604
590
        if transport_base.startswith('bzr+'):
605
591
            transport_base = transport_base[4:]
606
592
        rel_url = urlutils.relative_url(self.base, transport_base)
607
 
        return urllib.unquote(rel_url)
 
593
        return urlutils.unquote(rel_url)
608
594
 
609
595
    def send_http_smart_request(self, bytes):
610
596
        try:
612
598
            t = self._http_transport_ref()
613
599
            code, body_filelike = t._post(bytes)
614
600
            if code != 200:
615
 
                raise InvalidHttpResponse(
 
601
                raise errors.InvalidHttpResponse(
616
602
                    t._remote_path('.bzr/smart'),
617
603
                    'Expected 200 response code, got %r' % (code,))
618
604
        except (errors.InvalidHttpResponse, errors.ConnectionReset), e: