~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Eric Holmberg
  • Date: 2008-05-06 15:02:27 UTC
  • mto: This revision was merged to the branch mainline in revision 3449.
  • Revision ID: eholmberg@arrow.com-20080506150227-l3arq1yntdvnoxum
Fix for Bug #215426 in which bzr can cause a MemoryError in socket.recv while
downloading large packs over http.  This patch limits the request size for
socket.recv to avoid this problem.

Changes:
Added mock file object bzrlib.tests.file_utils.
Added new parameters to bzrlib.osutils.pumpfile.
Added unit tests for bzrlib.osutils.pumpfile.
Added usage of bzrlib.osutils.pumpfile to bzrlib.transport.http.response.

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
26
27
 
27
28
from bzrlib import (
28
29
    errors,
29
30
    trace,
 
31
    osutils,
30
32
    )
31
33
 
32
34
 
61
63
    # 8k chunks should be fine.
62
64
    _discarded_buf_size = 8192
63
65
 
 
66
    # maximum size of read requests -- used to avoid MemoryError issues in recv
 
67
    _max_read_size = 512 * 1024
 
68
 
64
69
    def __init__(self, path, infile):
65
70
        """Constructor.
66
71
 
176
181
        self.read_range_definition()
177
182
 
178
183
    def read(self, size=-1):
179
 
        """Read size bytes from the current position in the file.
 
184
        """Read size bytes from the current position in the file.  Use size=-1
 
185
        to read to EOF.
180
186
 
181
187
        Reading across ranges is not supported. We rely on the underlying http
182
188
        client to clean the socket if we leave bytes unread. This may occur for
201
207
                    "Can't read %s bytes across range (%s, %s)"
202
208
                    % (size, self._start, self._size))
203
209
 
 
210
        # read data from file
 
211
        buffer = StringIO()
 
212
        limited = size
204
213
        if self._size > 0:
205
214
            # Don't read past the range definition
206
215
            limited = self._start + self._size - self._pos
207
216
            if size >= 0:
208
217
                limited = min(limited, size)
209
 
            data = self._file.read(limited)
210
 
        else:
211
 
            # Size of file unknown, the user may have specified a size or not,
212
 
            # we delegate that to the filesocket object (-1 means read until
213
 
            # EOF)
214
 
            data = self._file.read(size)
 
218
        osutils.pumpfile(self._file, buffer, limited, self._max_read_size)
 
219
        data = buffer.getvalue()
 
220
 
215
221
        # Update _pos respecting the data effectively read
216
222
        self._pos += len(data)
217
223
        return data