| OLD | NEW |
| 1 # urllib3/response.py | 1 # urllib3/response.py |
| 2 # Copyright 2008-2012 Andrey Petrov and contributors (see CONTRIBUTORS.txt) | 2 # Copyright 2008-2013 Andrey Petrov and contributors (see CONTRIBUTORS.txt) |
| 3 # | 3 # |
| 4 # This module is part of urllib3 and is released under | 4 # This module is part of urllib3 and is released under |
| 5 # the MIT License: http://www.opensource.org/licenses/mit-license.php | 5 # the MIT License: http://www.opensource.org/licenses/mit-license.php |
| 6 | 6 |
| 7 | 7 |
| 8 import logging | 8 import logging |
| 9 import zlib | 9 import zlib |
| 10 import io |
| 10 | 11 |
| 11 from .exceptions import DecodeError | 12 from .exceptions import DecodeError |
| 12 from .packages.six import string_types as basestring, binary_type | 13 from .packages.six import string_types as basestring, binary_type |
| 14 from .util import is_fp_closed |
| 13 | 15 |
| 14 | 16 |
| 15 log = logging.getLogger(__name__) | 17 log = logging.getLogger(__name__) |
| 16 | 18 |
| 17 | 19 |
| 18 class DeflateDecoder(object): | 20 class DeflateDecoder(object): |
| 19 | 21 |
| 20 def __init__(self): | 22 def __init__(self): |
| 21 self._first_try = True | 23 self._first_try = True |
| 22 self._data = binary_type() | 24 self._data = binary_type() |
| (...skipping 18 matching lines...) Expand all Loading... |
| 41 self._data = None | 43 self._data = None |
| 42 | 44 |
| 43 | 45 |
| 44 def _get_decoder(mode): | 46 def _get_decoder(mode): |
| 45 if mode == 'gzip': | 47 if mode == 'gzip': |
| 46 return zlib.decompressobj(16 + zlib.MAX_WBITS) | 48 return zlib.decompressobj(16 + zlib.MAX_WBITS) |
| 47 | 49 |
| 48 return DeflateDecoder() | 50 return DeflateDecoder() |
| 49 | 51 |
| 50 | 52 |
| 51 class HTTPResponse(object): | 53 class HTTPResponse(io.IOBase): |
| 52 """ | 54 """ |
| 53 HTTP Response container. | 55 HTTP Response container. |
| 54 | 56 |
| 55 Backwards-compatible to httplib's HTTPResponse but the response ``body`` is | 57 Backwards-compatible to httplib's HTTPResponse but the response ``body`` is |
| 56 loaded and decoded on-demand when the ``data`` property is accessed. | 58 loaded and decoded on-demand when the ``data`` property is accessed. |
| 57 | 59 |
| 58 Extra parameters for behaviour not present in httplib.HTTPResponse: | 60 Extra parameters for behaviour not present in httplib.HTTPResponse: |
| 59 | 61 |
| 60 :param preload_content: | 62 :param preload_content: |
| 61 If True, the response's body will be preloaded during construction. | 63 If True, the response's body will be preloaded during construction. |
| 62 | 64 |
| 63 :param decode_content: | 65 :param decode_content: |
| 64 If True, attempts to decode specific content-encoding's based on headers | 66 If True, attempts to decode specific content-encoding's based on headers |
| 65 (like 'gzip' and 'deflate') will be skipped and raw data will be used | 67 (like 'gzip' and 'deflate') will be skipped and raw data will be used |
| 66 instead. | 68 instead. |
| 67 | 69 |
| 68 :param original_response: | 70 :param original_response: |
| 69 When this HTTPResponse wrapper is generated from an httplib.HTTPResponse | 71 When this HTTPResponse wrapper is generated from an httplib.HTTPResponse |
| 70 object, it's convenient to include the original for debug purposes. It's | 72 object, it's convenient to include the original for debug purposes. It's |
| 71 otherwise unused. | 73 otherwise unused. |
| 72 """ | 74 """ |
| 73 | 75 |
| 74 CONTENT_DECODERS = ['gzip', 'deflate'] | 76 CONTENT_DECODERS = ['gzip', 'deflate'] |
| 77 REDIRECT_STATUSES = [301, 302, 303, 307, 308] |
| 75 | 78 |
| 76 def __init__(self, body='', headers=None, status=0, version=0, reason=None, | 79 def __init__(self, body='', headers=None, status=0, version=0, reason=None, |
| 77 strict=0, preload_content=True, decode_content=True, | 80 strict=0, preload_content=True, decode_content=True, |
| 78 original_response=None, pool=None, connection=None): | 81 original_response=None, pool=None, connection=None): |
| 79 self.headers = headers or {} | 82 self.headers = headers or {} |
| 80 self.status = status | 83 self.status = status |
| 81 self.version = version | 84 self.version = version |
| 82 self.reason = reason | 85 self.reason = reason |
| 83 self.strict = strict | 86 self.strict = strict |
| 84 self.decode_content = decode_content | 87 self.decode_content = decode_content |
| (...skipping 13 matching lines...) Expand all Loading... |
| 98 self._body = self.read(decode_content=decode_content) | 101 self._body = self.read(decode_content=decode_content) |
| 99 | 102 |
| 100 def get_redirect_location(self): | 103 def get_redirect_location(self): |
| 101 """ | 104 """ |
| 102 Should we redirect and where to? | 105 Should we redirect and where to? |
| 103 | 106 |
| 104 :returns: Truthy redirect location string if we got a redirect status | 107 :returns: Truthy redirect location string if we got a redirect status |
| 105 code and valid location. ``None`` if redirect status and no | 108 code and valid location. ``None`` if redirect status and no |
| 106 location. ``False`` if not a redirect status code. | 109 location. ``False`` if not a redirect status code. |
| 107 """ | 110 """ |
| 108 if self.status in [301, 302, 303, 307]: | 111 if self.status in self.REDIRECT_STATUSES: |
| 109 return self.headers.get('location') | 112 return self.headers.get('location') |
| 110 | 113 |
| 111 return False | 114 return False |
| 112 | 115 |
| 113 def release_conn(self): | 116 def release_conn(self): |
| 114 if not self._pool or not self._connection: | 117 if not self._pool or not self._connection: |
| 115 return | 118 return |
| 116 | 119 |
| 117 self._pool._put_conn(self._connection) | 120 self._pool._put_conn(self._connection) |
| 118 self._connection = None | 121 self._connection = None |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 176 # already do. However, versions of python released before | 179 # already do. However, versions of python released before |
| 177 # December 15, 2012 (http://bugs.python.org/issue16298) do n
ot | 180 # December 15, 2012 (http://bugs.python.org/issue16298) do n
ot |
| 178 # properly close the connection in all cases. There is no ha
rm | 181 # properly close the connection in all cases. There is no ha
rm |
| 179 # in redundantly calling close. | 182 # in redundantly calling close. |
| 180 self._fp.close() | 183 self._fp.close() |
| 181 flush_decoder = True | 184 flush_decoder = True |
| 182 | 185 |
| 183 try: | 186 try: |
| 184 if decode_content and self._decoder: | 187 if decode_content and self._decoder: |
| 185 data = self._decoder.decompress(data) | 188 data = self._decoder.decompress(data) |
| 186 except (IOError, zlib.error): | 189 except (IOError, zlib.error) as e: |
| 187 raise DecodeError("Received response with content-encoding: %s,
but " | 190 raise DecodeError( |
| 188 "failed to decode it." % content_encoding) | 191 "Received response with content-encoding: %s, but " |
| 192 "failed to decode it." % content_encoding, |
| 193 e) |
| 189 | 194 |
| 190 if flush_decoder and self._decoder: | 195 if flush_decoder and decode_content and self._decoder: |
| 191 buf = self._decoder.decompress(binary_type()) | 196 buf = self._decoder.decompress(binary_type()) |
| 192 data += buf + self._decoder.flush() | 197 data += buf + self._decoder.flush() |
| 193 | 198 |
| 194 if cache_content: | 199 if cache_content: |
| 195 self._body = data | 200 self._body = data |
| 196 | 201 |
| 197 return data | 202 return data |
| 198 | 203 |
| 199 finally: | 204 finally: |
| 200 if self._original_response and self._original_response.isclosed(): | 205 if self._original_response and self._original_response.isclosed(): |
| 201 self.release_conn() | 206 self.release_conn() |
| 202 | 207 |
| 208 def stream(self, amt=2**16, decode_content=None): |
| 209 """ |
| 210 A generator wrapper for the read() method. A call will block until |
| 211 ``amt`` bytes have been read from the connection or until the |
| 212 connection is closed. |
| 213 |
| 214 :param amt: |
| 215 How much of the content to read. The generator will return up to |
| 216 much data per iteration, but may return less. This is particularly |
| 217 likely when using compressed data. However, the empty string will |
| 218 never be returned. |
| 219 |
| 220 :param decode_content: |
| 221 If True, will attempt to decode the body based on the |
| 222 'content-encoding' header. |
| 223 """ |
| 224 while not is_fp_closed(self._fp): |
| 225 data = self.read(amt=amt, decode_content=decode_content) |
| 226 |
| 227 if data: |
| 228 yield data |
| 229 |
| 230 |
| 203 @classmethod | 231 @classmethod |
| 204 def from_httplib(ResponseCls, r, **response_kw): | 232 def from_httplib(ResponseCls, r, **response_kw): |
| 205 """ | 233 """ |
| 206 Given an :class:`httplib.HTTPResponse` instance ``r``, return a | 234 Given an :class:`httplib.HTTPResponse` instance ``r``, return a |
| 207 corresponding :class:`urllib3.response.HTTPResponse` object. | 235 corresponding :class:`urllib3.response.HTTPResponse` object. |
| 208 | 236 |
| 209 Remaining parameters are passed to the HTTPResponse constructor, along | 237 Remaining parameters are passed to the HTTPResponse constructor, along |
| 210 with ``original_response=r``. | 238 with ``original_response=r``. |
| 211 """ | 239 """ |
| 212 | 240 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 232 strict=strict, | 260 strict=strict, |
| 233 original_response=r, | 261 original_response=r, |
| 234 **response_kw) | 262 **response_kw) |
| 235 | 263 |
| 236 # Backwards-compatibility methods for httplib.HTTPResponse | 264 # Backwards-compatibility methods for httplib.HTTPResponse |
| 237 def getheaders(self): | 265 def getheaders(self): |
| 238 return self.headers | 266 return self.headers |
| 239 | 267 |
| 240 def getheader(self, name, default=None): | 268 def getheader(self, name, default=None): |
| 241 return self.headers.get(name, default) | 269 return self.headers.get(name, default) |
| 270 |
| 271 # Overrides from io.IOBase |
| 272 def close(self): |
| 273 if not self.closed: |
| 274 self._fp.close() |
| 275 |
| 276 @property |
| 277 def closed(self): |
| 278 if self._fp is None: |
| 279 return True |
| 280 elif hasattr(self._fp, 'closed'): |
| 281 return self._fp.closed |
| 282 elif hasattr(self._fp, 'isclosed'): # Python 2 |
| 283 return self._fp.isclosed() |
| 284 else: |
| 285 return True |
| 286 |
| 287 def fileno(self): |
| 288 if self._fp is None: |
| 289 raise IOError("HTTPResponse has no file to get a fileno from") |
| 290 elif hasattr(self._fp, "fileno"): |
| 291 return self._fp.fileno() |
| 292 else: |
| 293 raise IOError("The file-like object this HTTPResponse is wrapped " |
| 294 "around has no file descriptor") |
| 295 |
| 296 def flush(self): |
| 297 if self._fp is not None and hasattr(self._fp, 'flush'): |
| 298 return self._fp.flush() |
| 299 |
| 300 def readable(self): |
| 301 return True |
| OLD | NEW |