response.py 3.4 KB

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