Mercurial > repos > bcclaywell > argo_navis
comparison venv/lib/python2.7/site-packages/requests/packages/urllib3/response.py @ 0:d67268158946 draft
planemo upload commit a3f181f5f126803c654b3a66dd4e83a48f7e203b
author | bcclaywell |
---|---|
date | Mon, 12 Oct 2015 17:43:33 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:d67268158946 |
---|---|
1 from contextlib import contextmanager | |
2 import zlib | |
3 import io | |
4 from socket import timeout as SocketTimeout | |
5 | |
6 from ._collections import HTTPHeaderDict | |
7 from .exceptions import ( | |
8 ProtocolError, DecodeError, ReadTimeoutError, ResponseNotChunked | |
9 ) | |
10 from .packages.six import string_types as basestring, binary_type, PY3 | |
11 from .packages.six.moves import http_client as httplib | |
12 from .connection import HTTPException, BaseSSLError | |
13 from .util.response import is_fp_closed, is_response_to_head | |
14 | |
15 | |
16 class DeflateDecoder(object): | |
17 | |
18 def __init__(self): | |
19 self._first_try = True | |
20 self._data = binary_type() | |
21 self._obj = zlib.decompressobj() | |
22 | |
23 def __getattr__(self, name): | |
24 return getattr(self._obj, name) | |
25 | |
26 def decompress(self, data): | |
27 if not data: | |
28 return data | |
29 | |
30 if not self._first_try: | |
31 return self._obj.decompress(data) | |
32 | |
33 self._data += data | |
34 try: | |
35 return self._obj.decompress(data) | |
36 except zlib.error: | |
37 self._first_try = False | |
38 self._obj = zlib.decompressobj(-zlib.MAX_WBITS) | |
39 try: | |
40 return self.decompress(self._data) | |
41 finally: | |
42 self._data = None | |
43 | |
44 | |
45 class GzipDecoder(object): | |
46 | |
47 def __init__(self): | |
48 self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) | |
49 | |
50 def __getattr__(self, name): | |
51 return getattr(self._obj, name) | |
52 | |
53 def decompress(self, data): | |
54 if not data: | |
55 return data | |
56 return self._obj.decompress(data) | |
57 | |
58 | |
59 def _get_decoder(mode): | |
60 if mode == 'gzip': | |
61 return GzipDecoder() | |
62 | |
63 return DeflateDecoder() | |
64 | |
65 | |
66 class HTTPResponse(io.IOBase): | |
67 """ | |
68 HTTP Response container. | |
69 | |
70 Backwards-compatible to httplib's HTTPResponse but the response ``body`` is | |
71 loaded and decoded on-demand when the ``data`` property is accessed. This | |
72 class is also compatible with the Python standard library's :mod:`io` | |
73 module, and can hence be treated as a readable object in the context of that | |
74 framework. | |
75 | |
76 Extra parameters for behaviour not present in httplib.HTTPResponse: | |
77 | |
78 :param preload_content: | |
79 If True, the response's body will be preloaded during construction. | |
80 | |
81 :param decode_content: | |
82 If True, attempts to decode specific content-encoding's based on headers | |
83 (like 'gzip' and 'deflate') will be skipped and raw data will be used | |
84 instead. | |
85 | |
86 :param original_response: | |
87 When this HTTPResponse wrapper is generated from an httplib.HTTPResponse | |
88 object, it's convenient to include the original for debug purposes. It's | |
89 otherwise unused. | |
90 """ | |
91 | |
92 CONTENT_DECODERS = ['gzip', 'deflate'] | |
93 REDIRECT_STATUSES = [301, 302, 303, 307, 308] | |
94 | |
95 def __init__(self, body='', headers=None, status=0, version=0, reason=None, | |
96 strict=0, preload_content=True, decode_content=True, | |
97 original_response=None, pool=None, connection=None): | |
98 | |
99 if isinstance(headers, HTTPHeaderDict): | |
100 self.headers = headers | |
101 else: | |
102 self.headers = HTTPHeaderDict(headers) | |
103 self.status = status | |
104 self.version = version | |
105 self.reason = reason | |
106 self.strict = strict | |
107 self.decode_content = decode_content | |
108 | |
109 self._decoder = None | |
110 self._body = None | |
111 self._fp = None | |
112 self._original_response = original_response | |
113 self._fp_bytes_read = 0 | |
114 | |
115 if body and isinstance(body, (basestring, binary_type)): | |
116 self._body = body | |
117 | |
118 self._pool = pool | |
119 self._connection = connection | |
120 | |
121 if hasattr(body, 'read'): | |
122 self._fp = body | |
123 | |
124 # Are we using the chunked-style of transfer encoding? | |
125 self.chunked = False | |
126 self.chunk_left = None | |
127 tr_enc = self.headers.get('transfer-encoding', '').lower() | |
128 # Don't incur the penalty of creating a list and then discarding it | |
129 encodings = (enc.strip() for enc in tr_enc.split(",")) | |
130 if "chunked" in encodings: | |
131 self.chunked = True | |
132 | |
133 # We certainly don't want to preload content when the response is chunked. | |
134 if not self.chunked and preload_content and not self._body: | |
135 self._body = self.read(decode_content=decode_content) | |
136 | |
137 def get_redirect_location(self): | |
138 """ | |
139 Should we redirect and where to? | |
140 | |
141 :returns: Truthy redirect location string if we got a redirect status | |
142 code and valid location. ``None`` if redirect status and no | |
143 location. ``False`` if not a redirect status code. | |
144 """ | |
145 if self.status in self.REDIRECT_STATUSES: | |
146 return self.headers.get('location') | |
147 | |
148 return False | |
149 | |
150 def release_conn(self): | |
151 if not self._pool or not self._connection: | |
152 return | |
153 | |
154 self._pool._put_conn(self._connection) | |
155 self._connection = None | |
156 | |
157 @property | |
158 def data(self): | |
159 # For backwords-compat with earlier urllib3 0.4 and earlier. | |
160 if self._body: | |
161 return self._body | |
162 | |
163 if self._fp: | |
164 return self.read(cache_content=True) | |
165 | |
166 def tell(self): | |
167 """ | |
168 Obtain the number of bytes pulled over the wire so far. May differ from | |
169 the amount of content returned by :meth:``HTTPResponse.read`` if bytes | |
170 are encoded on the wire (e.g, compressed). | |
171 """ | |
172 return self._fp_bytes_read | |
173 | |
174 def _init_decoder(self): | |
175 """ | |
176 Set-up the _decoder attribute if necessar. | |
177 """ | |
178 # Note: content-encoding value should be case-insensitive, per RFC 7230 | |
179 # Section 3.2 | |
180 content_encoding = self.headers.get('content-encoding', '').lower() | |
181 if self._decoder is None and content_encoding in self.CONTENT_DECODERS: | |
182 self._decoder = _get_decoder(content_encoding) | |
183 | |
184 def _decode(self, data, decode_content, flush_decoder): | |
185 """ | |
186 Decode the data passed in and potentially flush the decoder. | |
187 """ | |
188 try: | |
189 if decode_content and self._decoder: | |
190 data = self._decoder.decompress(data) | |
191 except (IOError, zlib.error) as e: | |
192 content_encoding = self.headers.get('content-encoding', '').lower() | |
193 raise DecodeError( | |
194 "Received response with content-encoding: %s, but " | |
195 "failed to decode it." % content_encoding, e) | |
196 | |
197 if flush_decoder and decode_content and self._decoder: | |
198 buf = self._decoder.decompress(binary_type()) | |
199 data += buf + self._decoder.flush() | |
200 | |
201 return data | |
202 | |
203 @contextmanager | |
204 def _error_catcher(self): | |
205 """ | |
206 Catch low-level python exceptions, instead re-raising urllib3 | |
207 variants, so that low-level exceptions are not leaked in the | |
208 high-level api. | |
209 | |
210 On exit, release the connection back to the pool. | |
211 """ | |
212 try: | |
213 try: | |
214 yield | |
215 | |
216 except SocketTimeout: | |
217 # FIXME: Ideally we'd like to include the url in the ReadTimeoutError but | |
218 # there is yet no clean way to get at it from this context. | |
219 raise ReadTimeoutError(self._pool, None, 'Read timed out.') | |
220 | |
221 except BaseSSLError as e: | |
222 # FIXME: Is there a better way to differentiate between SSLErrors? | |
223 if 'read operation timed out' not in str(e): # Defensive: | |
224 # This shouldn't happen but just in case we're missing an edge | |
225 # case, let's avoid swallowing SSL errors. | |
226 raise | |
227 | |
228 raise ReadTimeoutError(self._pool, None, 'Read timed out.') | |
229 | |
230 except HTTPException as e: | |
231 # This includes IncompleteRead. | |
232 raise ProtocolError('Connection broken: %r' % e, e) | |
233 except Exception: | |
234 # The response may not be closed but we're not going to use it anymore | |
235 # so close it now to ensure that the connection is released back to the pool. | |
236 if self._original_response and not self._original_response.isclosed(): | |
237 self._original_response.close() | |
238 | |
239 raise | |
240 finally: | |
241 if self._original_response and self._original_response.isclosed(): | |
242 self.release_conn() | |
243 | |
244 def read(self, amt=None, decode_content=None, cache_content=False): | |
245 """ | |
246 Similar to :meth:`httplib.HTTPResponse.read`, but with two additional | |
247 parameters: ``decode_content`` and ``cache_content``. | |
248 | |
249 :param amt: | |
250 How much of the content to read. If specified, caching is skipped | |
251 because it doesn't make sense to cache partial content as the full | |
252 response. | |
253 | |
254 :param decode_content: | |
255 If True, will attempt to decode the body based on the | |
256 'content-encoding' header. | |
257 | |
258 :param cache_content: | |
259 If True, will save the returned data such that the same result is | |
260 returned despite of the state of the underlying file object. This | |
261 is useful if you want the ``.data`` property to continue working | |
262 after having ``.read()`` the file object. (Overridden if ``amt`` is | |
263 set.) | |
264 """ | |
265 self._init_decoder() | |
266 if decode_content is None: | |
267 decode_content = self.decode_content | |
268 | |
269 if self._fp is None: | |
270 return | |
271 | |
272 flush_decoder = False | |
273 data = None | |
274 | |
275 with self._error_catcher(): | |
276 if amt is None: | |
277 # cStringIO doesn't like amt=None | |
278 data = self._fp.read() | |
279 flush_decoder = True | |
280 else: | |
281 cache_content = False | |
282 data = self._fp.read(amt) | |
283 if amt != 0 and not data: # Platform-specific: Buggy versions of Python. | |
284 # Close the connection when no data is returned | |
285 # | |
286 # This is redundant to what httplib/http.client _should_ | |
287 # already do. However, versions of python released before | |
288 # December 15, 2012 (http://bugs.python.org/issue16298) do | |
289 # not properly close the connection in all cases. There is | |
290 # no harm in redundantly calling close. | |
291 self._fp.close() | |
292 flush_decoder = True | |
293 | |
294 if data: | |
295 self._fp_bytes_read += len(data) | |
296 | |
297 data = self._decode(data, decode_content, flush_decoder) | |
298 | |
299 if cache_content: | |
300 self._body = data | |
301 | |
302 return data | |
303 | |
304 | |
305 def stream(self, amt=2**16, decode_content=None): | |
306 """ | |
307 A generator wrapper for the read() method. A call will block until | |
308 ``amt`` bytes have been read from the connection or until the | |
309 connection is closed. | |
310 | |
311 :param amt: | |
312 How much of the content to read. The generator will return up to | |
313 much data per iteration, but may return less. This is particularly | |
314 likely when using compressed data. However, the empty string will | |
315 never be returned. | |
316 | |
317 :param decode_content: | |
318 If True, will attempt to decode the body based on the | |
319 'content-encoding' header. | |
320 """ | |
321 if self.chunked: | |
322 for line in self.read_chunked(amt, decode_content=decode_content): | |
323 yield line | |
324 else: | |
325 while not is_fp_closed(self._fp): | |
326 data = self.read(amt=amt, decode_content=decode_content) | |
327 | |
328 if data: | |
329 yield data | |
330 | |
331 @classmethod | |
332 def from_httplib(ResponseCls, r, **response_kw): | |
333 """ | |
334 Given an :class:`httplib.HTTPResponse` instance ``r``, return a | |
335 corresponding :class:`urllib3.response.HTTPResponse` object. | |
336 | |
337 Remaining parameters are passed to the HTTPResponse constructor, along | |
338 with ``original_response=r``. | |
339 """ | |
340 headers = r.msg | |
341 | |
342 if not isinstance(headers, HTTPHeaderDict): | |
343 if PY3: # Python 3 | |
344 headers = HTTPHeaderDict(headers.items()) | |
345 else: # Python 2 | |
346 headers = HTTPHeaderDict.from_httplib(headers) | |
347 | |
348 # HTTPResponse objects in Python 3 don't have a .strict attribute | |
349 strict = getattr(r, 'strict', 0) | |
350 resp = ResponseCls(body=r, | |
351 headers=headers, | |
352 status=r.status, | |
353 version=r.version, | |
354 reason=r.reason, | |
355 strict=strict, | |
356 original_response=r, | |
357 **response_kw) | |
358 return resp | |
359 | |
360 # Backwards-compatibility methods for httplib.HTTPResponse | |
361 def getheaders(self): | |
362 return self.headers | |
363 | |
364 def getheader(self, name, default=None): | |
365 return self.headers.get(name, default) | |
366 | |
367 # Overrides from io.IOBase | |
368 def close(self): | |
369 if not self.closed: | |
370 self._fp.close() | |
371 | |
372 @property | |
373 def closed(self): | |
374 if self._fp is None: | |
375 return True | |
376 elif hasattr(self._fp, 'closed'): | |
377 return self._fp.closed | |
378 elif hasattr(self._fp, 'isclosed'): # Python 2 | |
379 return self._fp.isclosed() | |
380 else: | |
381 return True | |
382 | |
383 def fileno(self): | |
384 if self._fp is None: | |
385 raise IOError("HTTPResponse has no file to get a fileno from") | |
386 elif hasattr(self._fp, "fileno"): | |
387 return self._fp.fileno() | |
388 else: | |
389 raise IOError("The file-like object this HTTPResponse is wrapped " | |
390 "around has no file descriptor") | |
391 | |
392 def flush(self): | |
393 if self._fp is not None and hasattr(self._fp, 'flush'): | |
394 return self._fp.flush() | |
395 | |
396 def readable(self): | |
397 # This method is required for `io` module compatibility. | |
398 return True | |
399 | |
400 def readinto(self, b): | |
401 # This method is required for `io` module compatibility. | |
402 temp = self.read(len(b)) | |
403 if len(temp) == 0: | |
404 return 0 | |
405 else: | |
406 b[:len(temp)] = temp | |
407 return len(temp) | |
408 | |
409 def _update_chunk_length(self): | |
410 # First, we'll figure out length of a chunk and then | |
411 # we'll try to read it from socket. | |
412 if self.chunk_left is not None: | |
413 return | |
414 line = self._fp.fp.readline() | |
415 line = line.split(b';', 1)[0] | |
416 try: | |
417 self.chunk_left = int(line, 16) | |
418 except ValueError: | |
419 # Invalid chunked protocol response, abort. | |
420 self.close() | |
421 raise httplib.IncompleteRead(line) | |
422 | |
423 def _handle_chunk(self, amt): | |
424 returned_chunk = None | |
425 if amt is None: | |
426 chunk = self._fp._safe_read(self.chunk_left) | |
427 returned_chunk = chunk | |
428 self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. | |
429 self.chunk_left = None | |
430 elif amt < self.chunk_left: | |
431 value = self._fp._safe_read(amt) | |
432 self.chunk_left = self.chunk_left - amt | |
433 returned_chunk = value | |
434 elif amt == self.chunk_left: | |
435 value = self._fp._safe_read(amt) | |
436 self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. | |
437 self.chunk_left = None | |
438 returned_chunk = value | |
439 else: # amt > self.chunk_left | |
440 returned_chunk = self._fp._safe_read(self.chunk_left) | |
441 self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. | |
442 self.chunk_left = None | |
443 return returned_chunk | |
444 | |
445 def read_chunked(self, amt=None, decode_content=None): | |
446 """ | |
447 Similar to :meth:`HTTPResponse.read`, but with an additional | |
448 parameter: ``decode_content``. | |
449 | |
450 :param decode_content: | |
451 If True, will attempt to decode the body based on the | |
452 'content-encoding' header. | |
453 """ | |
454 self._init_decoder() | |
455 # FIXME: Rewrite this method and make it a class with a better structured logic. | |
456 if not self.chunked: | |
457 raise ResponseNotChunked("Response is not chunked. " | |
458 "Header 'transfer-encoding: chunked' is missing.") | |
459 | |
460 # Don't bother reading the body of a HEAD request. | |
461 if self._original_response and is_response_to_head(self._original_response): | |
462 self._original_response.close() | |
463 return | |
464 | |
465 with self._error_catcher(): | |
466 while True: | |
467 self._update_chunk_length() | |
468 if self.chunk_left == 0: | |
469 break | |
470 chunk = self._handle_chunk(amt) | |
471 yield self._decode(chunk, decode_content=decode_content, | |
472 flush_decoder=True) | |
473 | |
474 # Chunk content ends with \r\n: discard it. | |
475 while True: | |
476 line = self._fp.fp.readline() | |
477 if not line: | |
478 # Some sites may not end with '\r\n'. | |
479 break | |
480 if line == b'\r\n': | |
481 break | |
482 | |
483 # We read everything; close the "file". | |
484 if self._original_response: | |
485 self._original_response.close() |