~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-12-20 16:16:34 UTC
  • mfrom: (3123.5.18 hardlinks)
  • Revision ID: pqm@pqm.ubuntu.com-20071220161634-2kcjb650o21ydko4
Accelerate build_tree using similar workingtrees (abentley)

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
 
24
24
 
25
25
import httplib
26
 
from cStringIO import StringIO
27
 
import rfc822
28
26
 
29
27
from bzrlib import (
30
28
    errors,
31
29
    trace,
32
 
    osutils,
33
30
    )
34
31
 
35
32
 
58
55
    should happen with monotonically increasing offsets.
59
56
    """
60
57
 
61
 
    # in _checked_read() below, we may have to discard several MB in the worst
62
 
    # case. To avoid buffering that much, we read and discard by chunks
63
 
    # instead. The underlying file is either a socket or a StringIO, so reading
64
 
    # 8k chunks should be fine.
65
 
    _discarded_buf_size = 8192
66
 
 
67
 
    # maximum size of read requests -- used to avoid MemoryError issues in recv
68
 
    _max_read_size = 512 * 1024
69
 
 
70
58
    def __init__(self, path, infile):
71
59
        """Constructor.
72
60
 
108
96
            # string entity.
109
97
            # To be on the safe side we allow it before any boundary line
110
98
            boundary_line = self._file.readline()
111
 
 
112
99
        if boundary_line != '--' + self._boundary + '\r\n':
113
 
            # rfc822.unquote() incorrectly unquotes strings enclosed in <>
114
 
            # IIS 6 and 7 incorrectly wrap boundary strings in <>
115
 
            # together they make a beautiful bug, which we will be gracious
116
 
            # about here
117
 
            if (self._unquote_boundary(boundary_line) != 
118
 
                '--' + self._boundary + '\r\n'):
119
 
                raise errors.InvalidHttpResponse(
120
 
                    self._path,
121
 
                    "Expected a boundary (%s) line, got '%s'"
122
 
                    % (self._boundary, boundary_line))
123
 
 
124
 
    def _unquote_boundary(self, b):
125
 
        return b[:2] + rfc822.unquote(b[2:-2]) + b[-2:]
 
100
            raise errors.InvalidHttpResponse(
 
101
                self._path,
 
102
                "Expected a boundary (%s) line, got '%s'" % (self._boundary,
 
103
                                                             boundary_line))
126
104
 
127
105
    def read_range_definition(self):
128
106
        """Read a new range definition in a multi parts message.
167
145
        self.set_range(start, size)
168
146
 
169
147
    def _checked_read(self, size):
170
 
        """Read the file checking for short reads.
171
 
 
172
 
        The data read is discarded along the way.
173
 
        """
 
148
        """Read the file checking for short reads"""
174
149
        pos = self._pos
175
 
        remaining = size
176
 
        while remaining > 0:
177
 
            data = self._file.read(min(remaining, self._discarded_buf_size))
178
 
            remaining -= len(data)
179
 
            if not data:
180
 
                raise errors.ShortReadvError(self._path, pos, size,
181
 
                                             size - remaining)
182
 
        self._pos += size
 
150
        data = self._file.read(size)
 
151
        data_len = len(data)
 
152
        if size > 0 and data_len != size:
 
153
            raise errors.ShortReadvError(self._path, pos, size, data_len)
 
154
        self._pos += data_len
 
155
        return data
183
156
 
184
157
    def _seek_to_next_range(self):
185
158
        # We will cross range boundaries
186
159
        if self._boundary is None:
187
160
            # If we don't have a boundary, we can't find another range
188
 
            raise errors.InvalidRange(self._path, self._pos,
189
 
                                      "Range (%s, %s) exhausted"
190
 
                                      % (self._start, self._size))
 
161
            raise errors.InvalidRange(
 
162
                self._path, self._pos,
 
163
                "Range (%s, %s) exhausted"
 
164
                % (self._start, self._size))
191
165
        self.read_boundary()
192
166
        self.read_range_definition()
193
167
 
198
172
        client to clean the socket if we leave bytes unread. This may occur for
199
173
        the final boundary line of a multipart response or for any range
200
174
        request not entirely consumed by the client (due to offset coalescing)
201
 
 
202
 
        :param size:  The number of bytes to read.  Leave unspecified or pass
203
 
            -1 to read to EOF.
204
175
        """
205
176
        if (self._size > 0
206
177
            and self._pos == self._start + self._size):
220
191
                    "Can't read %s bytes across range (%s, %s)"
221
192
                    % (size, self._start, self._size))
222
193
 
223
 
        # read data from file
224
 
        buffer = StringIO()
225
 
        limited = size
226
194
        if self._size > 0:
227
195
            # Don't read past the range definition
228
196
            limited = self._start + self._size - self._pos
229
197
            if size >= 0:
230
198
                limited = min(limited, size)
231
 
        osutils.pumpfile(self._file, buffer, limited, self._max_read_size)
232
 
        data = buffer.getvalue()
233
 
 
 
199
            data = self._file.read(limited)
 
200
        else:
 
201
            # Size of file unknown, the user may have specified a size or not,
 
202
            # we delegate that to the filesocket object (-1 means read until
 
203
            # EOF)
 
204
            data = self._file.read(size)
234
205
        # Update _pos respecting the data effectively read
235
206
        self._pos += len(data)
236
207
        return data