Mercurial > hg
comparison mercurial/httpclient/_readers.py @ 19182:fae47ecaa952
httpclient: upgrade to fe8c09e4db64 of httpplus
author | Augie Fackler <raf@durin42.com> |
---|---|
date | Sat, 11 May 2013 20:25:15 -0500 |
parents | 36733ab7fa05 |
children | 1ad9da968a2e |
comparison
equal
deleted
inserted
replaced
19181:8c2fdf7d5645 | 19182:fae47ecaa952 |
---|---|
31 This module is package-private. It is not expected that these will | 31 This module is package-private. It is not expected that these will |
32 have any clients outside of httpplus. | 32 have any clients outside of httpplus. |
33 """ | 33 """ |
34 | 34 |
35 import httplib | 35 import httplib |
36 import itertools | |
37 import logging | 36 import logging |
38 | 37 |
39 logger = logging.getLogger(__name__) | 38 logger = logging.getLogger(__name__) |
40 | 39 |
41 | 40 |
57 def __init__(self): | 56 def __init__(self): |
58 self._finished = False | 57 self._finished = False |
59 self._done_chunks = [] | 58 self._done_chunks = [] |
60 self.available_data = 0 | 59 self.available_data = 0 |
61 | 60 |
62 def addchunk(self, data): | 61 def _addchunk(self, data): |
63 self._done_chunks.append(data) | 62 self._done_chunks.append(data) |
64 self.available_data += len(data) | 63 self.available_data += len(data) |
65 | 64 |
66 def pushchunk(self, data): | 65 def _pushchunk(self, data): |
67 self._done_chunks.insert(0, data) | 66 self._done_chunks.insert(0, data) |
68 self.available_data += len(data) | 67 self.available_data += len(data) |
69 | 68 |
70 def popchunk(self): | 69 def _popchunk(self): |
71 b = self._done_chunks.pop(0) | 70 b = self._done_chunks.pop(0) |
72 self.available_data -= len(b) | 71 self.available_data -= len(b) |
73 | 72 |
74 return b | 73 return b |
75 | 74 |
76 def done(self): | 75 def done(self): |
76 """Returns true if the response body is entirely read.""" | |
77 return self._finished | 77 return self._finished |
78 | 78 |
79 def read(self, amt): | 79 def read(self, amt): |
80 """Read amt bytes from the response body.""" | |
80 if self.available_data < amt and not self._finished: | 81 if self.available_data < amt and not self._finished: |
81 raise ReadNotReady() | 82 raise ReadNotReady() |
82 blocks = [] | 83 blocks = [] |
83 need = amt | 84 need = amt |
84 while self._done_chunks: | 85 while self._done_chunks: |
85 b = self.popchunk() | 86 b = self._popchunk() |
86 if len(b) > need: | 87 if len(b) > need: |
87 nb = b[:need] | 88 nb = b[:need] |
88 self.pushchunk(b[need:]) | 89 self._pushchunk(b[need:]) |
89 b = nb | 90 b = nb |
90 blocks.append(b) | 91 blocks.append(b) |
91 need -= len(b) | 92 need -= len(b) |
92 if need == 0: | 93 if need == 0: |
93 break | 94 break |
105 """ | 106 """ |
106 if blocks is None: | 107 if blocks is None: |
107 blocks = [] | 108 blocks = [] |
108 | 109 |
109 while self._done_chunks: | 110 while self._done_chunks: |
110 b = self.popchunk() | 111 b = self._popchunk() |
111 i = b.find(delimstr) + len(delimstr) | 112 i = b.find(delimstr) + len(delimstr) |
112 if i: | 113 if i: |
113 if i < len(b): | 114 if i < len(b): |
114 self.pushchunk(b[i:]) | 115 self._pushchunk(b[i:]) |
115 blocks.append(b[:i]) | 116 blocks.append(b[:i]) |
116 break | 117 break |
117 else: | 118 else: |
118 blocks.append(b) | 119 blocks.append(b) |
119 | 120 |
152 """ | 153 """ |
153 def _load(self, data): | 154 def _load(self, data): |
154 if data: | 155 if data: |
155 assert not self._finished, ( | 156 assert not self._finished, ( |
156 'tried to add data (%r) to a closed reader!' % data) | 157 'tried to add data (%r) to a closed reader!' % data) |
157 logger.debug('%s read an additional %d data', self.name, len(data)) | 158 logger.debug('%s read an additional %d data', |
158 self.addchunk(data) | 159 self.name, len(data)) # pylint: disable=E1101 |
160 self._addchunk(data) | |
159 | 161 |
160 | 162 |
161 class CloseIsEndReader(AbstractSimpleReader): | 163 class CloseIsEndReader(AbstractSimpleReader): |
162 """Reader for responses that specify Connection: Close for length.""" | 164 """Reader for responses that specify Connection: Close for length.""" |
163 name = 'close-is-end' | 165 name = 'close-is-end' |
170 class ContentLengthReader(AbstractSimpleReader): | 172 class ContentLengthReader(AbstractSimpleReader): |
171 """Reader for responses that specify an exact content length.""" | 173 """Reader for responses that specify an exact content length.""" |
172 name = 'content-length' | 174 name = 'content-length' |
173 | 175 |
174 def __init__(self, amount): | 176 def __init__(self, amount): |
175 AbstractReader.__init__(self) | 177 AbstractSimpleReader.__init__(self) |
176 self._amount = amount | 178 self._amount = amount |
177 if amount == 0: | 179 if amount == 0: |
178 self._finished = True | 180 self._finished = True |
179 self._amount_seen = 0 | 181 self._amount_seen = 0 |
180 | 182 |
197 def _load(self, data): | 199 def _load(self, data): |
198 assert not self._finished, 'tried to add data to a closed reader!' | 200 assert not self._finished, 'tried to add data to a closed reader!' |
199 logger.debug('chunked read an additional %d data', len(data)) | 201 logger.debug('chunked read an additional %d data', len(data)) |
200 position = 0 | 202 position = 0 |
201 if self._leftover_data: | 203 if self._leftover_data: |
202 logger.debug('chunked reader trying to finish block from leftover data') | 204 logger.debug( |
205 'chunked reader trying to finish block from leftover data') | |
203 # TODO: avoid this string concatenation if possible | 206 # TODO: avoid this string concatenation if possible |
204 data = self._leftover_data + data | 207 data = self._leftover_data + data |
205 position = self._leftover_skip_amt | 208 position = self._leftover_skip_amt |
206 self._leftover_data = '' | 209 self._leftover_data = '' |
207 self._leftover_skip_amt = 0 | 210 self._leftover_skip_amt = 0 |
222 return | 225 return |
223 if amt == 0: | 226 if amt == 0: |
224 self._finished = True | 227 self._finished = True |
225 logger.debug('closing chunked reader due to chunk of length 0') | 228 logger.debug('closing chunked reader due to chunk of length 0') |
226 return | 229 return |
227 self.addchunk(data[block_start:block_start + amt]) | 230 self._addchunk(data[block_start:block_start + amt]) |
228 position = block_start + amt + len(self._eol) | 231 position = block_start + amt + len(self._eol) |
229 # no-check-code | 232 # no-check-code |