Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/urllib3/response.py @ 1:56ad4e20f292 draft
"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
author | guerler |
---|---|
date | Fri, 31 Jul 2020 00:32:28 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:d30785e31577 | 1:56ad4e20f292 |
---|---|
1 from __future__ import absolute_import | |
2 from contextlib import contextmanager | |
3 import zlib | |
4 import io | |
5 import logging | |
6 from socket import timeout as SocketTimeout | |
7 from socket import error as SocketError | |
8 | |
9 try: | |
10 import brotli | |
11 except ImportError: | |
12 brotli = None | |
13 | |
14 from ._collections import HTTPHeaderDict | |
15 from .exceptions import ( | |
16 BodyNotHttplibCompatible, | |
17 ProtocolError, | |
18 DecodeError, | |
19 ReadTimeoutError, | |
20 ResponseNotChunked, | |
21 IncompleteRead, | |
22 InvalidHeader, | |
23 HTTPError, | |
24 ) | |
25 from .packages.six import string_types as basestring, PY3 | |
26 from .packages.six.moves import http_client as httplib | |
27 from .connection import HTTPException, BaseSSLError | |
28 from .util.response import is_fp_closed, is_response_to_head | |
29 | |
30 log = logging.getLogger(__name__) | |
31 | |
32 | |
33 class DeflateDecoder(object): | |
34 def __init__(self): | |
35 self._first_try = True | |
36 self._data = b"" | |
37 self._obj = zlib.decompressobj() | |
38 | |
39 def __getattr__(self, name): | |
40 return getattr(self._obj, name) | |
41 | |
42 def decompress(self, data): | |
43 if not data: | |
44 return data | |
45 | |
46 if not self._first_try: | |
47 return self._obj.decompress(data) | |
48 | |
49 self._data += data | |
50 try: | |
51 decompressed = self._obj.decompress(data) | |
52 if decompressed: | |
53 self._first_try = False | |
54 self._data = None | |
55 return decompressed | |
56 except zlib.error: | |
57 self._first_try = False | |
58 self._obj = zlib.decompressobj(-zlib.MAX_WBITS) | |
59 try: | |
60 return self.decompress(self._data) | |
61 finally: | |
62 self._data = None | |
63 | |
64 | |
65 class GzipDecoderState(object): | |
66 | |
67 FIRST_MEMBER = 0 | |
68 OTHER_MEMBERS = 1 | |
69 SWALLOW_DATA = 2 | |
70 | |
71 | |
72 class GzipDecoder(object): | |
73 def __init__(self): | |
74 self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) | |
75 self._state = GzipDecoderState.FIRST_MEMBER | |
76 | |
77 def __getattr__(self, name): | |
78 return getattr(self._obj, name) | |
79 | |
80 def decompress(self, data): | |
81 ret = bytearray() | |
82 if self._state == GzipDecoderState.SWALLOW_DATA or not data: | |
83 return bytes(ret) | |
84 while True: | |
85 try: | |
86 ret += self._obj.decompress(data) | |
87 except zlib.error: | |
88 previous_state = self._state | |
89 # Ignore data after the first error | |
90 self._state = GzipDecoderState.SWALLOW_DATA | |
91 if previous_state == GzipDecoderState.OTHER_MEMBERS: | |
92 # Allow trailing garbage acceptable in other gzip clients | |
93 return bytes(ret) | |
94 raise | |
95 data = self._obj.unused_data | |
96 if not data: | |
97 return bytes(ret) | |
98 self._state = GzipDecoderState.OTHER_MEMBERS | |
99 self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) | |
100 | |
101 | |
102 if brotli is not None: | |
103 | |
104 class BrotliDecoder(object): | |
105 # Supports both 'brotlipy' and 'Brotli' packages | |
106 # since they share an import name. The top branches | |
107 # are for 'brotlipy' and bottom branches for 'Brotli' | |
108 def __init__(self): | |
109 self._obj = brotli.Decompressor() | |
110 if hasattr(self._obj, "decompress"): | |
111 self.decompress = self._obj.decompress | |
112 else: | |
113 self.decompress = self._obj.process | |
114 | |
115 def flush(self): | |
116 if hasattr(self._obj, "flush"): | |
117 return self._obj.flush() | |
118 return b"" | |
119 | |
120 | |
121 class MultiDecoder(object): | |
122 """ | |
123 From RFC7231: | |
124 If one or more encodings have been applied to a representation, the | |
125 sender that applied the encodings MUST generate a Content-Encoding | |
126 header field that lists the content codings in the order in which | |
127 they were applied. | |
128 """ | |
129 | |
130 def __init__(self, modes): | |
131 self._decoders = [_get_decoder(m.strip()) for m in modes.split(",")] | |
132 | |
133 def flush(self): | |
134 return self._decoders[0].flush() | |
135 | |
136 def decompress(self, data): | |
137 for d in reversed(self._decoders): | |
138 data = d.decompress(data) | |
139 return data | |
140 | |
141 | |
142 def _get_decoder(mode): | |
143 if "," in mode: | |
144 return MultiDecoder(mode) | |
145 | |
146 if mode == "gzip": | |
147 return GzipDecoder() | |
148 | |
149 if brotli is not None and mode == "br": | |
150 return BrotliDecoder() | |
151 | |
152 return DeflateDecoder() | |
153 | |
154 | |
155 class HTTPResponse(io.IOBase): | |
156 """ | |
157 HTTP Response container. | |
158 | |
159 Backwards-compatible to httplib's HTTPResponse but the response ``body`` is | |
160 loaded and decoded on-demand when the ``data`` property is accessed. This | |
161 class is also compatible with the Python standard library's :mod:`io` | |
162 module, and can hence be treated as a readable object in the context of that | |
163 framework. | |
164 | |
165 Extra parameters for behaviour not present in httplib.HTTPResponse: | |
166 | |
167 :param preload_content: | |
168 If True, the response's body will be preloaded during construction. | |
169 | |
170 :param decode_content: | |
171 If True, will attempt to decode the body based on the | |
172 'content-encoding' header. | |
173 | |
174 :param original_response: | |
175 When this HTTPResponse wrapper is generated from an httplib.HTTPResponse | |
176 object, it's convenient to include the original for debug purposes. It's | |
177 otherwise unused. | |
178 | |
179 :param retries: | |
180 The retries contains the last :class:`~urllib3.util.retry.Retry` that | |
181 was used during the request. | |
182 | |
183 :param enforce_content_length: | |
184 Enforce content length checking. Body returned by server must match | |
185 value of Content-Length header, if present. Otherwise, raise error. | |
186 """ | |
187 | |
188 CONTENT_DECODERS = ["gzip", "deflate"] | |
189 if brotli is not None: | |
190 CONTENT_DECODERS += ["br"] | |
191 REDIRECT_STATUSES = [301, 302, 303, 307, 308] | |
192 | |
193 def __init__( | |
194 self, | |
195 body="", | |
196 headers=None, | |
197 status=0, | |
198 version=0, | |
199 reason=None, | |
200 strict=0, | |
201 preload_content=True, | |
202 decode_content=True, | |
203 original_response=None, | |
204 pool=None, | |
205 connection=None, | |
206 msg=None, | |
207 retries=None, | |
208 enforce_content_length=False, | |
209 request_method=None, | |
210 request_url=None, | |
211 auto_close=True, | |
212 ): | |
213 | |
214 if isinstance(headers, HTTPHeaderDict): | |
215 self.headers = headers | |
216 else: | |
217 self.headers = HTTPHeaderDict(headers) | |
218 self.status = status | |
219 self.version = version | |
220 self.reason = reason | |
221 self.strict = strict | |
222 self.decode_content = decode_content | |
223 self.retries = retries | |
224 self.enforce_content_length = enforce_content_length | |
225 self.auto_close = auto_close | |
226 | |
227 self._decoder = None | |
228 self._body = None | |
229 self._fp = None | |
230 self._original_response = original_response | |
231 self._fp_bytes_read = 0 | |
232 self.msg = msg | |
233 self._request_url = request_url | |
234 | |
235 if body and isinstance(body, (basestring, bytes)): | |
236 self._body = body | |
237 | |
238 self._pool = pool | |
239 self._connection = connection | |
240 | |
241 if hasattr(body, "read"): | |
242 self._fp = body | |
243 | |
244 # Are we using the chunked-style of transfer encoding? | |
245 self.chunked = False | |
246 self.chunk_left = None | |
247 tr_enc = self.headers.get("transfer-encoding", "").lower() | |
248 # Don't incur the penalty of creating a list and then discarding it | |
249 encodings = (enc.strip() for enc in tr_enc.split(",")) | |
250 if "chunked" in encodings: | |
251 self.chunked = True | |
252 | |
253 # Determine length of response | |
254 self.length_remaining = self._init_length(request_method) | |
255 | |
256 # If requested, preload the body. | |
257 if preload_content and not self._body: | |
258 self._body = self.read(decode_content=decode_content) | |
259 | |
260 def get_redirect_location(self): | |
261 """ | |
262 Should we redirect and where to? | |
263 | |
264 :returns: Truthy redirect location string if we got a redirect status | |
265 code and valid location. ``None`` if redirect status and no | |
266 location. ``False`` if not a redirect status code. | |
267 """ | |
268 if self.status in self.REDIRECT_STATUSES: | |
269 return self.headers.get("location") | |
270 | |
271 return False | |
272 | |
273 def release_conn(self): | |
274 if not self._pool or not self._connection: | |
275 return | |
276 | |
277 self._pool._put_conn(self._connection) | |
278 self._connection = None | |
279 | |
280 def drain_conn(self): | |
281 """ | |
282 Read and discard any remaining HTTP response data in the response connection. | |
283 | |
284 Unread data in the HTTPResponse connection blocks the connection from being released back to the pool. | |
285 """ | |
286 try: | |
287 self.read() | |
288 except (HTTPError, SocketError, BaseSSLError, HTTPException): | |
289 pass | |
290 | |
291 @property | |
292 def data(self): | |
293 # For backwords-compat with earlier urllib3 0.4 and earlier. | |
294 if self._body: | |
295 return self._body | |
296 | |
297 if self._fp: | |
298 return self.read(cache_content=True) | |
299 | |
300 @property | |
301 def connection(self): | |
302 return self._connection | |
303 | |
304 def isclosed(self): | |
305 return is_fp_closed(self._fp) | |
306 | |
307 def tell(self): | |
308 """ | |
309 Obtain the number of bytes pulled over the wire so far. May differ from | |
310 the amount of content returned by :meth:``HTTPResponse.read`` if bytes | |
311 are encoded on the wire (e.g, compressed). | |
312 """ | |
313 return self._fp_bytes_read | |
314 | |
315 def _init_length(self, request_method): | |
316 """ | |
317 Set initial length value for Response content if available. | |
318 """ | |
319 length = self.headers.get("content-length") | |
320 | |
321 if length is not None: | |
322 if self.chunked: | |
323 # This Response will fail with an IncompleteRead if it can't be | |
324 # received as chunked. This method falls back to attempt reading | |
325 # the response before raising an exception. | |
326 log.warning( | |
327 "Received response with both Content-Length and " | |
328 "Transfer-Encoding set. This is expressly forbidden " | |
329 "by RFC 7230 sec 3.3.2. Ignoring Content-Length and " | |
330 "attempting to process response as Transfer-Encoding: " | |
331 "chunked." | |
332 ) | |
333 return None | |
334 | |
335 try: | |
336 # RFC 7230 section 3.3.2 specifies multiple content lengths can | |
337 # be sent in a single Content-Length header | |
338 # (e.g. Content-Length: 42, 42). This line ensures the values | |
339 # are all valid ints and that as long as the `set` length is 1, | |
340 # all values are the same. Otherwise, the header is invalid. | |
341 lengths = set([int(val) for val in length.split(",")]) | |
342 if len(lengths) > 1: | |
343 raise InvalidHeader( | |
344 "Content-Length contained multiple " | |
345 "unmatching values (%s)" % length | |
346 ) | |
347 length = lengths.pop() | |
348 except ValueError: | |
349 length = None | |
350 else: | |
351 if length < 0: | |
352 length = None | |
353 | |
354 # Convert status to int for comparison | |
355 # In some cases, httplib returns a status of "_UNKNOWN" | |
356 try: | |
357 status = int(self.status) | |
358 except ValueError: | |
359 status = 0 | |
360 | |
361 # Check for responses that shouldn't include a body | |
362 if status in (204, 304) or 100 <= status < 200 or request_method == "HEAD": | |
363 length = 0 | |
364 | |
365 return length | |
366 | |
367 def _init_decoder(self): | |
368 """ | |
369 Set-up the _decoder attribute if necessary. | |
370 """ | |
371 # Note: content-encoding value should be case-insensitive, per RFC 7230 | |
372 # Section 3.2 | |
373 content_encoding = self.headers.get("content-encoding", "").lower() | |
374 if self._decoder is None: | |
375 if content_encoding in self.CONTENT_DECODERS: | |
376 self._decoder = _get_decoder(content_encoding) | |
377 elif "," in content_encoding: | |
378 encodings = [ | |
379 e.strip() | |
380 for e in content_encoding.split(",") | |
381 if e.strip() in self.CONTENT_DECODERS | |
382 ] | |
383 if len(encodings): | |
384 self._decoder = _get_decoder(content_encoding) | |
385 | |
386 DECODER_ERROR_CLASSES = (IOError, zlib.error) | |
387 if brotli is not None: | |
388 DECODER_ERROR_CLASSES += (brotli.error,) | |
389 | |
390 def _decode(self, data, decode_content, flush_decoder): | |
391 """ | |
392 Decode the data passed in and potentially flush the decoder. | |
393 """ | |
394 if not decode_content: | |
395 return data | |
396 | |
397 try: | |
398 if self._decoder: | |
399 data = self._decoder.decompress(data) | |
400 except self.DECODER_ERROR_CLASSES as e: | |
401 content_encoding = self.headers.get("content-encoding", "").lower() | |
402 raise DecodeError( | |
403 "Received response with content-encoding: %s, but " | |
404 "failed to decode it." % content_encoding, | |
405 e, | |
406 ) | |
407 if flush_decoder: | |
408 data += self._flush_decoder() | |
409 | |
410 return data | |
411 | |
412 def _flush_decoder(self): | |
413 """ | |
414 Flushes the decoder. Should only be called if the decoder is actually | |
415 being used. | |
416 """ | |
417 if self._decoder: | |
418 buf = self._decoder.decompress(b"") | |
419 return buf + self._decoder.flush() | |
420 | |
421 return b"" | |
422 | |
423 @contextmanager | |
424 def _error_catcher(self): | |
425 """ | |
426 Catch low-level python exceptions, instead re-raising urllib3 | |
427 variants, so that low-level exceptions are not leaked in the | |
428 high-level api. | |
429 | |
430 On exit, release the connection back to the pool. | |
431 """ | |
432 clean_exit = False | |
433 | |
434 try: | |
435 try: | |
436 yield | |
437 | |
438 except SocketTimeout: | |
439 # FIXME: Ideally we'd like to include the url in the ReadTimeoutError but | |
440 # there is yet no clean way to get at it from this context. | |
441 raise ReadTimeoutError(self._pool, None, "Read timed out.") | |
442 | |
443 except BaseSSLError as e: | |
444 # FIXME: Is there a better way to differentiate between SSLErrors? | |
445 if "read operation timed out" not in str(e): # Defensive: | |
446 # This shouldn't happen but just in case we're missing an edge | |
447 # case, let's avoid swallowing SSL errors. | |
448 raise | |
449 | |
450 raise ReadTimeoutError(self._pool, None, "Read timed out.") | |
451 | |
452 except (HTTPException, SocketError) as e: | |
453 # This includes IncompleteRead. | |
454 raise ProtocolError("Connection broken: %r" % e, e) | |
455 | |
456 # If no exception is thrown, we should avoid cleaning up | |
457 # unnecessarily. | |
458 clean_exit = True | |
459 finally: | |
460 # If we didn't terminate cleanly, we need to throw away our | |
461 # connection. | |
462 if not clean_exit: | |
463 # The response may not be closed but we're not going to use it | |
464 # anymore so close it now to ensure that the connection is | |
465 # released back to the pool. | |
466 if self._original_response: | |
467 self._original_response.close() | |
468 | |
469 # Closing the response may not actually be sufficient to close | |
470 # everything, so if we have a hold of the connection close that | |
471 # too. | |
472 if self._connection: | |
473 self._connection.close() | |
474 | |
475 # If we hold the original response but it's closed now, we should | |
476 # return the connection back to the pool. | |
477 if self._original_response and self._original_response.isclosed(): | |
478 self.release_conn() | |
479 | |
480 def read(self, amt=None, decode_content=None, cache_content=False): | |
481 """ | |
482 Similar to :meth:`httplib.HTTPResponse.read`, but with two additional | |
483 parameters: ``decode_content`` and ``cache_content``. | |
484 | |
485 :param amt: | |
486 How much of the content to read. If specified, caching is skipped | |
487 because it doesn't make sense to cache partial content as the full | |
488 response. | |
489 | |
490 :param decode_content: | |
491 If True, will attempt to decode the body based on the | |
492 'content-encoding' header. | |
493 | |
494 :param cache_content: | |
495 If True, will save the returned data such that the same result is | |
496 returned despite of the state of the underlying file object. This | |
497 is useful if you want the ``.data`` property to continue working | |
498 after having ``.read()`` the file object. (Overridden if ``amt`` is | |
499 set.) | |
500 """ | |
501 self._init_decoder() | |
502 if decode_content is None: | |
503 decode_content = self.decode_content | |
504 | |
505 if self._fp is None: | |
506 return | |
507 | |
508 flush_decoder = False | |
509 fp_closed = getattr(self._fp, "closed", False) | |
510 | |
511 with self._error_catcher(): | |
512 if amt is None: | |
513 # cStringIO doesn't like amt=None | |
514 data = self._fp.read() if not fp_closed else b"" | |
515 flush_decoder = True | |
516 else: | |
517 cache_content = False | |
518 data = self._fp.read(amt) if not fp_closed else b"" | |
519 if ( | |
520 amt != 0 and not data | |
521 ): # Platform-specific: Buggy versions of Python. | |
522 # Close the connection when no data is returned | |
523 # | |
524 # This is redundant to what httplib/http.client _should_ | |
525 # already do. However, versions of python released before | |
526 # December 15, 2012 (http://bugs.python.org/issue16298) do | |
527 # not properly close the connection in all cases. There is | |
528 # no harm in redundantly calling close. | |
529 self._fp.close() | |
530 flush_decoder = True | |
531 if self.enforce_content_length and self.length_remaining not in ( | |
532 0, | |
533 None, | |
534 ): | |
535 # This is an edge case that httplib failed to cover due | |
536 # to concerns of backward compatibility. We're | |
537 # addressing it here to make sure IncompleteRead is | |
538 # raised during streaming, so all calls with incorrect | |
539 # Content-Length are caught. | |
540 raise IncompleteRead(self._fp_bytes_read, self.length_remaining) | |
541 | |
542 if data: | |
543 self._fp_bytes_read += len(data) | |
544 if self.length_remaining is not None: | |
545 self.length_remaining -= len(data) | |
546 | |
547 data = self._decode(data, decode_content, flush_decoder) | |
548 | |
549 if cache_content: | |
550 self._body = data | |
551 | |
552 return data | |
553 | |
554 def stream(self, amt=2 ** 16, decode_content=None): | |
555 """ | |
556 A generator wrapper for the read() method. A call will block until | |
557 ``amt`` bytes have been read from the connection or until the | |
558 connection is closed. | |
559 | |
560 :param amt: | |
561 How much of the content to read. The generator will return up to | |
562 much data per iteration, but may return less. This is particularly | |
563 likely when using compressed data. However, the empty string will | |
564 never be returned. | |
565 | |
566 :param decode_content: | |
567 If True, will attempt to decode the body based on the | |
568 'content-encoding' header. | |
569 """ | |
570 if self.chunked and self.supports_chunked_reads(): | |
571 for line in self.read_chunked(amt, decode_content=decode_content): | |
572 yield line | |
573 else: | |
574 while not is_fp_closed(self._fp): | |
575 data = self.read(amt=amt, decode_content=decode_content) | |
576 | |
577 if data: | |
578 yield data | |
579 | |
580 @classmethod | |
581 def from_httplib(ResponseCls, r, **response_kw): | |
582 """ | |
583 Given an :class:`httplib.HTTPResponse` instance ``r``, return a | |
584 corresponding :class:`urllib3.response.HTTPResponse` object. | |
585 | |
586 Remaining parameters are passed to the HTTPResponse constructor, along | |
587 with ``original_response=r``. | |
588 """ | |
589 headers = r.msg | |
590 | |
591 if not isinstance(headers, HTTPHeaderDict): | |
592 if PY3: | |
593 headers = HTTPHeaderDict(headers.items()) | |
594 else: | |
595 # Python 2.7 | |
596 headers = HTTPHeaderDict.from_httplib(headers) | |
597 | |
598 # HTTPResponse objects in Python 3 don't have a .strict attribute | |
599 strict = getattr(r, "strict", 0) | |
600 resp = ResponseCls( | |
601 body=r, | |
602 headers=headers, | |
603 status=r.status, | |
604 version=r.version, | |
605 reason=r.reason, | |
606 strict=strict, | |
607 original_response=r, | |
608 **response_kw | |
609 ) | |
610 return resp | |
611 | |
612 # Backwards-compatibility methods for httplib.HTTPResponse | |
613 def getheaders(self): | |
614 return self.headers | |
615 | |
616 def getheader(self, name, default=None): | |
617 return self.headers.get(name, default) | |
618 | |
619 # Backwards compatibility for http.cookiejar | |
620 def info(self): | |
621 return self.headers | |
622 | |
623 # Overrides from io.IOBase | |
624 def close(self): | |
625 if not self.closed: | |
626 self._fp.close() | |
627 | |
628 if self._connection: | |
629 self._connection.close() | |
630 | |
631 if not self.auto_close: | |
632 io.IOBase.close(self) | |
633 | |
634 @property | |
635 def closed(self): | |
636 if not self.auto_close: | |
637 return io.IOBase.closed.__get__(self) | |
638 elif self._fp is None: | |
639 return True | |
640 elif hasattr(self._fp, "isclosed"): | |
641 return self._fp.isclosed() | |
642 elif hasattr(self._fp, "closed"): | |
643 return self._fp.closed | |
644 else: | |
645 return True | |
646 | |
647 def fileno(self): | |
648 if self._fp is None: | |
649 raise IOError("HTTPResponse has no file to get a fileno from") | |
650 elif hasattr(self._fp, "fileno"): | |
651 return self._fp.fileno() | |
652 else: | |
653 raise IOError( | |
654 "The file-like object this HTTPResponse is wrapped " | |
655 "around has no file descriptor" | |
656 ) | |
657 | |
658 def flush(self): | |
659 if ( | |
660 self._fp is not None | |
661 and hasattr(self._fp, "flush") | |
662 and not getattr(self._fp, "closed", False) | |
663 ): | |
664 return self._fp.flush() | |
665 | |
666 def readable(self): | |
667 # This method is required for `io` module compatibility. | |
668 return True | |
669 | |
670 def readinto(self, b): | |
671 # This method is required for `io` module compatibility. | |
672 temp = self.read(len(b)) | |
673 if len(temp) == 0: | |
674 return 0 | |
675 else: | |
676 b[: len(temp)] = temp | |
677 return len(temp) | |
678 | |
679 def supports_chunked_reads(self): | |
680 """ | |
681 Checks if the underlying file-like object looks like a | |
682 httplib.HTTPResponse object. We do this by testing for the fp | |
683 attribute. If it is present we assume it returns raw chunks as | |
684 processed by read_chunked(). | |
685 """ | |
686 return hasattr(self._fp, "fp") | |
687 | |
688 def _update_chunk_length(self): | |
689 # First, we'll figure out length of a chunk and then | |
690 # we'll try to read it from socket. | |
691 if self.chunk_left is not None: | |
692 return | |
693 line = self._fp.fp.readline() | |
694 line = line.split(b";", 1)[0] | |
695 try: | |
696 self.chunk_left = int(line, 16) | |
697 except ValueError: | |
698 # Invalid chunked protocol response, abort. | |
699 self.close() | |
700 raise httplib.IncompleteRead(line) | |
701 | |
702 def _handle_chunk(self, amt): | |
703 returned_chunk = None | |
704 if amt is None: | |
705 chunk = self._fp._safe_read(self.chunk_left) | |
706 returned_chunk = chunk | |
707 self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. | |
708 self.chunk_left = None | |
709 elif amt < self.chunk_left: | |
710 value = self._fp._safe_read(amt) | |
711 self.chunk_left = self.chunk_left - amt | |
712 returned_chunk = value | |
713 elif amt == self.chunk_left: | |
714 value = self._fp._safe_read(amt) | |
715 self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. | |
716 self.chunk_left = None | |
717 returned_chunk = value | |
718 else: # amt > self.chunk_left | |
719 returned_chunk = self._fp._safe_read(self.chunk_left) | |
720 self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. | |
721 self.chunk_left = None | |
722 return returned_chunk | |
723 | |
724 def read_chunked(self, amt=None, decode_content=None): | |
725 """ | |
726 Similar to :meth:`HTTPResponse.read`, but with an additional | |
727 parameter: ``decode_content``. | |
728 | |
729 :param amt: | |
730 How much of the content to read. If specified, caching is skipped | |
731 because it doesn't make sense to cache partial content as the full | |
732 response. | |
733 | |
734 :param decode_content: | |
735 If True, will attempt to decode the body based on the | |
736 'content-encoding' header. | |
737 """ | |
738 self._init_decoder() | |
739 # FIXME: Rewrite this method and make it a class with a better structured logic. | |
740 if not self.chunked: | |
741 raise ResponseNotChunked( | |
742 "Response is not chunked. " | |
743 "Header 'transfer-encoding: chunked' is missing." | |
744 ) | |
745 if not self.supports_chunked_reads(): | |
746 raise BodyNotHttplibCompatible( | |
747 "Body should be httplib.HTTPResponse like. " | |
748 "It should have have an fp attribute which returns raw chunks." | |
749 ) | |
750 | |
751 with self._error_catcher(): | |
752 # Don't bother reading the body of a HEAD request. | |
753 if self._original_response and is_response_to_head(self._original_response): | |
754 self._original_response.close() | |
755 return | |
756 | |
757 # If a response is already read and closed | |
758 # then return immediately. | |
759 if self._fp.fp is None: | |
760 return | |
761 | |
762 while True: | |
763 self._update_chunk_length() | |
764 if self.chunk_left == 0: | |
765 break | |
766 chunk = self._handle_chunk(amt) | |
767 decoded = self._decode( | |
768 chunk, decode_content=decode_content, flush_decoder=False | |
769 ) | |
770 if decoded: | |
771 yield decoded | |
772 | |
773 if decode_content: | |
774 # On CPython and PyPy, we should never need to flush the | |
775 # decoder. However, on Jython we *might* need to, so | |
776 # lets defensively do it anyway. | |
777 decoded = self._flush_decoder() | |
778 if decoded: # Platform-specific: Jython. | |
779 yield decoded | |
780 | |
781 # Chunk content ends with \r\n: discard it. | |
782 while True: | |
783 line = self._fp.fp.readline() | |
784 if not line: | |
785 # Some sites may not end with '\r\n'. | |
786 break | |
787 if line == b"\r\n": | |
788 break | |
789 | |
790 # We read everything; close the "file". | |
791 if self._original_response: | |
792 self._original_response.close() | |
793 | |
794 def geturl(self): | |
795 """ | |
796 Returns the URL that was the source of this response. | |
797 If the request that generated this response redirected, this method | |
798 will return the final redirect location. | |
799 """ | |
800 if self.retries is not None and len(self.retries.history): | |
801 return self.retries.history[-1].redirect_location | |
802 else: | |
803 return self._request_url | |
804 | |
805 def __iter__(self): | |
806 buffer = [] | |
807 for chunk in self.stream(decode_content=True): | |
808 if b"\n" in chunk: | |
809 chunk = chunk.split(b"\n") | |
810 yield b"".join(buffer) + chunk[0] + b"\n" | |
811 for x in chunk[1:-1]: | |
812 yield x + b"\n" | |
813 if chunk[-1]: | |
814 buffer = [chunk[-1]] | |
815 else: | |
816 buffer = [] | |
817 else: | |
818 buffer.append(chunk) | |
819 if buffer: | |
820 yield b"".join(buffer) |