123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- from __future__ import annotations
-
- import http.client as httplib
- from email.errors import MultipartInvariantViolationDefect, StartBoundaryNotFoundDefect
-
- from ..exceptions import HeaderParsingError
-
-
- def is_fp_closed(obj: object) -> bool:
- """
- Checks whether a given file-like object is closed.
-
- :param obj:
- The file-like object to check.
- """
-
- try:
- # Check `isclosed()` first, in case Python3 doesn't set `closed`.
- # GH Issue #928
- return obj.isclosed() # type: ignore[no-any-return, attr-defined]
- except AttributeError:
- pass
-
- try:
- # Check via the official file-like-object way.
- return obj.closed # type: ignore[no-any-return, attr-defined]
- except AttributeError:
- pass
-
- try:
- # Check if the object is a container for another file-like object that
- # gets released on exhaustion (e.g. HTTPResponse).
- return obj.fp is None # type: ignore[attr-defined]
- except AttributeError:
- pass
-
- raise ValueError("Unable to determine whether fp is closed.")
-
-
- def assert_header_parsing(headers: httplib.HTTPMessage) -> None:
- """
- Asserts whether all headers have been successfully parsed.
- Extracts encountered errors from the result of parsing headers.
-
- Only works on Python 3.
-
- :param http.client.HTTPMessage headers: Headers to verify.
-
- :raises urllib3.exceptions.HeaderParsingError:
- If parsing errors are found.
- """
-
- # This will fail silently if we pass in the wrong kind of parameter.
- # To make debugging easier add an explicit check.
- if not isinstance(headers, httplib.HTTPMessage):
- raise TypeError(f"expected httplib.Message, got {type(headers)}.")
-
- unparsed_data = None
-
- # get_payload is actually email.message.Message.get_payload;
- # we're only interested in the result if it's not a multipart message
- if not headers.is_multipart():
- payload = headers.get_payload()
-
- if isinstance(payload, (bytes, str)):
- unparsed_data = payload
-
- # httplib is assuming a response body is available
- # when parsing headers even when httplib only sends
- # header data to parse_headers() This results in
- # defects on multipart responses in particular.
- # See: https://github.com/urllib3/urllib3/issues/800
-
- # So we ignore the following defects:
- # - StartBoundaryNotFoundDefect:
- # The claimed start boundary was never found.
- # - MultipartInvariantViolationDefect:
- # A message claimed to be a multipart but no subparts were found.
- defects = [
- defect
- for defect in headers.defects
- if not isinstance(
- defect, (StartBoundaryNotFoundDefect, MultipartInvariantViolationDefect)
- )
- ]
-
- if defects or unparsed_data:
- raise HeaderParsingError(defects=defects, unparsed_data=unparsed_data)
-
-
- def is_response_to_head(response: httplib.HTTPResponse) -> bool:
- """
- Checks whether the request of a response has been a HEAD-request.
-
- :param http.client.HTTPResponse response:
- Response to check if the originating request
- used 'HEAD' as a method.
- """
- # FIXME: Can we do this somehow without accessing private httplib _method?
- method_str = response._method # type: str # type: ignore[attr-defined]
- return method_str.upper() == "HEAD"
|