1from __future__ import absolute_import 2 3from email.errors import MultipartInvariantViolationDefect, StartBoundaryNotFoundDefect 4 5from ..exceptions import HeaderParsingError 6from ..packages.six.moves import http_client as httplib 7 8 9def is_fp_closed(obj): 10 """ 11 Checks whether a given file-like object is closed. 12 13 :param obj: 14 The file-like object to check. 15 """ 16 17 try: 18 # Check `isclosed()` first, in case Python3 doesn't set `closed`. 19 # GH Issue #928 20 return obj.isclosed() 21 except AttributeError: 22 pass 23 24 try: 25 # Check via the official file-like-object way. 26 return obj.closed 27 except AttributeError: 28 pass 29 30 try: 31 # Check if the object is a container for another file-like object that 32 # gets released on exhaustion (e.g. HTTPResponse). 33 return obj.fp is None 34 except AttributeError: 35 pass 36 37 raise ValueError("Unable to determine whether fp is closed.") 38 39 40def assert_header_parsing(headers): 41 """ 42 Asserts whether all headers have been successfully parsed. 43 Extracts encountered errors from the result of parsing headers. 44 45 Only works on Python 3. 46 47 :param http.client.HTTPMessage headers: Headers to verify. 48 49 :raises urllib3.exceptions.HeaderParsingError: 50 If parsing errors are found. 51 """ 52 53 # This will fail silently if we pass in the wrong kind of parameter. 54 # To make debugging easier add an explicit check. 55 if not isinstance(headers, httplib.HTTPMessage): 56 raise TypeError("expected httplib.Message, got {0}.".format(type(headers))) 57 58 defects = getattr(headers, "defects", None) 59 get_payload = getattr(headers, "get_payload", None) 60 61 unparsed_data = None 62 if get_payload: 63 # get_payload is actually email.message.Message.get_payload; 64 # we're only interested in the result if it's not a multipart message 65 if not headers.is_multipart(): 66 payload = get_payload() 67 68 if isinstance(payload, (bytes, str)): 69 unparsed_data = payload 70 if defects: 71 # httplib is assuming a response body is available 72 # when parsing headers even when httplib only sends 73 # header data to parse_headers() This results in 74 # defects on multipart responses in particular. 75 # See: https://github.com/urllib3/urllib3/issues/800 76 77 # So we ignore the following defects: 78 # - StartBoundaryNotFoundDefect: 79 # The claimed start boundary was never found. 80 # - MultipartInvariantViolationDefect: 81 # A message claimed to be a multipart but no subparts were found. 82 defects = [ 83 defect 84 for defect in defects 85 if not isinstance( 86 defect, (StartBoundaryNotFoundDefect, MultipartInvariantViolationDefect) 87 ) 88 ] 89 90 if defects or unparsed_data: 91 raise HeaderParsingError(defects=defects, unparsed_data=unparsed_data) 92 93 94def is_response_to_head(response): 95 """ 96 Checks whether the request of a response has been a HEAD-request. 97 Handles the quirks of AppEngine. 98 99 :param http.client.HTTPResponse response: 100 Response to check if the originating request 101 used 'HEAD' as a method. 102 """ 103 # FIXME: Can we do this somehow without accessing private httplib _method? 104 method = response._method 105 if isinstance(method, int): # Platform-specific: Appengine 106 return method == 3 107 return method.upper() == "HEAD" 108