/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

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

  • Committer: Andrew Bennetts
  • Date: 2010-04-13 04:33:55 UTC
  • mfrom: (5147 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5149.
  • Revision ID: andrew.bennetts@canonical.com-20100413043355-lg3id0uwtju0k3zs
MergeĀ lp:bzr.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""Base implementation of Transport over http.
18
18
 
41
41
from bzrlib.transport import (
42
42
    ConnectedTransport,
43
43
    _CoalescedOffset,
 
44
    get_transport,
44
45
    Transport,
45
46
    )
46
47
 
92
93
    # _unqualified_scheme: "http" or "https"
93
94
    # _scheme: may have "+pycurl", etc
94
95
 
95
 
    def __init__(self, base, _from_transport=None):
 
96
    def __init__(self, base, _impl_name, _from_transport=None):
96
97
        """Set the base path where files will be stored."""
97
98
        proto_match = re.match(r'^(https?)(\+\w+)?://', base)
98
99
        if not proto_match:
99
100
            raise AssertionError("not a http url: %r" % base)
100
101
        self._unqualified_scheme = proto_match.group(1)
101
 
        impl_name = proto_match.group(2)
102
 
        if impl_name:
103
 
            impl_name = impl_name[1:]
104
 
        self._impl_name = impl_name
 
102
        self._impl_name = _impl_name
105
103
        super(HttpTransportBase, self).__init__(base,
106
104
                                                _from_transport=_from_transport)
107
105
        self._medium = None
156
154
                                 None, None, self._host, self._port, path)
157
155
 
158
156
    def _create_auth(self):
159
 
        """Returns a dict returning the credentials provided at build time."""
 
157
        """Returns a dict containing the credentials provided at build time."""
160
158
        auth = dict(host=self._host, port=self._port,
161
159
                    user=self._user, password=self._password,
162
160
                    protocol=self._unqualified_scheme,
173
171
            self._medium = SmartClientHTTPMedium(self)
174
172
        return self._medium
175
173
 
176
 
 
177
174
    def _degrade_range_hint(self, relpath, ranges, exc_info):
178
175
        if self._range_hint == 'multi':
179
176
            self._range_hint = 'single'
214
211
        :param offsets: A list of (offset, size) tuples.
215
212
        :param return: A list or generator of (offset, data) tuples
216
213
        """
217
 
 
218
214
        # offsets may be a generator, we will iterate it several times, so
219
215
        # build a list
220
216
        offsets = list(offsets)
351
347
 
352
348
    def _post(self, body_bytes):
353
349
        """POST body_bytes to .bzr/smart on this transport.
354
 
        
 
350
 
355
351
        :returns: (response code, response body file-like object).
356
352
        """
357
353
        # TODO: Requiring all the body_bytes to be available at the beginning of
414
410
 
415
411
    def external_url(self):
416
412
        """See bzrlib.transport.Transport.external_url."""
417
 
        # HTTP URL's are externally usable.
418
 
        return self.base
 
413
        # HTTP URL's are externally usable as long as they don't mention their
 
414
        # implementation qualifier
 
415
        return self._unsplit_url(self._unqualified_scheme,
 
416
                                 self._user, self._password,
 
417
                                 self._host, self._port,
 
418
                                 self._path)
419
419
 
420
420
    def is_readonly(self):
421
421
        """See Transport.is_readonly."""
451
451
        """
452
452
        raise errors.TransportNotPossible('http does not support lock_write()')
453
453
 
454
 
    def clone(self, offset=None):
455
 
        """Return a new HttpTransportBase with root at self.base + offset
456
 
 
457
 
        We leave the daughter classes take advantage of the hint
458
 
        that it's a cloning not a raw creation.
459
 
        """
460
 
        if offset is None:
461
 
            return self.__class__(self.base, self)
462
 
        else:
463
 
            return self.__class__(self.abspath(offset), self)
464
 
 
465
454
    def _attempted_range_header(self, offsets, tail_amount):
466
455
        """Prepare a HTTP Range header at a level the server should accept.
467
456
 
517
506
 
518
507
        return ','.join(strings)
519
508
 
 
509
    def _redirected_to(self, source, target):
 
510
        """Returns a transport suitable to re-issue a redirected request.
 
511
 
 
512
        :param source: The source url as returned by the server.
 
513
        :param target: The target url as returned by the server.
 
514
 
 
515
        The redirection can be handled only if the relpath involved is not
 
516
        renamed by the redirection.
 
517
 
 
518
        :returns: A transport or None.
 
519
        """
 
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
            (scheme,
 
530
             user, password,
 
531
             host, port,
 
532
             path) = self._split_url(abspath)
 
533
            pl = len(self._path)
 
534
            return path[pl:].strip('/')
 
535
 
 
536
        relpath = relpath(source)
 
537
        if not target.endswith(relpath):
 
538
            # The final part of the url has been renamed, we can't handle the
 
539
            # redirection.
 
540
            return None
 
541
        new_transport = None
 
542
        (scheme,
 
543
         user, password,
 
544
         host, port,
 
545
         path) = self._split_url(target)
 
546
        # Recalculate base path. This is needed to ensure that when the
 
547
        # redirected tranport will be used to re-try whatever request was
 
548
        # redirected, we end up with the same url
 
549
        base_path = path[:-len(relpath)]
 
550
        if scheme in ('http', 'https'):
 
551
            # Same protocol family (i.e. http[s]), we will preserve the same
 
552
            # http client implementation when a redirection occurs from one to
 
553
            # the other (otherwise users may be surprised that bzr switches
 
554
            # from one implementation to the other, and devs may suffer
 
555
            # debugging it).
 
556
            if (scheme == self._unqualified_scheme
 
557
                and host == self._host
 
558
                and port == self._port
 
559
                and (user is None or user == self._user)):
 
560
                # If a user is specified, it should match, we don't care about
 
561
                # passwords, wrong passwords will be rejected anyway.
 
562
                new_transport = self.clone(base_path)
 
563
            else:
 
564
                # Rebuild the url preserving the scheme qualification and the
 
565
                # credentials (if they don't apply, the redirected to server
 
566
                # will tell us, but if they do apply, we avoid prompting the
 
567
                # user)
 
568
                redir_scheme = scheme + '+' + self._impl_name
 
569
                new_url = self._unsplit_url(redir_scheme,
 
570
                                            self._user, self._password,
 
571
                                            host, port,
 
572
                                            base_path)
 
573
                new_transport = get_transport(new_url)
 
574
        else:
 
575
            # Redirected to a different protocol
 
576
            new_url = self._unsplit_url(scheme,
 
577
                                        user, password,
 
578
                                        host, port,
 
579
                                        base_path)
 
580
            new_transport = get_transport(new_url)
 
581
        return new_transport
 
582
 
520
583
 
521
584
# TODO: May be better located in smart/medium.py with the other
522
585
# SmartMedium classes
554
617
                raise InvalidHttpResponse(
555
618
                    t._remote_path('.bzr/smart'),
556
619
                    'Expected 200 response code, got %r' % (code,))
557
 
        except errors.InvalidHttpResponse, e:
 
620
        except (errors.InvalidHttpResponse, errors.ConnectionReset), e:
558
621
            raise errors.SmartProtocolError(str(e))
559
622
        return body_filelike
560
623
 
 
624
    def _report_activity(self, bytes, direction):
 
625
        """See SmartMedium._report_activity.
 
626
 
 
627
        Does nothing; the underlying plain HTTP transport will report the
 
628
        activity that this medium would report.
 
629
        """
 
630
        pass
 
631
 
561
632
 
562
633
# TODO: May be better located in smart/medium.py with the other
563
634
# SmartMediumRequest classes