~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Marius Kruger
  • Date: 2008-10-01 00:17:39 UTC
  • mfrom: (3753 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3809.
  • Revision ID: amanic@gmail.com-20081001001739-65kpo9asl0q8pdcz
merge with bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
import urlparse
26
26
import urllib
27
27
import sys
 
28
import weakref
28
29
 
29
30
from bzrlib import (
 
31
    debug,
30
32
    errors,
31
33
    ui,
32
34
    urlutils,
78
80
    return url
79
81
 
80
82
 
81
 
class HttpTransportBase(ConnectedTransport, medium.SmartClientMedium):
 
83
class HttpTransportBase(ConnectedTransport):
82
84
    """Base class for http implementations.
83
85
 
84
86
    Does URL parsing, etc, but not any network IO.
102
104
        self._impl_name = impl_name
103
105
        super(HttpTransportBase, self).__init__(base,
104
106
                                                _from_transport=_from_transport)
 
107
        self._medium = None
105
108
        # range hint is handled dynamically throughout the life
106
109
        # of the transport object. We start by trying multi-range
107
110
        # requests and if the server returns bogus results, we
160
163
                    path=self._path)
161
164
        return auth
162
165
 
163
 
    def get_request(self):
164
 
        return SmartClientHTTPMediumRequest(self)
165
 
 
166
166
    def get_smart_medium(self):
167
 
        """See Transport.get_smart_medium.
 
167
        """See Transport.get_smart_medium."""
 
168
        if self._medium is None:
 
169
            # Since medium holds some state (smart server probing at least), we
 
170
            # need to keep it around. Note that this is needed because medium
 
171
            # has the same 'base' attribute as the transport so it can't be
 
172
            # shared between transports having different bases.
 
173
            self._medium = SmartClientHTTPMedium(self)
 
174
        return self._medium
168
175
 
169
 
        HttpTransportBase directly implements the minimal interface of
170
 
        SmartMediumClient, so this returns self.
171
 
        """
172
 
        return self
173
176
 
174
177
    def _degrade_range_hint(self, relpath, ranges, exc_info):
175
178
        if self._range_hint == 'multi':
230
233
 
231
234
            # Turn it into a list, we will iterate it several times
232
235
            coalesced = list(coalesced)
233
 
            mutter('http readv of %s  offsets => %s collapsed %s',
 
236
            if 'http' in debug.debug_flags:
 
237
                mutter('http readv of %s  offsets => %s collapsed %s',
234
238
                    relpath, len(offsets), len(coalesced))
235
239
 
236
240
            # Cache the data read, but only until it's been used
513
517
 
514
518
        return ','.join(strings)
515
519
 
516
 
    def send_http_smart_request(self, bytes):
517
 
        try:
518
 
            code, body_filelike = self._post(bytes)
519
 
            if code != 200:
520
 
                raise InvalidHttpResponse(
521
 
                    self._remote_path('.bzr/smart'),
522
 
                    'Expected 200 response code, got %r' % (code,))
523
 
        except errors.InvalidHttpResponse, e:
524
 
            raise errors.SmartProtocolError(str(e))
525
 
        return body_filelike
 
520
 
 
521
# TODO: May be better located in smart/medium.py with the other
 
522
# SmartMedium classes
 
523
class SmartClientHTTPMedium(medium.SmartClientMedium):
 
524
 
 
525
    def __init__(self, http_transport):
 
526
        super(SmartClientHTTPMedium, self).__init__(http_transport.base)
 
527
        # We don't want to create a circular reference between the http
 
528
        # transport and its associated medium. Since the transport will live
 
529
        # longer than the medium, the medium keep only a weak reference to its
 
530
        # transport.
 
531
        self._http_transport_ref = weakref.ref(http_transport)
 
532
 
 
533
    def get_request(self):
 
534
        return SmartClientHTTPMediumRequest(self)
526
535
 
527
536
    def should_probe(self):
528
537
        return True
536
545
        rel_url = urlutils.relative_url(self.base, transport_base)
537
546
        return urllib.unquote(rel_url)
538
547
 
539
 
 
 
548
    def send_http_smart_request(self, bytes):
 
549
        try:
 
550
            # Get back the http_transport hold by the weak reference
 
551
            t = self._http_transport_ref()
 
552
            code, body_filelike = t._post(bytes)
 
553
            if code != 200:
 
554
                raise InvalidHttpResponse(
 
555
                    t._remote_path('.bzr/smart'),
 
556
                    'Expected 200 response code, got %r' % (code,))
 
557
        except errors.InvalidHttpResponse, e:
 
558
            raise errors.SmartProtocolError(str(e))
 
559
        return body_filelike
 
560
 
 
561
 
 
562
# TODO: May be better located in smart/medium.py with the other
 
563
# SmartMediumRequest classes
540
564
class SmartClientHTTPMediumRequest(medium.SmartClientMediumRequest):
541
565
    """A SmartClientMediumRequest that works with an HTTP medium."""
542
566
 
552
576
        self._response_body = data
553
577
 
554
578
    def _read_bytes(self, count):
 
579
        """See SmartClientMediumRequest._read_bytes."""
555
580
        return self._response_body.read(count)
556
581
 
 
582
    def _read_line(self):
 
583
        line, excess = medium._get_line(self._response_body.read)
 
584
        if excess != '':
 
585
            raise AssertionError(
 
586
                '_get_line returned excess bytes, but this mediumrequest '
 
587
                'cannot handle excess. (%r)' % (excess,))
 
588
        return line
 
589
 
557
590
    def _finished_reading(self):
558
591
        """See SmartClientMediumRequest._finished_reading."""
559
592
        pass