comparison tests/testlib/badserverext.py @ 48613:b060e305d79f

test-http-bad-server: factor code dealing with "read" in the new object This will make sure both `read` and `readline` do the same processing and make it simpler to update that processing in the future. Differential Revision: https://phab.mercurial-scm.org/D12044
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Fri, 21 Jan 2022 03:05:43 +0100
parents 11e5cb170d36
children 3efc8644dd00
comparison
equal deleted inserted replaced
48612:11e5cb170d36 48613:b060e305d79f
144 object.__getattribute__(obj, '_cond_close')() 144 object.__getattribute__(obj, '_cond_close')()
145 raise Exception('connection closed after sending N bytes') 145 raise Exception('connection closed after sending N bytes')
146 146
147 return result 147 return result
148 148
149 def forward_read(self, obj, method, size=-1):
150 """call an underlying read function until condition are met
151
152 When the condition are met the socket is closed
153 """
154 remaining = self.remaining_recv_bytes
155
156 orig = object.__getattribute__(obj, '_orig')
157 bmethod = method.encode('ascii')
158 func = getattr(orig, method)
159
160 # No read limit. Call original function.
161 if not remaining:
162 result = func(size)
163 obj._writelog(
164 b'%s(%d) -> (%d) %s' % (bmethod, size, len(result), result)
165 )
166 return result
167
168 origsize = size
169
170 if size < 0:
171 size = remaining
172 else:
173 size = min(remaining, size)
174
175 result = func(size)
176 remaining -= len(result)
177
178 obj._writelog(
179 b'%s(%d from %d) -> (%d) %s'
180 % (bmethod, size, origsize, len(result), result)
181 )
182
183 self.remaining_recv_bytes = remaining
184
185 if remaining <= 0:
186 obj._writelog(b'read limit reached; closing socket')
187 obj._cond_close()
188
189 # This is the easiest way to abort the current request.
190 raise Exception('connection closed after receiving N bytes')
191
192 return result
193
149 194
150 # We can't adjust __class__ on a socket instance. So we define a proxy type. 195 # We can't adjust __class__ on a socket instance. So we define a proxy type.
151 class socketproxy(object): 196 class socketproxy(object):
152 __slots__ = ('_orig', '_logfp', '_cond') 197 __slots__ = ('_orig', '_logfp', '_cond')
153 198
238 self.close() 283 self.close()
239 else: 284 else:
240 self._sock.shutdown(socket.SHUT_RDWR) 285 self._sock.shutdown(socket.SHUT_RDWR)
241 286
242 def read(self, size=-1): 287 def read(self, size=-1):
243 remaining = object.__getattribute__(self, '_cond').remaining_recv_bytes 288 cond = object.__getattribute__(self, '_cond')
244 289 return cond.forward_read(self, 'read', size)
245 # No read limit. Call original function.
246 if not remaining:
247 result = object.__getattribute__(self, '_orig').read(size)
248 self._writelog(
249 b'read(%d) -> (%d) (%s) %s' % (size, len(result), result)
250 )
251 return result
252
253 origsize = size
254
255 if size < 0:
256 size = remaining
257 else:
258 size = min(remaining, size)
259
260 result = object.__getattribute__(self, '_orig').read(size)
261 remaining -= len(result)
262
263 self._writelog(
264 b'read(%d from %d) -> (%d) %s'
265 % (size, origsize, len(result), result)
266 )
267
268 object.__getattribute__(self, '_cond').remaining_recv_bytes = remaining
269
270 if remaining <= 0:
271 self._writelog(b'read limit reached; closing socket')
272 self._close()
273
274 # This is the easiest way to abort the current request.
275 raise Exception('connection closed after receiving N bytes')
276
277 return result
278 290
279 def readline(self, size=-1): 291 def readline(self, size=-1):
280 remaining = object.__getattribute__(self, '_cond').remaining_recv_bytes 292 cond = object.__getattribute__(self, '_cond')
281 293 return cond.forward_read(self, 'readline', size)
282 # No read limit. Call original function.
283 if not remaining:
284 result = object.__getattribute__(self, '_orig').readline(size)
285 self._writelog(
286 b'readline(%d) -> (%d) %s' % (size, len(result), result)
287 )
288 return result
289
290 origsize = size
291
292 if size < 0:
293 size = remaining
294 else:
295 size = min(remaining, size)
296
297 result = object.__getattribute__(self, '_orig').readline(size)
298 remaining -= len(result)
299
300 self._writelog(
301 b'readline(%d from %d) -> (%d) %s'
302 % (size, origsize, len(result), result)
303 )
304
305 object.__getattribute__(self, '_cond').remaining_recv_bytes = remaining
306
307 if remaining <= 0:
308 self._writelog(b'read limit reached; closing socket')
309 self._close()
310
311 # This is the easiest way to abort the current request.
312 raise Exception('connection closed after receiving N bytes')
313
314 return result
315 294
316 def write(self, data): 295 def write(self, data):
317 cond = object.__getattribute__(self, '_cond') 296 cond = object.__getattribute__(self, '_cond')
318 return cond.forward_write(self, 'write', data) 297 return cond.forward_write(self, 'write', data)
319 298