17db96d56Sopenharmony_cir"""HTTP/1.1 client library
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ci<intro stuff goes here>
47db96d56Sopenharmony_ci<other stuff, too>
57db96d56Sopenharmony_ci
67db96d56Sopenharmony_ciHTTPConnection goes through a number of "states", which define when a client
77db96d56Sopenharmony_cimay legally make another request or fetch the response for a particular
87db96d56Sopenharmony_cirequest. This diagram details these state transitions:
97db96d56Sopenharmony_ci
107db96d56Sopenharmony_ci    (null)
117db96d56Sopenharmony_ci      |
127db96d56Sopenharmony_ci      | HTTPConnection()
137db96d56Sopenharmony_ci      v
147db96d56Sopenharmony_ci    Idle
157db96d56Sopenharmony_ci      |
167db96d56Sopenharmony_ci      | putrequest()
177db96d56Sopenharmony_ci      v
187db96d56Sopenharmony_ci    Request-started
197db96d56Sopenharmony_ci      |
207db96d56Sopenharmony_ci      | ( putheader() )*  endheaders()
217db96d56Sopenharmony_ci      v
227db96d56Sopenharmony_ci    Request-sent
237db96d56Sopenharmony_ci      |\_____________________________
247db96d56Sopenharmony_ci      |                              | getresponse() raises
257db96d56Sopenharmony_ci      | response = getresponse()     | ConnectionError
267db96d56Sopenharmony_ci      v                              v
277db96d56Sopenharmony_ci    Unread-response                Idle
287db96d56Sopenharmony_ci    [Response-headers-read]
297db96d56Sopenharmony_ci      |\____________________
307db96d56Sopenharmony_ci      |                     |
317db96d56Sopenharmony_ci      | response.read()     | putrequest()
327db96d56Sopenharmony_ci      v                     v
337db96d56Sopenharmony_ci    Idle                  Req-started-unread-response
347db96d56Sopenharmony_ci                     ______/|
357db96d56Sopenharmony_ci                   /        |
367db96d56Sopenharmony_ci   response.read() |        | ( putheader() )*  endheaders()
377db96d56Sopenharmony_ci                   v        v
387db96d56Sopenharmony_ci       Request-started    Req-sent-unread-response
397db96d56Sopenharmony_ci                            |
407db96d56Sopenharmony_ci                            | response.read()
417db96d56Sopenharmony_ci                            v
427db96d56Sopenharmony_ci                          Request-sent
437db96d56Sopenharmony_ci
447db96d56Sopenharmony_ciThis diagram presents the following rules:
457db96d56Sopenharmony_ci  -- a second request may not be started until {response-headers-read}
467db96d56Sopenharmony_ci  -- a response [object] cannot be retrieved until {request-sent}
477db96d56Sopenharmony_ci  -- there is no differentiation between an unread response body and a
487db96d56Sopenharmony_ci     partially read response body
497db96d56Sopenharmony_ci
507db96d56Sopenharmony_ciNote: this enforcement is applied by the HTTPConnection class. The
517db96d56Sopenharmony_ci      HTTPResponse class does not enforce this state machine, which
527db96d56Sopenharmony_ci      implies sophisticated clients may accelerate the request/response
537db96d56Sopenharmony_ci      pipeline. Caution should be taken, though: accelerating the states
547db96d56Sopenharmony_ci      beyond the above pattern may imply knowledge of the server's
557db96d56Sopenharmony_ci      connection-close behavior for certain requests. For example, it
567db96d56Sopenharmony_ci      is impossible to tell whether the server will close the connection
577db96d56Sopenharmony_ci      UNTIL the response headers have been read; this means that further
587db96d56Sopenharmony_ci      requests cannot be placed into the pipeline until it is known that
597db96d56Sopenharmony_ci      the server will NOT be closing the connection.
607db96d56Sopenharmony_ci
617db96d56Sopenharmony_ciLogical State                  __state            __response
627db96d56Sopenharmony_ci-------------                  -------            ----------
637db96d56Sopenharmony_ciIdle                           _CS_IDLE           None
647db96d56Sopenharmony_ciRequest-started                _CS_REQ_STARTED    None
657db96d56Sopenharmony_ciRequest-sent                   _CS_REQ_SENT       None
667db96d56Sopenharmony_ciUnread-response                _CS_IDLE           <response_class>
677db96d56Sopenharmony_ciReq-started-unread-response    _CS_REQ_STARTED    <response_class>
687db96d56Sopenharmony_ciReq-sent-unread-response       _CS_REQ_SENT       <response_class>
697db96d56Sopenharmony_ci"""
707db96d56Sopenharmony_ci
717db96d56Sopenharmony_ciimport email.parser
727db96d56Sopenharmony_ciimport email.message
737db96d56Sopenharmony_ciimport errno
747db96d56Sopenharmony_ciimport http
757db96d56Sopenharmony_ciimport io
767db96d56Sopenharmony_ciimport re
777db96d56Sopenharmony_ciimport socket
787db96d56Sopenharmony_ciimport sys
797db96d56Sopenharmony_ciimport collections.abc
807db96d56Sopenharmony_cifrom urllib.parse import urlsplit
817db96d56Sopenharmony_ci
827db96d56Sopenharmony_ci# HTTPMessage, parse_headers(), and the HTTP status code constants are
837db96d56Sopenharmony_ci# intentionally omitted for simplicity
847db96d56Sopenharmony_ci__all__ = ["HTTPResponse", "HTTPConnection",
857db96d56Sopenharmony_ci           "HTTPException", "NotConnected", "UnknownProtocol",
867db96d56Sopenharmony_ci           "UnknownTransferEncoding", "UnimplementedFileMode",
877db96d56Sopenharmony_ci           "IncompleteRead", "InvalidURL", "ImproperConnectionState",
887db96d56Sopenharmony_ci           "CannotSendRequest", "CannotSendHeader", "ResponseNotReady",
897db96d56Sopenharmony_ci           "BadStatusLine", "LineTooLong", "RemoteDisconnected", "error",
907db96d56Sopenharmony_ci           "responses"]
917db96d56Sopenharmony_ci
927db96d56Sopenharmony_ciHTTP_PORT = 80
937db96d56Sopenharmony_ciHTTPS_PORT = 443
947db96d56Sopenharmony_ci
957db96d56Sopenharmony_ci_UNKNOWN = 'UNKNOWN'
967db96d56Sopenharmony_ci
977db96d56Sopenharmony_ci# connection states
987db96d56Sopenharmony_ci_CS_IDLE = 'Idle'
997db96d56Sopenharmony_ci_CS_REQ_STARTED = 'Request-started'
1007db96d56Sopenharmony_ci_CS_REQ_SENT = 'Request-sent'
1017db96d56Sopenharmony_ci
1027db96d56Sopenharmony_ci
1037db96d56Sopenharmony_ci# hack to maintain backwards compatibility
1047db96d56Sopenharmony_ciglobals().update(http.HTTPStatus.__members__)
1057db96d56Sopenharmony_ci
1067db96d56Sopenharmony_ci# another hack to maintain backwards compatibility
1077db96d56Sopenharmony_ci# Mapping status codes to official W3C names
1087db96d56Sopenharmony_ciresponses = {v: v.phrase for v in http.HTTPStatus.__members__.values()}
1097db96d56Sopenharmony_ci
1107db96d56Sopenharmony_ci# maximal line length when calling readline().
1117db96d56Sopenharmony_ci_MAXLINE = 65536
1127db96d56Sopenharmony_ci_MAXHEADERS = 100
1137db96d56Sopenharmony_ci
1147db96d56Sopenharmony_ci# Header name/value ABNF (http://tools.ietf.org/html/rfc7230#section-3.2)
1157db96d56Sopenharmony_ci#
1167db96d56Sopenharmony_ci# VCHAR          = %x21-7E
1177db96d56Sopenharmony_ci# obs-text       = %x80-FF
1187db96d56Sopenharmony_ci# header-field   = field-name ":" OWS field-value OWS
1197db96d56Sopenharmony_ci# field-name     = token
1207db96d56Sopenharmony_ci# field-value    = *( field-content / obs-fold )
1217db96d56Sopenharmony_ci# field-content  = field-vchar [ 1*( SP / HTAB ) field-vchar ]
1227db96d56Sopenharmony_ci# field-vchar    = VCHAR / obs-text
1237db96d56Sopenharmony_ci#
1247db96d56Sopenharmony_ci# obs-fold       = CRLF 1*( SP / HTAB )
1257db96d56Sopenharmony_ci#                ; obsolete line folding
1267db96d56Sopenharmony_ci#                ; see Section 3.2.4
1277db96d56Sopenharmony_ci
1287db96d56Sopenharmony_ci# token          = 1*tchar
1297db96d56Sopenharmony_ci#
1307db96d56Sopenharmony_ci# tchar          = "!" / "#" / "$" / "%" / "&" / "'" / "*"
1317db96d56Sopenharmony_ci#                / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
1327db96d56Sopenharmony_ci#                / DIGIT / ALPHA
1337db96d56Sopenharmony_ci#                ; any VCHAR, except delimiters
1347db96d56Sopenharmony_ci#
1357db96d56Sopenharmony_ci# VCHAR defined in http://tools.ietf.org/html/rfc5234#appendix-B.1
1367db96d56Sopenharmony_ci
1377db96d56Sopenharmony_ci# the patterns for both name and value are more lenient than RFC
1387db96d56Sopenharmony_ci# definitions to allow for backwards compatibility
1397db96d56Sopenharmony_ci_is_legal_header_name = re.compile(rb'[^:\s][^:\r\n]*').fullmatch
1407db96d56Sopenharmony_ci_is_illegal_header_value = re.compile(rb'\n(?![ \t])|\r(?![ \t\n])').search
1417db96d56Sopenharmony_ci
1427db96d56Sopenharmony_ci# These characters are not allowed within HTTP URL paths.
1437db96d56Sopenharmony_ci#  See https://tools.ietf.org/html/rfc3986#section-3.3 and the
1447db96d56Sopenharmony_ci#  https://tools.ietf.org/html/rfc3986#appendix-A pchar definition.
1457db96d56Sopenharmony_ci# Prevents CVE-2019-9740.  Includes control characters such as \r\n.
1467db96d56Sopenharmony_ci# We don't restrict chars above \x7f as putrequest() limits us to ASCII.
1477db96d56Sopenharmony_ci_contains_disallowed_url_pchar_re = re.compile('[\x00-\x20\x7f]')
1487db96d56Sopenharmony_ci# Arguably only these _should_ allowed:
1497db96d56Sopenharmony_ci#  _is_allowed_url_pchars_re = re.compile(r"^[/!$&'()*+,;=:@%a-zA-Z0-9._~-]+$")
1507db96d56Sopenharmony_ci# We are more lenient for assumed real world compatibility purposes.
1517db96d56Sopenharmony_ci
1527db96d56Sopenharmony_ci# These characters are not allowed within HTTP method names
1537db96d56Sopenharmony_ci# to prevent http header injection.
1547db96d56Sopenharmony_ci_contains_disallowed_method_pchar_re = re.compile('[\x00-\x1f]')
1557db96d56Sopenharmony_ci
1567db96d56Sopenharmony_ci# We always set the Content-Length header for these methods because some
1577db96d56Sopenharmony_ci# servers will otherwise respond with a 411
1587db96d56Sopenharmony_ci_METHODS_EXPECTING_BODY = {'PATCH', 'POST', 'PUT'}
1597db96d56Sopenharmony_ci
1607db96d56Sopenharmony_ci
1617db96d56Sopenharmony_cidef _encode(data, name='data'):
1627db96d56Sopenharmony_ci    """Call data.encode("latin-1") but show a better error message."""
1637db96d56Sopenharmony_ci    try:
1647db96d56Sopenharmony_ci        return data.encode("latin-1")
1657db96d56Sopenharmony_ci    except UnicodeEncodeError as err:
1667db96d56Sopenharmony_ci        raise UnicodeEncodeError(
1677db96d56Sopenharmony_ci            err.encoding,
1687db96d56Sopenharmony_ci            err.object,
1697db96d56Sopenharmony_ci            err.start,
1707db96d56Sopenharmony_ci            err.end,
1717db96d56Sopenharmony_ci            "%s (%.20r) is not valid Latin-1. Use %s.encode('utf-8') "
1727db96d56Sopenharmony_ci            "if you want to send it encoded in UTF-8." %
1737db96d56Sopenharmony_ci            (name.title(), data[err.start:err.end], name)) from None
1747db96d56Sopenharmony_ci
1757db96d56Sopenharmony_ci
1767db96d56Sopenharmony_ciclass HTTPMessage(email.message.Message):
1777db96d56Sopenharmony_ci    # XXX The only usage of this method is in
1787db96d56Sopenharmony_ci    # http.server.CGIHTTPRequestHandler.  Maybe move the code there so
1797db96d56Sopenharmony_ci    # that it doesn't need to be part of the public API.  The API has
1807db96d56Sopenharmony_ci    # never been defined so this could cause backwards compatibility
1817db96d56Sopenharmony_ci    # issues.
1827db96d56Sopenharmony_ci
1837db96d56Sopenharmony_ci    def getallmatchingheaders(self, name):
1847db96d56Sopenharmony_ci        """Find all header lines matching a given header name.
1857db96d56Sopenharmony_ci
1867db96d56Sopenharmony_ci        Look through the list of headers and find all lines matching a given
1877db96d56Sopenharmony_ci        header name (and their continuation lines).  A list of the lines is
1887db96d56Sopenharmony_ci        returned, without interpretation.  If the header does not occur, an
1897db96d56Sopenharmony_ci        empty list is returned.  If the header occurs multiple times, all
1907db96d56Sopenharmony_ci        occurrences are returned.  Case is not important in the header name.
1917db96d56Sopenharmony_ci
1927db96d56Sopenharmony_ci        """
1937db96d56Sopenharmony_ci        name = name.lower() + ':'
1947db96d56Sopenharmony_ci        n = len(name)
1957db96d56Sopenharmony_ci        lst = []
1967db96d56Sopenharmony_ci        hit = 0
1977db96d56Sopenharmony_ci        for line in self.keys():
1987db96d56Sopenharmony_ci            if line[:n].lower() == name:
1997db96d56Sopenharmony_ci                hit = 1
2007db96d56Sopenharmony_ci            elif not line[:1].isspace():
2017db96d56Sopenharmony_ci                hit = 0
2027db96d56Sopenharmony_ci            if hit:
2037db96d56Sopenharmony_ci                lst.append(line)
2047db96d56Sopenharmony_ci        return lst
2057db96d56Sopenharmony_ci
2067db96d56Sopenharmony_cidef _read_headers(fp):
2077db96d56Sopenharmony_ci    """Reads potential header lines into a list from a file pointer.
2087db96d56Sopenharmony_ci
2097db96d56Sopenharmony_ci    Length of line is limited by _MAXLINE, and number of
2107db96d56Sopenharmony_ci    headers is limited by _MAXHEADERS.
2117db96d56Sopenharmony_ci    """
2127db96d56Sopenharmony_ci    headers = []
2137db96d56Sopenharmony_ci    while True:
2147db96d56Sopenharmony_ci        line = fp.readline(_MAXLINE + 1)
2157db96d56Sopenharmony_ci        if len(line) > _MAXLINE:
2167db96d56Sopenharmony_ci            raise LineTooLong("header line")
2177db96d56Sopenharmony_ci        headers.append(line)
2187db96d56Sopenharmony_ci        if len(headers) > _MAXHEADERS:
2197db96d56Sopenharmony_ci            raise HTTPException("got more than %d headers" % _MAXHEADERS)
2207db96d56Sopenharmony_ci        if line in (b'\r\n', b'\n', b''):
2217db96d56Sopenharmony_ci            break
2227db96d56Sopenharmony_ci    return headers
2237db96d56Sopenharmony_ci
2247db96d56Sopenharmony_cidef parse_headers(fp, _class=HTTPMessage):
2257db96d56Sopenharmony_ci    """Parses only RFC2822 headers from a file pointer.
2267db96d56Sopenharmony_ci
2277db96d56Sopenharmony_ci    email Parser wants to see strings rather than bytes.
2287db96d56Sopenharmony_ci    But a TextIOWrapper around self.rfile would buffer too many bytes
2297db96d56Sopenharmony_ci    from the stream, bytes which we later need to read as bytes.
2307db96d56Sopenharmony_ci    So we read the correct bytes here, as bytes, for email Parser
2317db96d56Sopenharmony_ci    to parse.
2327db96d56Sopenharmony_ci
2337db96d56Sopenharmony_ci    """
2347db96d56Sopenharmony_ci    headers = _read_headers(fp)
2357db96d56Sopenharmony_ci    hstring = b''.join(headers).decode('iso-8859-1')
2367db96d56Sopenharmony_ci    return email.parser.Parser(_class=_class).parsestr(hstring)
2377db96d56Sopenharmony_ci
2387db96d56Sopenharmony_ci
2397db96d56Sopenharmony_ciclass HTTPResponse(io.BufferedIOBase):
2407db96d56Sopenharmony_ci
2417db96d56Sopenharmony_ci    # See RFC 2616 sec 19.6 and RFC 1945 sec 6 for details.
2427db96d56Sopenharmony_ci
2437db96d56Sopenharmony_ci    # The bytes from the socket object are iso-8859-1 strings.
2447db96d56Sopenharmony_ci    # See RFC 2616 sec 2.2 which notes an exception for MIME-encoded
2457db96d56Sopenharmony_ci    # text following RFC 2047.  The basic status line parsing only
2467db96d56Sopenharmony_ci    # accepts iso-8859-1.
2477db96d56Sopenharmony_ci
2487db96d56Sopenharmony_ci    def __init__(self, sock, debuglevel=0, method=None, url=None):
2497db96d56Sopenharmony_ci        # If the response includes a content-length header, we need to
2507db96d56Sopenharmony_ci        # make sure that the client doesn't read more than the
2517db96d56Sopenharmony_ci        # specified number of bytes.  If it does, it will block until
2527db96d56Sopenharmony_ci        # the server times out and closes the connection.  This will
2537db96d56Sopenharmony_ci        # happen if a self.fp.read() is done (without a size) whether
2547db96d56Sopenharmony_ci        # self.fp is buffered or not.  So, no self.fp.read() by
2557db96d56Sopenharmony_ci        # clients unless they know what they are doing.
2567db96d56Sopenharmony_ci        self.fp = sock.makefile("rb")
2577db96d56Sopenharmony_ci        self.debuglevel = debuglevel
2587db96d56Sopenharmony_ci        self._method = method
2597db96d56Sopenharmony_ci
2607db96d56Sopenharmony_ci        # The HTTPResponse object is returned via urllib.  The clients
2617db96d56Sopenharmony_ci        # of http and urllib expect different attributes for the
2627db96d56Sopenharmony_ci        # headers.  headers is used here and supports urllib.  msg is
2637db96d56Sopenharmony_ci        # provided as a backwards compatibility layer for http
2647db96d56Sopenharmony_ci        # clients.
2657db96d56Sopenharmony_ci
2667db96d56Sopenharmony_ci        self.headers = self.msg = None
2677db96d56Sopenharmony_ci
2687db96d56Sopenharmony_ci        # from the Status-Line of the response
2697db96d56Sopenharmony_ci        self.version = _UNKNOWN # HTTP-Version
2707db96d56Sopenharmony_ci        self.status = _UNKNOWN  # Status-Code
2717db96d56Sopenharmony_ci        self.reason = _UNKNOWN  # Reason-Phrase
2727db96d56Sopenharmony_ci
2737db96d56Sopenharmony_ci        self.chunked = _UNKNOWN         # is "chunked" being used?
2747db96d56Sopenharmony_ci        self.chunk_left = _UNKNOWN      # bytes left to read in current chunk
2757db96d56Sopenharmony_ci        self.length = _UNKNOWN          # number of bytes left in response
2767db96d56Sopenharmony_ci        self.will_close = _UNKNOWN      # conn will close at end of response
2777db96d56Sopenharmony_ci
2787db96d56Sopenharmony_ci    def _read_status(self):
2797db96d56Sopenharmony_ci        line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
2807db96d56Sopenharmony_ci        if len(line) > _MAXLINE:
2817db96d56Sopenharmony_ci            raise LineTooLong("status line")
2827db96d56Sopenharmony_ci        if self.debuglevel > 0:
2837db96d56Sopenharmony_ci            print("reply:", repr(line))
2847db96d56Sopenharmony_ci        if not line:
2857db96d56Sopenharmony_ci            # Presumably, the server closed the connection before
2867db96d56Sopenharmony_ci            # sending a valid response.
2877db96d56Sopenharmony_ci            raise RemoteDisconnected("Remote end closed connection without"
2887db96d56Sopenharmony_ci                                     " response")
2897db96d56Sopenharmony_ci        try:
2907db96d56Sopenharmony_ci            version, status, reason = line.split(None, 2)
2917db96d56Sopenharmony_ci        except ValueError:
2927db96d56Sopenharmony_ci            try:
2937db96d56Sopenharmony_ci                version, status = line.split(None, 1)
2947db96d56Sopenharmony_ci                reason = ""
2957db96d56Sopenharmony_ci            except ValueError:
2967db96d56Sopenharmony_ci                # empty version will cause next test to fail.
2977db96d56Sopenharmony_ci                version = ""
2987db96d56Sopenharmony_ci        if not version.startswith("HTTP/"):
2997db96d56Sopenharmony_ci            self._close_conn()
3007db96d56Sopenharmony_ci            raise BadStatusLine(line)
3017db96d56Sopenharmony_ci
3027db96d56Sopenharmony_ci        # The status code is a three-digit number
3037db96d56Sopenharmony_ci        try:
3047db96d56Sopenharmony_ci            status = int(status)
3057db96d56Sopenharmony_ci            if status < 100 or status > 999:
3067db96d56Sopenharmony_ci                raise BadStatusLine(line)
3077db96d56Sopenharmony_ci        except ValueError:
3087db96d56Sopenharmony_ci            raise BadStatusLine(line)
3097db96d56Sopenharmony_ci        return version, status, reason
3107db96d56Sopenharmony_ci
3117db96d56Sopenharmony_ci    def begin(self):
3127db96d56Sopenharmony_ci        if self.headers is not None:
3137db96d56Sopenharmony_ci            # we've already started reading the response
3147db96d56Sopenharmony_ci            return
3157db96d56Sopenharmony_ci
3167db96d56Sopenharmony_ci        # read until we get a non-100 response
3177db96d56Sopenharmony_ci        while True:
3187db96d56Sopenharmony_ci            version, status, reason = self._read_status()
3197db96d56Sopenharmony_ci            if status != CONTINUE:
3207db96d56Sopenharmony_ci                break
3217db96d56Sopenharmony_ci            # skip the header from the 100 response
3227db96d56Sopenharmony_ci            skipped_headers = _read_headers(self.fp)
3237db96d56Sopenharmony_ci            if self.debuglevel > 0:
3247db96d56Sopenharmony_ci                print("headers:", skipped_headers)
3257db96d56Sopenharmony_ci            del skipped_headers
3267db96d56Sopenharmony_ci
3277db96d56Sopenharmony_ci        self.code = self.status = status
3287db96d56Sopenharmony_ci        self.reason = reason.strip()
3297db96d56Sopenharmony_ci        if version in ("HTTP/1.0", "HTTP/0.9"):
3307db96d56Sopenharmony_ci            # Some servers might still return "0.9", treat it as 1.0 anyway
3317db96d56Sopenharmony_ci            self.version = 10
3327db96d56Sopenharmony_ci        elif version.startswith("HTTP/1."):
3337db96d56Sopenharmony_ci            self.version = 11   # use HTTP/1.1 code for HTTP/1.x where x>=1
3347db96d56Sopenharmony_ci        else:
3357db96d56Sopenharmony_ci            raise UnknownProtocol(version)
3367db96d56Sopenharmony_ci
3377db96d56Sopenharmony_ci        self.headers = self.msg = parse_headers(self.fp)
3387db96d56Sopenharmony_ci
3397db96d56Sopenharmony_ci        if self.debuglevel > 0:
3407db96d56Sopenharmony_ci            for hdr, val in self.headers.items():
3417db96d56Sopenharmony_ci                print("header:", hdr + ":", val)
3427db96d56Sopenharmony_ci
3437db96d56Sopenharmony_ci        # are we using the chunked-style of transfer encoding?
3447db96d56Sopenharmony_ci        tr_enc = self.headers.get("transfer-encoding")
3457db96d56Sopenharmony_ci        if tr_enc and tr_enc.lower() == "chunked":
3467db96d56Sopenharmony_ci            self.chunked = True
3477db96d56Sopenharmony_ci            self.chunk_left = None
3487db96d56Sopenharmony_ci        else:
3497db96d56Sopenharmony_ci            self.chunked = False
3507db96d56Sopenharmony_ci
3517db96d56Sopenharmony_ci        # will the connection close at the end of the response?
3527db96d56Sopenharmony_ci        self.will_close = self._check_close()
3537db96d56Sopenharmony_ci
3547db96d56Sopenharmony_ci        # do we have a Content-Length?
3557db96d56Sopenharmony_ci        # NOTE: RFC 2616, S4.4, #3 says we ignore this if tr_enc is "chunked"
3567db96d56Sopenharmony_ci        self.length = None
3577db96d56Sopenharmony_ci        length = self.headers.get("content-length")
3587db96d56Sopenharmony_ci        if length and not self.chunked:
3597db96d56Sopenharmony_ci            try:
3607db96d56Sopenharmony_ci                self.length = int(length)
3617db96d56Sopenharmony_ci            except ValueError:
3627db96d56Sopenharmony_ci                self.length = None
3637db96d56Sopenharmony_ci            else:
3647db96d56Sopenharmony_ci                if self.length < 0:  # ignore nonsensical negative lengths
3657db96d56Sopenharmony_ci                    self.length = None
3667db96d56Sopenharmony_ci        else:
3677db96d56Sopenharmony_ci            self.length = None
3687db96d56Sopenharmony_ci
3697db96d56Sopenharmony_ci        # does the body have a fixed length? (of zero)
3707db96d56Sopenharmony_ci        if (status == NO_CONTENT or status == NOT_MODIFIED or
3717db96d56Sopenharmony_ci            100 <= status < 200 or      # 1xx codes
3727db96d56Sopenharmony_ci            self._method == "HEAD"):
3737db96d56Sopenharmony_ci            self.length = 0
3747db96d56Sopenharmony_ci
3757db96d56Sopenharmony_ci        # if the connection remains open, and we aren't using chunked, and
3767db96d56Sopenharmony_ci        # a content-length was not provided, then assume that the connection
3777db96d56Sopenharmony_ci        # WILL close.
3787db96d56Sopenharmony_ci        if (not self.will_close and
3797db96d56Sopenharmony_ci            not self.chunked and
3807db96d56Sopenharmony_ci            self.length is None):
3817db96d56Sopenharmony_ci            self.will_close = True
3827db96d56Sopenharmony_ci
3837db96d56Sopenharmony_ci    def _check_close(self):
3847db96d56Sopenharmony_ci        conn = self.headers.get("connection")
3857db96d56Sopenharmony_ci        if self.version == 11:
3867db96d56Sopenharmony_ci            # An HTTP/1.1 proxy is assumed to stay open unless
3877db96d56Sopenharmony_ci            # explicitly closed.
3887db96d56Sopenharmony_ci            if conn and "close" in conn.lower():
3897db96d56Sopenharmony_ci                return True
3907db96d56Sopenharmony_ci            return False
3917db96d56Sopenharmony_ci
3927db96d56Sopenharmony_ci        # Some HTTP/1.0 implementations have support for persistent
3937db96d56Sopenharmony_ci        # connections, using rules different than HTTP/1.1.
3947db96d56Sopenharmony_ci
3957db96d56Sopenharmony_ci        # For older HTTP, Keep-Alive indicates persistent connection.
3967db96d56Sopenharmony_ci        if self.headers.get("keep-alive"):
3977db96d56Sopenharmony_ci            return False
3987db96d56Sopenharmony_ci
3997db96d56Sopenharmony_ci        # At least Akamai returns a "Connection: Keep-Alive" header,
4007db96d56Sopenharmony_ci        # which was supposed to be sent by the client.
4017db96d56Sopenharmony_ci        if conn and "keep-alive" in conn.lower():
4027db96d56Sopenharmony_ci            return False
4037db96d56Sopenharmony_ci
4047db96d56Sopenharmony_ci        # Proxy-Connection is a netscape hack.
4057db96d56Sopenharmony_ci        pconn = self.headers.get("proxy-connection")
4067db96d56Sopenharmony_ci        if pconn and "keep-alive" in pconn.lower():
4077db96d56Sopenharmony_ci            return False
4087db96d56Sopenharmony_ci
4097db96d56Sopenharmony_ci        # otherwise, assume it will close
4107db96d56Sopenharmony_ci        return True
4117db96d56Sopenharmony_ci
4127db96d56Sopenharmony_ci    def _close_conn(self):
4137db96d56Sopenharmony_ci        fp = self.fp
4147db96d56Sopenharmony_ci        self.fp = None
4157db96d56Sopenharmony_ci        fp.close()
4167db96d56Sopenharmony_ci
4177db96d56Sopenharmony_ci    def close(self):
4187db96d56Sopenharmony_ci        try:
4197db96d56Sopenharmony_ci            super().close() # set "closed" flag
4207db96d56Sopenharmony_ci        finally:
4217db96d56Sopenharmony_ci            if self.fp:
4227db96d56Sopenharmony_ci                self._close_conn()
4237db96d56Sopenharmony_ci
4247db96d56Sopenharmony_ci    # These implementations are for the benefit of io.BufferedReader.
4257db96d56Sopenharmony_ci
4267db96d56Sopenharmony_ci    # XXX This class should probably be revised to act more like
4277db96d56Sopenharmony_ci    # the "raw stream" that BufferedReader expects.
4287db96d56Sopenharmony_ci
4297db96d56Sopenharmony_ci    def flush(self):
4307db96d56Sopenharmony_ci        super().flush()
4317db96d56Sopenharmony_ci        if self.fp:
4327db96d56Sopenharmony_ci            self.fp.flush()
4337db96d56Sopenharmony_ci
4347db96d56Sopenharmony_ci    def readable(self):
4357db96d56Sopenharmony_ci        """Always returns True"""
4367db96d56Sopenharmony_ci        return True
4377db96d56Sopenharmony_ci
4387db96d56Sopenharmony_ci    # End of "raw stream" methods
4397db96d56Sopenharmony_ci
4407db96d56Sopenharmony_ci    def isclosed(self):
4417db96d56Sopenharmony_ci        """True if the connection is closed."""
4427db96d56Sopenharmony_ci        # NOTE: it is possible that we will not ever call self.close(). This
4437db96d56Sopenharmony_ci        #       case occurs when will_close is TRUE, length is None, and we
4447db96d56Sopenharmony_ci        #       read up to the last byte, but NOT past it.
4457db96d56Sopenharmony_ci        #
4467db96d56Sopenharmony_ci        # IMPLIES: if will_close is FALSE, then self.close() will ALWAYS be
4477db96d56Sopenharmony_ci        #          called, meaning self.isclosed() is meaningful.
4487db96d56Sopenharmony_ci        return self.fp is None
4497db96d56Sopenharmony_ci
4507db96d56Sopenharmony_ci    def read(self, amt=None):
4517db96d56Sopenharmony_ci        """Read and return the response body, or up to the next amt bytes."""
4527db96d56Sopenharmony_ci        if self.fp is None:
4537db96d56Sopenharmony_ci            return b""
4547db96d56Sopenharmony_ci
4557db96d56Sopenharmony_ci        if self._method == "HEAD":
4567db96d56Sopenharmony_ci            self._close_conn()
4577db96d56Sopenharmony_ci            return b""
4587db96d56Sopenharmony_ci
4597db96d56Sopenharmony_ci        if self.chunked:
4607db96d56Sopenharmony_ci            return self._read_chunked(amt)
4617db96d56Sopenharmony_ci
4627db96d56Sopenharmony_ci        if amt is not None:
4637db96d56Sopenharmony_ci            if self.length is not None and amt > self.length:
4647db96d56Sopenharmony_ci                # clip the read to the "end of response"
4657db96d56Sopenharmony_ci                amt = self.length
4667db96d56Sopenharmony_ci            s = self.fp.read(amt)
4677db96d56Sopenharmony_ci            if not s and amt:
4687db96d56Sopenharmony_ci                # Ideally, we would raise IncompleteRead if the content-length
4697db96d56Sopenharmony_ci                # wasn't satisfied, but it might break compatibility.
4707db96d56Sopenharmony_ci                self._close_conn()
4717db96d56Sopenharmony_ci            elif self.length is not None:
4727db96d56Sopenharmony_ci                self.length -= len(s)
4737db96d56Sopenharmony_ci                if not self.length:
4747db96d56Sopenharmony_ci                    self._close_conn()
4757db96d56Sopenharmony_ci            return s
4767db96d56Sopenharmony_ci        else:
4777db96d56Sopenharmony_ci            # Amount is not given (unbounded read) so we must check self.length
4787db96d56Sopenharmony_ci            if self.length is None:
4797db96d56Sopenharmony_ci                s = self.fp.read()
4807db96d56Sopenharmony_ci            else:
4817db96d56Sopenharmony_ci                try:
4827db96d56Sopenharmony_ci                    s = self._safe_read(self.length)
4837db96d56Sopenharmony_ci                except IncompleteRead:
4847db96d56Sopenharmony_ci                    self._close_conn()
4857db96d56Sopenharmony_ci                    raise
4867db96d56Sopenharmony_ci                self.length = 0
4877db96d56Sopenharmony_ci            self._close_conn()        # we read everything
4887db96d56Sopenharmony_ci            return s
4897db96d56Sopenharmony_ci
4907db96d56Sopenharmony_ci    def readinto(self, b):
4917db96d56Sopenharmony_ci        """Read up to len(b) bytes into bytearray b and return the number
4927db96d56Sopenharmony_ci        of bytes read.
4937db96d56Sopenharmony_ci        """
4947db96d56Sopenharmony_ci
4957db96d56Sopenharmony_ci        if self.fp is None:
4967db96d56Sopenharmony_ci            return 0
4977db96d56Sopenharmony_ci
4987db96d56Sopenharmony_ci        if self._method == "HEAD":
4997db96d56Sopenharmony_ci            self._close_conn()
5007db96d56Sopenharmony_ci            return 0
5017db96d56Sopenharmony_ci
5027db96d56Sopenharmony_ci        if self.chunked:
5037db96d56Sopenharmony_ci            return self._readinto_chunked(b)
5047db96d56Sopenharmony_ci
5057db96d56Sopenharmony_ci        if self.length is not None:
5067db96d56Sopenharmony_ci            if len(b) > self.length:
5077db96d56Sopenharmony_ci                # clip the read to the "end of response"
5087db96d56Sopenharmony_ci                b = memoryview(b)[0:self.length]
5097db96d56Sopenharmony_ci
5107db96d56Sopenharmony_ci        # we do not use _safe_read() here because this may be a .will_close
5117db96d56Sopenharmony_ci        # connection, and the user is reading more bytes than will be provided
5127db96d56Sopenharmony_ci        # (for example, reading in 1k chunks)
5137db96d56Sopenharmony_ci        n = self.fp.readinto(b)
5147db96d56Sopenharmony_ci        if not n and b:
5157db96d56Sopenharmony_ci            # Ideally, we would raise IncompleteRead if the content-length
5167db96d56Sopenharmony_ci            # wasn't satisfied, but it might break compatibility.
5177db96d56Sopenharmony_ci            self._close_conn()
5187db96d56Sopenharmony_ci        elif self.length is not None:
5197db96d56Sopenharmony_ci            self.length -= n
5207db96d56Sopenharmony_ci            if not self.length:
5217db96d56Sopenharmony_ci                self._close_conn()
5227db96d56Sopenharmony_ci        return n
5237db96d56Sopenharmony_ci
5247db96d56Sopenharmony_ci    def _read_next_chunk_size(self):
5257db96d56Sopenharmony_ci        # Read the next chunk size from the file
5267db96d56Sopenharmony_ci        line = self.fp.readline(_MAXLINE + 1)
5277db96d56Sopenharmony_ci        if len(line) > _MAXLINE:
5287db96d56Sopenharmony_ci            raise LineTooLong("chunk size")
5297db96d56Sopenharmony_ci        i = line.find(b";")
5307db96d56Sopenharmony_ci        if i >= 0:
5317db96d56Sopenharmony_ci            line = line[:i] # strip chunk-extensions
5327db96d56Sopenharmony_ci        try:
5337db96d56Sopenharmony_ci            return int(line, 16)
5347db96d56Sopenharmony_ci        except ValueError:
5357db96d56Sopenharmony_ci            # close the connection as protocol synchronisation is
5367db96d56Sopenharmony_ci            # probably lost
5377db96d56Sopenharmony_ci            self._close_conn()
5387db96d56Sopenharmony_ci            raise
5397db96d56Sopenharmony_ci
5407db96d56Sopenharmony_ci    def _read_and_discard_trailer(self):
5417db96d56Sopenharmony_ci        # read and discard trailer up to the CRLF terminator
5427db96d56Sopenharmony_ci        ### note: we shouldn't have any trailers!
5437db96d56Sopenharmony_ci        while True:
5447db96d56Sopenharmony_ci            line = self.fp.readline(_MAXLINE + 1)
5457db96d56Sopenharmony_ci            if len(line) > _MAXLINE:
5467db96d56Sopenharmony_ci                raise LineTooLong("trailer line")
5477db96d56Sopenharmony_ci            if not line:
5487db96d56Sopenharmony_ci                # a vanishingly small number of sites EOF without
5497db96d56Sopenharmony_ci                # sending the trailer
5507db96d56Sopenharmony_ci                break
5517db96d56Sopenharmony_ci            if line in (b'\r\n', b'\n', b''):
5527db96d56Sopenharmony_ci                break
5537db96d56Sopenharmony_ci
5547db96d56Sopenharmony_ci    def _get_chunk_left(self):
5557db96d56Sopenharmony_ci        # return self.chunk_left, reading a new chunk if necessary.
5567db96d56Sopenharmony_ci        # chunk_left == 0: at the end of the current chunk, need to close it
5577db96d56Sopenharmony_ci        # chunk_left == None: No current chunk, should read next.
5587db96d56Sopenharmony_ci        # This function returns non-zero or None if the last chunk has
5597db96d56Sopenharmony_ci        # been read.
5607db96d56Sopenharmony_ci        chunk_left = self.chunk_left
5617db96d56Sopenharmony_ci        if not chunk_left: # Can be 0 or None
5627db96d56Sopenharmony_ci            if chunk_left is not None:
5637db96d56Sopenharmony_ci                # We are at the end of chunk, discard chunk end
5647db96d56Sopenharmony_ci                self._safe_read(2)  # toss the CRLF at the end of the chunk
5657db96d56Sopenharmony_ci            try:
5667db96d56Sopenharmony_ci                chunk_left = self._read_next_chunk_size()
5677db96d56Sopenharmony_ci            except ValueError:
5687db96d56Sopenharmony_ci                raise IncompleteRead(b'')
5697db96d56Sopenharmony_ci            if chunk_left == 0:
5707db96d56Sopenharmony_ci                # last chunk: 1*("0") [ chunk-extension ] CRLF
5717db96d56Sopenharmony_ci                self._read_and_discard_trailer()
5727db96d56Sopenharmony_ci                # we read everything; close the "file"
5737db96d56Sopenharmony_ci                self._close_conn()
5747db96d56Sopenharmony_ci                chunk_left = None
5757db96d56Sopenharmony_ci            self.chunk_left = chunk_left
5767db96d56Sopenharmony_ci        return chunk_left
5777db96d56Sopenharmony_ci
5787db96d56Sopenharmony_ci    def _read_chunked(self, amt=None):
5797db96d56Sopenharmony_ci        assert self.chunked != _UNKNOWN
5807db96d56Sopenharmony_ci        value = []
5817db96d56Sopenharmony_ci        try:
5827db96d56Sopenharmony_ci            while True:
5837db96d56Sopenharmony_ci                chunk_left = self._get_chunk_left()
5847db96d56Sopenharmony_ci                if chunk_left is None:
5857db96d56Sopenharmony_ci                    break
5867db96d56Sopenharmony_ci
5877db96d56Sopenharmony_ci                if amt is not None and amt <= chunk_left:
5887db96d56Sopenharmony_ci                    value.append(self._safe_read(amt))
5897db96d56Sopenharmony_ci                    self.chunk_left = chunk_left - amt
5907db96d56Sopenharmony_ci                    break
5917db96d56Sopenharmony_ci
5927db96d56Sopenharmony_ci                value.append(self._safe_read(chunk_left))
5937db96d56Sopenharmony_ci                if amt is not None:
5947db96d56Sopenharmony_ci                    amt -= chunk_left
5957db96d56Sopenharmony_ci                self.chunk_left = 0
5967db96d56Sopenharmony_ci            return b''.join(value)
5977db96d56Sopenharmony_ci        except IncompleteRead as exc:
5987db96d56Sopenharmony_ci            raise IncompleteRead(b''.join(value)) from exc
5997db96d56Sopenharmony_ci
6007db96d56Sopenharmony_ci    def _readinto_chunked(self, b):
6017db96d56Sopenharmony_ci        assert self.chunked != _UNKNOWN
6027db96d56Sopenharmony_ci        total_bytes = 0
6037db96d56Sopenharmony_ci        mvb = memoryview(b)
6047db96d56Sopenharmony_ci        try:
6057db96d56Sopenharmony_ci            while True:
6067db96d56Sopenharmony_ci                chunk_left = self._get_chunk_left()
6077db96d56Sopenharmony_ci                if chunk_left is None:
6087db96d56Sopenharmony_ci                    return total_bytes
6097db96d56Sopenharmony_ci
6107db96d56Sopenharmony_ci                if len(mvb) <= chunk_left:
6117db96d56Sopenharmony_ci                    n = self._safe_readinto(mvb)
6127db96d56Sopenharmony_ci                    self.chunk_left = chunk_left - n
6137db96d56Sopenharmony_ci                    return total_bytes + n
6147db96d56Sopenharmony_ci
6157db96d56Sopenharmony_ci                temp_mvb = mvb[:chunk_left]
6167db96d56Sopenharmony_ci                n = self._safe_readinto(temp_mvb)
6177db96d56Sopenharmony_ci                mvb = mvb[n:]
6187db96d56Sopenharmony_ci                total_bytes += n
6197db96d56Sopenharmony_ci                self.chunk_left = 0
6207db96d56Sopenharmony_ci
6217db96d56Sopenharmony_ci        except IncompleteRead:
6227db96d56Sopenharmony_ci            raise IncompleteRead(bytes(b[0:total_bytes]))
6237db96d56Sopenharmony_ci
6247db96d56Sopenharmony_ci    def _safe_read(self, amt):
6257db96d56Sopenharmony_ci        """Read the number of bytes requested.
6267db96d56Sopenharmony_ci
6277db96d56Sopenharmony_ci        This function should be used when <amt> bytes "should" be present for
6287db96d56Sopenharmony_ci        reading. If the bytes are truly not available (due to EOF), then the
6297db96d56Sopenharmony_ci        IncompleteRead exception can be used to detect the problem.
6307db96d56Sopenharmony_ci        """
6317db96d56Sopenharmony_ci        data = self.fp.read(amt)
6327db96d56Sopenharmony_ci        if len(data) < amt:
6337db96d56Sopenharmony_ci            raise IncompleteRead(data, amt-len(data))
6347db96d56Sopenharmony_ci        return data
6357db96d56Sopenharmony_ci
6367db96d56Sopenharmony_ci    def _safe_readinto(self, b):
6377db96d56Sopenharmony_ci        """Same as _safe_read, but for reading into a buffer."""
6387db96d56Sopenharmony_ci        amt = len(b)
6397db96d56Sopenharmony_ci        n = self.fp.readinto(b)
6407db96d56Sopenharmony_ci        if n < amt:
6417db96d56Sopenharmony_ci            raise IncompleteRead(bytes(b[:n]), amt-n)
6427db96d56Sopenharmony_ci        return n
6437db96d56Sopenharmony_ci
6447db96d56Sopenharmony_ci    def read1(self, n=-1):
6457db96d56Sopenharmony_ci        """Read with at most one underlying system call.  If at least one
6467db96d56Sopenharmony_ci        byte is buffered, return that instead.
6477db96d56Sopenharmony_ci        """
6487db96d56Sopenharmony_ci        if self.fp is None or self._method == "HEAD":
6497db96d56Sopenharmony_ci            return b""
6507db96d56Sopenharmony_ci        if self.chunked:
6517db96d56Sopenharmony_ci            return self._read1_chunked(n)
6527db96d56Sopenharmony_ci        if self.length is not None and (n < 0 or n > self.length):
6537db96d56Sopenharmony_ci            n = self.length
6547db96d56Sopenharmony_ci        result = self.fp.read1(n)
6557db96d56Sopenharmony_ci        if not result and n:
6567db96d56Sopenharmony_ci            self._close_conn()
6577db96d56Sopenharmony_ci        elif self.length is not None:
6587db96d56Sopenharmony_ci            self.length -= len(result)
6597db96d56Sopenharmony_ci        return result
6607db96d56Sopenharmony_ci
6617db96d56Sopenharmony_ci    def peek(self, n=-1):
6627db96d56Sopenharmony_ci        # Having this enables IOBase.readline() to read more than one
6637db96d56Sopenharmony_ci        # byte at a time
6647db96d56Sopenharmony_ci        if self.fp is None or self._method == "HEAD":
6657db96d56Sopenharmony_ci            return b""
6667db96d56Sopenharmony_ci        if self.chunked:
6677db96d56Sopenharmony_ci            return self._peek_chunked(n)
6687db96d56Sopenharmony_ci        return self.fp.peek(n)
6697db96d56Sopenharmony_ci
6707db96d56Sopenharmony_ci    def readline(self, limit=-1):
6717db96d56Sopenharmony_ci        if self.fp is None or self._method == "HEAD":
6727db96d56Sopenharmony_ci            return b""
6737db96d56Sopenharmony_ci        if self.chunked:
6747db96d56Sopenharmony_ci            # Fallback to IOBase readline which uses peek() and read()
6757db96d56Sopenharmony_ci            return super().readline(limit)
6767db96d56Sopenharmony_ci        if self.length is not None and (limit < 0 or limit > self.length):
6777db96d56Sopenharmony_ci            limit = self.length
6787db96d56Sopenharmony_ci        result = self.fp.readline(limit)
6797db96d56Sopenharmony_ci        if not result and limit:
6807db96d56Sopenharmony_ci            self._close_conn()
6817db96d56Sopenharmony_ci        elif self.length is not None:
6827db96d56Sopenharmony_ci            self.length -= len(result)
6837db96d56Sopenharmony_ci        return result
6847db96d56Sopenharmony_ci
6857db96d56Sopenharmony_ci    def _read1_chunked(self, n):
6867db96d56Sopenharmony_ci        # Strictly speaking, _get_chunk_left() may cause more than one read,
6877db96d56Sopenharmony_ci        # but that is ok, since that is to satisfy the chunked protocol.
6887db96d56Sopenharmony_ci        chunk_left = self._get_chunk_left()
6897db96d56Sopenharmony_ci        if chunk_left is None or n == 0:
6907db96d56Sopenharmony_ci            return b''
6917db96d56Sopenharmony_ci        if not (0 <= n <= chunk_left):
6927db96d56Sopenharmony_ci            n = chunk_left # if n is negative or larger than chunk_left
6937db96d56Sopenharmony_ci        read = self.fp.read1(n)
6947db96d56Sopenharmony_ci        self.chunk_left -= len(read)
6957db96d56Sopenharmony_ci        if not read:
6967db96d56Sopenharmony_ci            raise IncompleteRead(b"")
6977db96d56Sopenharmony_ci        return read
6987db96d56Sopenharmony_ci
6997db96d56Sopenharmony_ci    def _peek_chunked(self, n):
7007db96d56Sopenharmony_ci        # Strictly speaking, _get_chunk_left() may cause more than one read,
7017db96d56Sopenharmony_ci        # but that is ok, since that is to satisfy the chunked protocol.
7027db96d56Sopenharmony_ci        try:
7037db96d56Sopenharmony_ci            chunk_left = self._get_chunk_left()
7047db96d56Sopenharmony_ci        except IncompleteRead:
7057db96d56Sopenharmony_ci            return b'' # peek doesn't worry about protocol
7067db96d56Sopenharmony_ci        if chunk_left is None:
7077db96d56Sopenharmony_ci            return b'' # eof
7087db96d56Sopenharmony_ci        # peek is allowed to return more than requested.  Just request the
7097db96d56Sopenharmony_ci        # entire chunk, and truncate what we get.
7107db96d56Sopenharmony_ci        return self.fp.peek(chunk_left)[:chunk_left]
7117db96d56Sopenharmony_ci
7127db96d56Sopenharmony_ci    def fileno(self):
7137db96d56Sopenharmony_ci        return self.fp.fileno()
7147db96d56Sopenharmony_ci
7157db96d56Sopenharmony_ci    def getheader(self, name, default=None):
7167db96d56Sopenharmony_ci        '''Returns the value of the header matching *name*.
7177db96d56Sopenharmony_ci
7187db96d56Sopenharmony_ci        If there are multiple matching headers, the values are
7197db96d56Sopenharmony_ci        combined into a single string separated by commas and spaces.
7207db96d56Sopenharmony_ci
7217db96d56Sopenharmony_ci        If no matching header is found, returns *default* or None if
7227db96d56Sopenharmony_ci        the *default* is not specified.
7237db96d56Sopenharmony_ci
7247db96d56Sopenharmony_ci        If the headers are unknown, raises http.client.ResponseNotReady.
7257db96d56Sopenharmony_ci
7267db96d56Sopenharmony_ci        '''
7277db96d56Sopenharmony_ci        if self.headers is None:
7287db96d56Sopenharmony_ci            raise ResponseNotReady()
7297db96d56Sopenharmony_ci        headers = self.headers.get_all(name) or default
7307db96d56Sopenharmony_ci        if isinstance(headers, str) or not hasattr(headers, '__iter__'):
7317db96d56Sopenharmony_ci            return headers
7327db96d56Sopenharmony_ci        else:
7337db96d56Sopenharmony_ci            return ', '.join(headers)
7347db96d56Sopenharmony_ci
7357db96d56Sopenharmony_ci    def getheaders(self):
7367db96d56Sopenharmony_ci        """Return list of (header, value) tuples."""
7377db96d56Sopenharmony_ci        if self.headers is None:
7387db96d56Sopenharmony_ci            raise ResponseNotReady()
7397db96d56Sopenharmony_ci        return list(self.headers.items())
7407db96d56Sopenharmony_ci
7417db96d56Sopenharmony_ci    # We override IOBase.__iter__ so that it doesn't check for closed-ness
7427db96d56Sopenharmony_ci
7437db96d56Sopenharmony_ci    def __iter__(self):
7447db96d56Sopenharmony_ci        return self
7457db96d56Sopenharmony_ci
7467db96d56Sopenharmony_ci    # For compatibility with old-style urllib responses.
7477db96d56Sopenharmony_ci
7487db96d56Sopenharmony_ci    def info(self):
7497db96d56Sopenharmony_ci        '''Returns an instance of the class mimetools.Message containing
7507db96d56Sopenharmony_ci        meta-information associated with the URL.
7517db96d56Sopenharmony_ci
7527db96d56Sopenharmony_ci        When the method is HTTP, these headers are those returned by
7537db96d56Sopenharmony_ci        the server at the head of the retrieved HTML page (including
7547db96d56Sopenharmony_ci        Content-Length and Content-Type).
7557db96d56Sopenharmony_ci
7567db96d56Sopenharmony_ci        When the method is FTP, a Content-Length header will be
7577db96d56Sopenharmony_ci        present if (as is now usual) the server passed back a file
7587db96d56Sopenharmony_ci        length in response to the FTP retrieval request. A
7597db96d56Sopenharmony_ci        Content-Type header will be present if the MIME type can be
7607db96d56Sopenharmony_ci        guessed.
7617db96d56Sopenharmony_ci
7627db96d56Sopenharmony_ci        When the method is local-file, returned headers will include
7637db96d56Sopenharmony_ci        a Date representing the file's last-modified time, a
7647db96d56Sopenharmony_ci        Content-Length giving file size, and a Content-Type
7657db96d56Sopenharmony_ci        containing a guess at the file's type. See also the
7667db96d56Sopenharmony_ci        description of the mimetools module.
7677db96d56Sopenharmony_ci
7687db96d56Sopenharmony_ci        '''
7697db96d56Sopenharmony_ci        return self.headers
7707db96d56Sopenharmony_ci
7717db96d56Sopenharmony_ci    def geturl(self):
7727db96d56Sopenharmony_ci        '''Return the real URL of the page.
7737db96d56Sopenharmony_ci
7747db96d56Sopenharmony_ci        In some cases, the HTTP server redirects a client to another
7757db96d56Sopenharmony_ci        URL. The urlopen() function handles this transparently, but in
7767db96d56Sopenharmony_ci        some cases the caller needs to know which URL the client was
7777db96d56Sopenharmony_ci        redirected to. The geturl() method can be used to get at this
7787db96d56Sopenharmony_ci        redirected URL.
7797db96d56Sopenharmony_ci
7807db96d56Sopenharmony_ci        '''
7817db96d56Sopenharmony_ci        return self.url
7827db96d56Sopenharmony_ci
7837db96d56Sopenharmony_ci    def getcode(self):
7847db96d56Sopenharmony_ci        '''Return the HTTP status code that was sent with the response,
7857db96d56Sopenharmony_ci        or None if the URL is not an HTTP URL.
7867db96d56Sopenharmony_ci
7877db96d56Sopenharmony_ci        '''
7887db96d56Sopenharmony_ci        return self.status
7897db96d56Sopenharmony_ci
7907db96d56Sopenharmony_ciclass HTTPConnection:
7917db96d56Sopenharmony_ci
7927db96d56Sopenharmony_ci    _http_vsn = 11
7937db96d56Sopenharmony_ci    _http_vsn_str = 'HTTP/1.1'
7947db96d56Sopenharmony_ci
7957db96d56Sopenharmony_ci    response_class = HTTPResponse
7967db96d56Sopenharmony_ci    default_port = HTTP_PORT
7977db96d56Sopenharmony_ci    auto_open = 1
7987db96d56Sopenharmony_ci    debuglevel = 0
7997db96d56Sopenharmony_ci
8007db96d56Sopenharmony_ci    @staticmethod
8017db96d56Sopenharmony_ci    def _is_textIO(stream):
8027db96d56Sopenharmony_ci        """Test whether a file-like object is a text or a binary stream.
8037db96d56Sopenharmony_ci        """
8047db96d56Sopenharmony_ci        return isinstance(stream, io.TextIOBase)
8057db96d56Sopenharmony_ci
8067db96d56Sopenharmony_ci    @staticmethod
8077db96d56Sopenharmony_ci    def _get_content_length(body, method):
8087db96d56Sopenharmony_ci        """Get the content-length based on the body.
8097db96d56Sopenharmony_ci
8107db96d56Sopenharmony_ci        If the body is None, we set Content-Length: 0 for methods that expect
8117db96d56Sopenharmony_ci        a body (RFC 7230, Section 3.3.2). We also set the Content-Length for
8127db96d56Sopenharmony_ci        any method if the body is a str or bytes-like object and not a file.
8137db96d56Sopenharmony_ci        """
8147db96d56Sopenharmony_ci        if body is None:
8157db96d56Sopenharmony_ci            # do an explicit check for not None here to distinguish
8167db96d56Sopenharmony_ci            # between unset and set but empty
8177db96d56Sopenharmony_ci            if method.upper() in _METHODS_EXPECTING_BODY:
8187db96d56Sopenharmony_ci                return 0
8197db96d56Sopenharmony_ci            else:
8207db96d56Sopenharmony_ci                return None
8217db96d56Sopenharmony_ci
8227db96d56Sopenharmony_ci        if hasattr(body, 'read'):
8237db96d56Sopenharmony_ci            # file-like object.
8247db96d56Sopenharmony_ci            return None
8257db96d56Sopenharmony_ci
8267db96d56Sopenharmony_ci        try:
8277db96d56Sopenharmony_ci            # does it implement the buffer protocol (bytes, bytearray, array)?
8287db96d56Sopenharmony_ci            mv = memoryview(body)
8297db96d56Sopenharmony_ci            return mv.nbytes
8307db96d56Sopenharmony_ci        except TypeError:
8317db96d56Sopenharmony_ci            pass
8327db96d56Sopenharmony_ci
8337db96d56Sopenharmony_ci        if isinstance(body, str):
8347db96d56Sopenharmony_ci            return len(body)
8357db96d56Sopenharmony_ci
8367db96d56Sopenharmony_ci        return None
8377db96d56Sopenharmony_ci
8387db96d56Sopenharmony_ci    def __init__(self, host, port=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
8397db96d56Sopenharmony_ci                 source_address=None, blocksize=8192):
8407db96d56Sopenharmony_ci        self.timeout = timeout
8417db96d56Sopenharmony_ci        self.source_address = source_address
8427db96d56Sopenharmony_ci        self.blocksize = blocksize
8437db96d56Sopenharmony_ci        self.sock = None
8447db96d56Sopenharmony_ci        self._buffer = []
8457db96d56Sopenharmony_ci        self.__response = None
8467db96d56Sopenharmony_ci        self.__state = _CS_IDLE
8477db96d56Sopenharmony_ci        self._method = None
8487db96d56Sopenharmony_ci        self._tunnel_host = None
8497db96d56Sopenharmony_ci        self._tunnel_port = None
8507db96d56Sopenharmony_ci        self._tunnel_headers = {}
8517db96d56Sopenharmony_ci
8527db96d56Sopenharmony_ci        (self.host, self.port) = self._get_hostport(host, port)
8537db96d56Sopenharmony_ci
8547db96d56Sopenharmony_ci        self._validate_host(self.host)
8557db96d56Sopenharmony_ci
8567db96d56Sopenharmony_ci        # This is stored as an instance variable to allow unit
8577db96d56Sopenharmony_ci        # tests to replace it with a suitable mockup
8587db96d56Sopenharmony_ci        self._create_connection = socket.create_connection
8597db96d56Sopenharmony_ci
8607db96d56Sopenharmony_ci    def set_tunnel(self, host, port=None, headers=None):
8617db96d56Sopenharmony_ci        """Set up host and port for HTTP CONNECT tunnelling.
8627db96d56Sopenharmony_ci
8637db96d56Sopenharmony_ci        In a connection that uses HTTP CONNECT tunneling, the host passed to the
8647db96d56Sopenharmony_ci        constructor is used as a proxy server that relays all communication to
8657db96d56Sopenharmony_ci        the endpoint passed to `set_tunnel`. This done by sending an HTTP
8667db96d56Sopenharmony_ci        CONNECT request to the proxy server when the connection is established.
8677db96d56Sopenharmony_ci
8687db96d56Sopenharmony_ci        This method must be called before the HTTP connection has been
8697db96d56Sopenharmony_ci        established.
8707db96d56Sopenharmony_ci
8717db96d56Sopenharmony_ci        The headers argument should be a mapping of extra HTTP headers to send
8727db96d56Sopenharmony_ci        with the CONNECT request.
8737db96d56Sopenharmony_ci        """
8747db96d56Sopenharmony_ci
8757db96d56Sopenharmony_ci        if self.sock:
8767db96d56Sopenharmony_ci            raise RuntimeError("Can't set up tunnel for established connection")
8777db96d56Sopenharmony_ci
8787db96d56Sopenharmony_ci        self._tunnel_host, self._tunnel_port = self._get_hostport(host, port)
8797db96d56Sopenharmony_ci        if headers:
8807db96d56Sopenharmony_ci            self._tunnel_headers = headers
8817db96d56Sopenharmony_ci        else:
8827db96d56Sopenharmony_ci            self._tunnel_headers.clear()
8837db96d56Sopenharmony_ci
8847db96d56Sopenharmony_ci    def _get_hostport(self, host, port):
8857db96d56Sopenharmony_ci        if port is None:
8867db96d56Sopenharmony_ci            i = host.rfind(':')
8877db96d56Sopenharmony_ci            j = host.rfind(']')         # ipv6 addresses have [...]
8887db96d56Sopenharmony_ci            if i > j:
8897db96d56Sopenharmony_ci                try:
8907db96d56Sopenharmony_ci                    port = int(host[i+1:])
8917db96d56Sopenharmony_ci                except ValueError:
8927db96d56Sopenharmony_ci                    if host[i+1:] == "": # http://foo.com:/ == http://foo.com/
8937db96d56Sopenharmony_ci                        port = self.default_port
8947db96d56Sopenharmony_ci                    else:
8957db96d56Sopenharmony_ci                        raise InvalidURL("nonnumeric port: '%s'" % host[i+1:])
8967db96d56Sopenharmony_ci                host = host[:i]
8977db96d56Sopenharmony_ci            else:
8987db96d56Sopenharmony_ci                port = self.default_port
8997db96d56Sopenharmony_ci            if host and host[0] == '[' and host[-1] == ']':
9007db96d56Sopenharmony_ci                host = host[1:-1]
9017db96d56Sopenharmony_ci
9027db96d56Sopenharmony_ci        return (host, port)
9037db96d56Sopenharmony_ci
9047db96d56Sopenharmony_ci    def set_debuglevel(self, level):
9057db96d56Sopenharmony_ci        self.debuglevel = level
9067db96d56Sopenharmony_ci
9077db96d56Sopenharmony_ci    def _tunnel(self):
9087db96d56Sopenharmony_ci        connect = b"CONNECT %s:%d HTTP/1.0\r\n" % (
9097db96d56Sopenharmony_ci            self._tunnel_host.encode("ascii"), self._tunnel_port)
9107db96d56Sopenharmony_ci        headers = [connect]
9117db96d56Sopenharmony_ci        for header, value in self._tunnel_headers.items():
9127db96d56Sopenharmony_ci            headers.append(f"{header}: {value}\r\n".encode("latin-1"))
9137db96d56Sopenharmony_ci        headers.append(b"\r\n")
9147db96d56Sopenharmony_ci        # Making a single send() call instead of one per line encourages
9157db96d56Sopenharmony_ci        # the host OS to use a more optimal packet size instead of
9167db96d56Sopenharmony_ci        # potentially emitting a series of small packets.
9177db96d56Sopenharmony_ci        self.send(b"".join(headers))
9187db96d56Sopenharmony_ci        del headers
9197db96d56Sopenharmony_ci
9207db96d56Sopenharmony_ci        response = self.response_class(self.sock, method=self._method)
9217db96d56Sopenharmony_ci        try:
9227db96d56Sopenharmony_ci            (version, code, message) = response._read_status()
9237db96d56Sopenharmony_ci
9247db96d56Sopenharmony_ci            if code != http.HTTPStatus.OK:
9257db96d56Sopenharmony_ci                self.close()
9267db96d56Sopenharmony_ci                raise OSError(f"Tunnel connection failed: {code} {message.strip()}")
9277db96d56Sopenharmony_ci            while True:
9287db96d56Sopenharmony_ci                line = response.fp.readline(_MAXLINE + 1)
9297db96d56Sopenharmony_ci                if len(line) > _MAXLINE:
9307db96d56Sopenharmony_ci                    raise LineTooLong("header line")
9317db96d56Sopenharmony_ci                if not line:
9327db96d56Sopenharmony_ci                    # for sites which EOF without sending a trailer
9337db96d56Sopenharmony_ci                    break
9347db96d56Sopenharmony_ci                if line in (b'\r\n', b'\n', b''):
9357db96d56Sopenharmony_ci                    break
9367db96d56Sopenharmony_ci
9377db96d56Sopenharmony_ci                if self.debuglevel > 0:
9387db96d56Sopenharmony_ci                    print('header:', line.decode())
9397db96d56Sopenharmony_ci        finally:
9407db96d56Sopenharmony_ci            response.close()
9417db96d56Sopenharmony_ci
9427db96d56Sopenharmony_ci    def connect(self):
9437db96d56Sopenharmony_ci        """Connect to the host and port specified in __init__."""
9447db96d56Sopenharmony_ci        sys.audit("http.client.connect", self, self.host, self.port)
9457db96d56Sopenharmony_ci        self.sock = self._create_connection(
9467db96d56Sopenharmony_ci            (self.host,self.port), self.timeout, self.source_address)
9477db96d56Sopenharmony_ci        # Might fail in OSs that don't implement TCP_NODELAY
9487db96d56Sopenharmony_ci        try:
9497db96d56Sopenharmony_ci            self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
9507db96d56Sopenharmony_ci        except OSError as e:
9517db96d56Sopenharmony_ci            if e.errno != errno.ENOPROTOOPT:
9527db96d56Sopenharmony_ci                raise
9537db96d56Sopenharmony_ci
9547db96d56Sopenharmony_ci        if self._tunnel_host:
9557db96d56Sopenharmony_ci            self._tunnel()
9567db96d56Sopenharmony_ci
9577db96d56Sopenharmony_ci    def close(self):
9587db96d56Sopenharmony_ci        """Close the connection to the HTTP server."""
9597db96d56Sopenharmony_ci        self.__state = _CS_IDLE
9607db96d56Sopenharmony_ci        try:
9617db96d56Sopenharmony_ci            sock = self.sock
9627db96d56Sopenharmony_ci            if sock:
9637db96d56Sopenharmony_ci                self.sock = None
9647db96d56Sopenharmony_ci                sock.close()   # close it manually... there may be other refs
9657db96d56Sopenharmony_ci        finally:
9667db96d56Sopenharmony_ci            response = self.__response
9677db96d56Sopenharmony_ci            if response:
9687db96d56Sopenharmony_ci                self.__response = None
9697db96d56Sopenharmony_ci                response.close()
9707db96d56Sopenharmony_ci
9717db96d56Sopenharmony_ci    def send(self, data):
9727db96d56Sopenharmony_ci        """Send `data' to the server.
9737db96d56Sopenharmony_ci        ``data`` can be a string object, a bytes object, an array object, a
9747db96d56Sopenharmony_ci        file-like object that supports a .read() method, or an iterable object.
9757db96d56Sopenharmony_ci        """
9767db96d56Sopenharmony_ci
9777db96d56Sopenharmony_ci        if self.sock is None:
9787db96d56Sopenharmony_ci            if self.auto_open:
9797db96d56Sopenharmony_ci                self.connect()
9807db96d56Sopenharmony_ci            else:
9817db96d56Sopenharmony_ci                raise NotConnected()
9827db96d56Sopenharmony_ci
9837db96d56Sopenharmony_ci        if self.debuglevel > 0:
9847db96d56Sopenharmony_ci            print("send:", repr(data))
9857db96d56Sopenharmony_ci        if hasattr(data, "read") :
9867db96d56Sopenharmony_ci            if self.debuglevel > 0:
9877db96d56Sopenharmony_ci                print("sending a readable")
9887db96d56Sopenharmony_ci            encode = self._is_textIO(data)
9897db96d56Sopenharmony_ci            if encode and self.debuglevel > 0:
9907db96d56Sopenharmony_ci                print("encoding file using iso-8859-1")
9917db96d56Sopenharmony_ci            while 1:
9927db96d56Sopenharmony_ci                datablock = data.read(self.blocksize)
9937db96d56Sopenharmony_ci                if not datablock:
9947db96d56Sopenharmony_ci                    break
9957db96d56Sopenharmony_ci                if encode:
9967db96d56Sopenharmony_ci                    datablock = datablock.encode("iso-8859-1")
9977db96d56Sopenharmony_ci                sys.audit("http.client.send", self, datablock)
9987db96d56Sopenharmony_ci                self.sock.sendall(datablock)
9997db96d56Sopenharmony_ci            return
10007db96d56Sopenharmony_ci        sys.audit("http.client.send", self, data)
10017db96d56Sopenharmony_ci        try:
10027db96d56Sopenharmony_ci            self.sock.sendall(data)
10037db96d56Sopenharmony_ci        except TypeError:
10047db96d56Sopenharmony_ci            if isinstance(data, collections.abc.Iterable):
10057db96d56Sopenharmony_ci                for d in data:
10067db96d56Sopenharmony_ci                    self.sock.sendall(d)
10077db96d56Sopenharmony_ci            else:
10087db96d56Sopenharmony_ci                raise TypeError("data should be a bytes-like object "
10097db96d56Sopenharmony_ci                                "or an iterable, got %r" % type(data))
10107db96d56Sopenharmony_ci
10117db96d56Sopenharmony_ci    def _output(self, s):
10127db96d56Sopenharmony_ci        """Add a line of output to the current request buffer.
10137db96d56Sopenharmony_ci
10147db96d56Sopenharmony_ci        Assumes that the line does *not* end with \\r\\n.
10157db96d56Sopenharmony_ci        """
10167db96d56Sopenharmony_ci        self._buffer.append(s)
10177db96d56Sopenharmony_ci
10187db96d56Sopenharmony_ci    def _read_readable(self, readable):
10197db96d56Sopenharmony_ci        if self.debuglevel > 0:
10207db96d56Sopenharmony_ci            print("reading a readable")
10217db96d56Sopenharmony_ci        encode = self._is_textIO(readable)
10227db96d56Sopenharmony_ci        if encode and self.debuglevel > 0:
10237db96d56Sopenharmony_ci            print("encoding file using iso-8859-1")
10247db96d56Sopenharmony_ci        while True:
10257db96d56Sopenharmony_ci            datablock = readable.read(self.blocksize)
10267db96d56Sopenharmony_ci            if not datablock:
10277db96d56Sopenharmony_ci                break
10287db96d56Sopenharmony_ci            if encode:
10297db96d56Sopenharmony_ci                datablock = datablock.encode("iso-8859-1")
10307db96d56Sopenharmony_ci            yield datablock
10317db96d56Sopenharmony_ci
10327db96d56Sopenharmony_ci    def _send_output(self, message_body=None, encode_chunked=False):
10337db96d56Sopenharmony_ci        """Send the currently buffered request and clear the buffer.
10347db96d56Sopenharmony_ci
10357db96d56Sopenharmony_ci        Appends an extra \\r\\n to the buffer.
10367db96d56Sopenharmony_ci        A message_body may be specified, to be appended to the request.
10377db96d56Sopenharmony_ci        """
10387db96d56Sopenharmony_ci        self._buffer.extend((b"", b""))
10397db96d56Sopenharmony_ci        msg = b"\r\n".join(self._buffer)
10407db96d56Sopenharmony_ci        del self._buffer[:]
10417db96d56Sopenharmony_ci        self.send(msg)
10427db96d56Sopenharmony_ci
10437db96d56Sopenharmony_ci        if message_body is not None:
10447db96d56Sopenharmony_ci
10457db96d56Sopenharmony_ci            # create a consistent interface to message_body
10467db96d56Sopenharmony_ci            if hasattr(message_body, 'read'):
10477db96d56Sopenharmony_ci                # Let file-like take precedence over byte-like.  This
10487db96d56Sopenharmony_ci                # is needed to allow the current position of mmap'ed
10497db96d56Sopenharmony_ci                # files to be taken into account.
10507db96d56Sopenharmony_ci                chunks = self._read_readable(message_body)
10517db96d56Sopenharmony_ci            else:
10527db96d56Sopenharmony_ci                try:
10537db96d56Sopenharmony_ci                    # this is solely to check to see if message_body
10547db96d56Sopenharmony_ci                    # implements the buffer API.  it /would/ be easier
10557db96d56Sopenharmony_ci                    # to capture if PyObject_CheckBuffer was exposed
10567db96d56Sopenharmony_ci                    # to Python.
10577db96d56Sopenharmony_ci                    memoryview(message_body)
10587db96d56Sopenharmony_ci                except TypeError:
10597db96d56Sopenharmony_ci                    try:
10607db96d56Sopenharmony_ci                        chunks = iter(message_body)
10617db96d56Sopenharmony_ci                    except TypeError:
10627db96d56Sopenharmony_ci                        raise TypeError("message_body should be a bytes-like "
10637db96d56Sopenharmony_ci                                        "object or an iterable, got %r"
10647db96d56Sopenharmony_ci                                        % type(message_body))
10657db96d56Sopenharmony_ci                else:
10667db96d56Sopenharmony_ci                    # the object implements the buffer interface and
10677db96d56Sopenharmony_ci                    # can be passed directly into socket methods
10687db96d56Sopenharmony_ci                    chunks = (message_body,)
10697db96d56Sopenharmony_ci
10707db96d56Sopenharmony_ci            for chunk in chunks:
10717db96d56Sopenharmony_ci                if not chunk:
10727db96d56Sopenharmony_ci                    if self.debuglevel > 0:
10737db96d56Sopenharmony_ci                        print('Zero length chunk ignored')
10747db96d56Sopenharmony_ci                    continue
10757db96d56Sopenharmony_ci
10767db96d56Sopenharmony_ci                if encode_chunked and self._http_vsn == 11:
10777db96d56Sopenharmony_ci                    # chunked encoding
10787db96d56Sopenharmony_ci                    chunk = f'{len(chunk):X}\r\n'.encode('ascii') + chunk \
10797db96d56Sopenharmony_ci                        + b'\r\n'
10807db96d56Sopenharmony_ci                self.send(chunk)
10817db96d56Sopenharmony_ci
10827db96d56Sopenharmony_ci            if encode_chunked and self._http_vsn == 11:
10837db96d56Sopenharmony_ci                # end chunked transfer
10847db96d56Sopenharmony_ci                self.send(b'0\r\n\r\n')
10857db96d56Sopenharmony_ci
10867db96d56Sopenharmony_ci    def putrequest(self, method, url, skip_host=False,
10877db96d56Sopenharmony_ci                   skip_accept_encoding=False):
10887db96d56Sopenharmony_ci        """Send a request to the server.
10897db96d56Sopenharmony_ci
10907db96d56Sopenharmony_ci        `method' specifies an HTTP request method, e.g. 'GET'.
10917db96d56Sopenharmony_ci        `url' specifies the object being requested, e.g. '/index.html'.
10927db96d56Sopenharmony_ci        `skip_host' if True does not add automatically a 'Host:' header
10937db96d56Sopenharmony_ci        `skip_accept_encoding' if True does not add automatically an
10947db96d56Sopenharmony_ci           'Accept-Encoding:' header
10957db96d56Sopenharmony_ci        """
10967db96d56Sopenharmony_ci
10977db96d56Sopenharmony_ci        # if a prior response has been completed, then forget about it.
10987db96d56Sopenharmony_ci        if self.__response and self.__response.isclosed():
10997db96d56Sopenharmony_ci            self.__response = None
11007db96d56Sopenharmony_ci
11017db96d56Sopenharmony_ci
11027db96d56Sopenharmony_ci        # in certain cases, we cannot issue another request on this connection.
11037db96d56Sopenharmony_ci        # this occurs when:
11047db96d56Sopenharmony_ci        #   1) we are in the process of sending a request.   (_CS_REQ_STARTED)
11057db96d56Sopenharmony_ci        #   2) a response to a previous request has signalled that it is going
11067db96d56Sopenharmony_ci        #      to close the connection upon completion.
11077db96d56Sopenharmony_ci        #   3) the headers for the previous response have not been read, thus
11087db96d56Sopenharmony_ci        #      we cannot determine whether point (2) is true.   (_CS_REQ_SENT)
11097db96d56Sopenharmony_ci        #
11107db96d56Sopenharmony_ci        # if there is no prior response, then we can request at will.
11117db96d56Sopenharmony_ci        #
11127db96d56Sopenharmony_ci        # if point (2) is true, then we will have passed the socket to the
11137db96d56Sopenharmony_ci        # response (effectively meaning, "there is no prior response"), and
11147db96d56Sopenharmony_ci        # will open a new one when a new request is made.
11157db96d56Sopenharmony_ci        #
11167db96d56Sopenharmony_ci        # Note: if a prior response exists, then we *can* start a new request.
11177db96d56Sopenharmony_ci        #       We are not allowed to begin fetching the response to this new
11187db96d56Sopenharmony_ci        #       request, however, until that prior response is complete.
11197db96d56Sopenharmony_ci        #
11207db96d56Sopenharmony_ci        if self.__state == _CS_IDLE:
11217db96d56Sopenharmony_ci            self.__state = _CS_REQ_STARTED
11227db96d56Sopenharmony_ci        else:
11237db96d56Sopenharmony_ci            raise CannotSendRequest(self.__state)
11247db96d56Sopenharmony_ci
11257db96d56Sopenharmony_ci        self._validate_method(method)
11267db96d56Sopenharmony_ci
11277db96d56Sopenharmony_ci        # Save the method for use later in the response phase
11287db96d56Sopenharmony_ci        self._method = method
11297db96d56Sopenharmony_ci
11307db96d56Sopenharmony_ci        url = url or '/'
11317db96d56Sopenharmony_ci        self._validate_path(url)
11327db96d56Sopenharmony_ci
11337db96d56Sopenharmony_ci        request = '%s %s %s' % (method, url, self._http_vsn_str)
11347db96d56Sopenharmony_ci
11357db96d56Sopenharmony_ci        self._output(self._encode_request(request))
11367db96d56Sopenharmony_ci
11377db96d56Sopenharmony_ci        if self._http_vsn == 11:
11387db96d56Sopenharmony_ci            # Issue some standard headers for better HTTP/1.1 compliance
11397db96d56Sopenharmony_ci
11407db96d56Sopenharmony_ci            if not skip_host:
11417db96d56Sopenharmony_ci                # this header is issued *only* for HTTP/1.1
11427db96d56Sopenharmony_ci                # connections. more specifically, this means it is
11437db96d56Sopenharmony_ci                # only issued when the client uses the new
11447db96d56Sopenharmony_ci                # HTTPConnection() class. backwards-compat clients
11457db96d56Sopenharmony_ci                # will be using HTTP/1.0 and those clients may be
11467db96d56Sopenharmony_ci                # issuing this header themselves. we should NOT issue
11477db96d56Sopenharmony_ci                # it twice; some web servers (such as Apache) barf
11487db96d56Sopenharmony_ci                # when they see two Host: headers
11497db96d56Sopenharmony_ci
11507db96d56Sopenharmony_ci                # If we need a non-standard port,include it in the
11517db96d56Sopenharmony_ci                # header.  If the request is going through a proxy,
11527db96d56Sopenharmony_ci                # but the host of the actual URL, not the host of the
11537db96d56Sopenharmony_ci                # proxy.
11547db96d56Sopenharmony_ci
11557db96d56Sopenharmony_ci                netloc = ''
11567db96d56Sopenharmony_ci                if url.startswith('http'):
11577db96d56Sopenharmony_ci                    nil, netloc, nil, nil, nil = urlsplit(url)
11587db96d56Sopenharmony_ci
11597db96d56Sopenharmony_ci                if netloc:
11607db96d56Sopenharmony_ci                    try:
11617db96d56Sopenharmony_ci                        netloc_enc = netloc.encode("ascii")
11627db96d56Sopenharmony_ci                    except UnicodeEncodeError:
11637db96d56Sopenharmony_ci                        netloc_enc = netloc.encode("idna")
11647db96d56Sopenharmony_ci                    self.putheader('Host', netloc_enc)
11657db96d56Sopenharmony_ci                else:
11667db96d56Sopenharmony_ci                    if self._tunnel_host:
11677db96d56Sopenharmony_ci                        host = self._tunnel_host
11687db96d56Sopenharmony_ci                        port = self._tunnel_port
11697db96d56Sopenharmony_ci                    else:
11707db96d56Sopenharmony_ci                        host = self.host
11717db96d56Sopenharmony_ci                        port = self.port
11727db96d56Sopenharmony_ci
11737db96d56Sopenharmony_ci                    try:
11747db96d56Sopenharmony_ci                        host_enc = host.encode("ascii")
11757db96d56Sopenharmony_ci                    except UnicodeEncodeError:
11767db96d56Sopenharmony_ci                        host_enc = host.encode("idna")
11777db96d56Sopenharmony_ci
11787db96d56Sopenharmony_ci                    # As per RFC 273, IPv6 address should be wrapped with []
11797db96d56Sopenharmony_ci                    # when used as Host header
11807db96d56Sopenharmony_ci
11817db96d56Sopenharmony_ci                    if host.find(':') >= 0:
11827db96d56Sopenharmony_ci                        host_enc = b'[' + host_enc + b']'
11837db96d56Sopenharmony_ci
11847db96d56Sopenharmony_ci                    if port == self.default_port:
11857db96d56Sopenharmony_ci                        self.putheader('Host', host_enc)
11867db96d56Sopenharmony_ci                    else:
11877db96d56Sopenharmony_ci                        host_enc = host_enc.decode("ascii")
11887db96d56Sopenharmony_ci                        self.putheader('Host', "%s:%s" % (host_enc, port))
11897db96d56Sopenharmony_ci
11907db96d56Sopenharmony_ci            # note: we are assuming that clients will not attempt to set these
11917db96d56Sopenharmony_ci            #       headers since *this* library must deal with the
11927db96d56Sopenharmony_ci            #       consequences. this also means that when the supporting
11937db96d56Sopenharmony_ci            #       libraries are updated to recognize other forms, then this
11947db96d56Sopenharmony_ci            #       code should be changed (removed or updated).
11957db96d56Sopenharmony_ci
11967db96d56Sopenharmony_ci            # we only want a Content-Encoding of "identity" since we don't
11977db96d56Sopenharmony_ci            # support encodings such as x-gzip or x-deflate.
11987db96d56Sopenharmony_ci            if not skip_accept_encoding:
11997db96d56Sopenharmony_ci                self.putheader('Accept-Encoding', 'identity')
12007db96d56Sopenharmony_ci
12017db96d56Sopenharmony_ci            # we can accept "chunked" Transfer-Encodings, but no others
12027db96d56Sopenharmony_ci            # NOTE: no TE header implies *only* "chunked"
12037db96d56Sopenharmony_ci            #self.putheader('TE', 'chunked')
12047db96d56Sopenharmony_ci
12057db96d56Sopenharmony_ci            # if TE is supplied in the header, then it must appear in a
12067db96d56Sopenharmony_ci            # Connection header.
12077db96d56Sopenharmony_ci            #self.putheader('Connection', 'TE')
12087db96d56Sopenharmony_ci
12097db96d56Sopenharmony_ci        else:
12107db96d56Sopenharmony_ci            # For HTTP/1.0, the server will assume "not chunked"
12117db96d56Sopenharmony_ci            pass
12127db96d56Sopenharmony_ci
12137db96d56Sopenharmony_ci    def _encode_request(self, request):
12147db96d56Sopenharmony_ci        # ASCII also helps prevent CVE-2019-9740.
12157db96d56Sopenharmony_ci        return request.encode('ascii')
12167db96d56Sopenharmony_ci
12177db96d56Sopenharmony_ci    def _validate_method(self, method):
12187db96d56Sopenharmony_ci        """Validate a method name for putrequest."""
12197db96d56Sopenharmony_ci        # prevent http header injection
12207db96d56Sopenharmony_ci        match = _contains_disallowed_method_pchar_re.search(method)
12217db96d56Sopenharmony_ci        if match:
12227db96d56Sopenharmony_ci            raise ValueError(
12237db96d56Sopenharmony_ci                    f"method can't contain control characters. {method!r} "
12247db96d56Sopenharmony_ci                    f"(found at least {match.group()!r})")
12257db96d56Sopenharmony_ci
12267db96d56Sopenharmony_ci    def _validate_path(self, url):
12277db96d56Sopenharmony_ci        """Validate a url for putrequest."""
12287db96d56Sopenharmony_ci        # Prevent CVE-2019-9740.
12297db96d56Sopenharmony_ci        match = _contains_disallowed_url_pchar_re.search(url)
12307db96d56Sopenharmony_ci        if match:
12317db96d56Sopenharmony_ci            raise InvalidURL(f"URL can't contain control characters. {url!r} "
12327db96d56Sopenharmony_ci                             f"(found at least {match.group()!r})")
12337db96d56Sopenharmony_ci
12347db96d56Sopenharmony_ci    def _validate_host(self, host):
12357db96d56Sopenharmony_ci        """Validate a host so it doesn't contain control characters."""
12367db96d56Sopenharmony_ci        # Prevent CVE-2019-18348.
12377db96d56Sopenharmony_ci        match = _contains_disallowed_url_pchar_re.search(host)
12387db96d56Sopenharmony_ci        if match:
12397db96d56Sopenharmony_ci            raise InvalidURL(f"URL can't contain control characters. {host!r} "
12407db96d56Sopenharmony_ci                             f"(found at least {match.group()!r})")
12417db96d56Sopenharmony_ci
12427db96d56Sopenharmony_ci    def putheader(self, header, *values):
12437db96d56Sopenharmony_ci        """Send a request header line to the server.
12447db96d56Sopenharmony_ci
12457db96d56Sopenharmony_ci        For example: h.putheader('Accept', 'text/html')
12467db96d56Sopenharmony_ci        """
12477db96d56Sopenharmony_ci        if self.__state != _CS_REQ_STARTED:
12487db96d56Sopenharmony_ci            raise CannotSendHeader()
12497db96d56Sopenharmony_ci
12507db96d56Sopenharmony_ci        if hasattr(header, 'encode'):
12517db96d56Sopenharmony_ci            header = header.encode('ascii')
12527db96d56Sopenharmony_ci
12537db96d56Sopenharmony_ci        if not _is_legal_header_name(header):
12547db96d56Sopenharmony_ci            raise ValueError('Invalid header name %r' % (header,))
12557db96d56Sopenharmony_ci
12567db96d56Sopenharmony_ci        values = list(values)
12577db96d56Sopenharmony_ci        for i, one_value in enumerate(values):
12587db96d56Sopenharmony_ci            if hasattr(one_value, 'encode'):
12597db96d56Sopenharmony_ci                values[i] = one_value.encode('latin-1')
12607db96d56Sopenharmony_ci            elif isinstance(one_value, int):
12617db96d56Sopenharmony_ci                values[i] = str(one_value).encode('ascii')
12627db96d56Sopenharmony_ci
12637db96d56Sopenharmony_ci            if _is_illegal_header_value(values[i]):
12647db96d56Sopenharmony_ci                raise ValueError('Invalid header value %r' % (values[i],))
12657db96d56Sopenharmony_ci
12667db96d56Sopenharmony_ci        value = b'\r\n\t'.join(values)
12677db96d56Sopenharmony_ci        header = header + b': ' + value
12687db96d56Sopenharmony_ci        self._output(header)
12697db96d56Sopenharmony_ci
12707db96d56Sopenharmony_ci    def endheaders(self, message_body=None, *, encode_chunked=False):
12717db96d56Sopenharmony_ci        """Indicate that the last header line has been sent to the server.
12727db96d56Sopenharmony_ci
12737db96d56Sopenharmony_ci        This method sends the request to the server.  The optional message_body
12747db96d56Sopenharmony_ci        argument can be used to pass a message body associated with the
12757db96d56Sopenharmony_ci        request.
12767db96d56Sopenharmony_ci        """
12777db96d56Sopenharmony_ci        if self.__state == _CS_REQ_STARTED:
12787db96d56Sopenharmony_ci            self.__state = _CS_REQ_SENT
12797db96d56Sopenharmony_ci        else:
12807db96d56Sopenharmony_ci            raise CannotSendHeader()
12817db96d56Sopenharmony_ci        self._send_output(message_body, encode_chunked=encode_chunked)
12827db96d56Sopenharmony_ci
12837db96d56Sopenharmony_ci    def request(self, method, url, body=None, headers={}, *,
12847db96d56Sopenharmony_ci                encode_chunked=False):
12857db96d56Sopenharmony_ci        """Send a complete request to the server."""
12867db96d56Sopenharmony_ci        self._send_request(method, url, body, headers, encode_chunked)
12877db96d56Sopenharmony_ci
12887db96d56Sopenharmony_ci    def _send_request(self, method, url, body, headers, encode_chunked):
12897db96d56Sopenharmony_ci        # Honor explicitly requested Host: and Accept-Encoding: headers.
12907db96d56Sopenharmony_ci        header_names = frozenset(k.lower() for k in headers)
12917db96d56Sopenharmony_ci        skips = {}
12927db96d56Sopenharmony_ci        if 'host' in header_names:
12937db96d56Sopenharmony_ci            skips['skip_host'] = 1
12947db96d56Sopenharmony_ci        if 'accept-encoding' in header_names:
12957db96d56Sopenharmony_ci            skips['skip_accept_encoding'] = 1
12967db96d56Sopenharmony_ci
12977db96d56Sopenharmony_ci        self.putrequest(method, url, **skips)
12987db96d56Sopenharmony_ci
12997db96d56Sopenharmony_ci        # chunked encoding will happen if HTTP/1.1 is used and either
13007db96d56Sopenharmony_ci        # the caller passes encode_chunked=True or the following
13017db96d56Sopenharmony_ci        # conditions hold:
13027db96d56Sopenharmony_ci        # 1. content-length has not been explicitly set
13037db96d56Sopenharmony_ci        # 2. the body is a file or iterable, but not a str or bytes-like
13047db96d56Sopenharmony_ci        # 3. Transfer-Encoding has NOT been explicitly set by the caller
13057db96d56Sopenharmony_ci
13067db96d56Sopenharmony_ci        if 'content-length' not in header_names:
13077db96d56Sopenharmony_ci            # only chunk body if not explicitly set for backwards
13087db96d56Sopenharmony_ci            # compatibility, assuming the client code is already handling the
13097db96d56Sopenharmony_ci            # chunking
13107db96d56Sopenharmony_ci            if 'transfer-encoding' not in header_names:
13117db96d56Sopenharmony_ci                # if content-length cannot be automatically determined, fall
13127db96d56Sopenharmony_ci                # back to chunked encoding
13137db96d56Sopenharmony_ci                encode_chunked = False
13147db96d56Sopenharmony_ci                content_length = self._get_content_length(body, method)
13157db96d56Sopenharmony_ci                if content_length is None:
13167db96d56Sopenharmony_ci                    if body is not None:
13177db96d56Sopenharmony_ci                        if self.debuglevel > 0:
13187db96d56Sopenharmony_ci                            print('Unable to determine size of %r' % body)
13197db96d56Sopenharmony_ci                        encode_chunked = True
13207db96d56Sopenharmony_ci                        self.putheader('Transfer-Encoding', 'chunked')
13217db96d56Sopenharmony_ci                else:
13227db96d56Sopenharmony_ci                    self.putheader('Content-Length', str(content_length))
13237db96d56Sopenharmony_ci        else:
13247db96d56Sopenharmony_ci            encode_chunked = False
13257db96d56Sopenharmony_ci
13267db96d56Sopenharmony_ci        for hdr, value in headers.items():
13277db96d56Sopenharmony_ci            self.putheader(hdr, value)
13287db96d56Sopenharmony_ci        if isinstance(body, str):
13297db96d56Sopenharmony_ci            # RFC 2616 Section 3.7.1 says that text default has a
13307db96d56Sopenharmony_ci            # default charset of iso-8859-1.
13317db96d56Sopenharmony_ci            body = _encode(body, 'body')
13327db96d56Sopenharmony_ci        self.endheaders(body, encode_chunked=encode_chunked)
13337db96d56Sopenharmony_ci
13347db96d56Sopenharmony_ci    def getresponse(self):
13357db96d56Sopenharmony_ci        """Get the response from the server.
13367db96d56Sopenharmony_ci
13377db96d56Sopenharmony_ci        If the HTTPConnection is in the correct state, returns an
13387db96d56Sopenharmony_ci        instance of HTTPResponse or of whatever object is returned by
13397db96d56Sopenharmony_ci        the response_class variable.
13407db96d56Sopenharmony_ci
13417db96d56Sopenharmony_ci        If a request has not been sent or if a previous response has
13427db96d56Sopenharmony_ci        not be handled, ResponseNotReady is raised.  If the HTTP
13437db96d56Sopenharmony_ci        response indicates that the connection should be closed, then
13447db96d56Sopenharmony_ci        it will be closed before the response is returned.  When the
13457db96d56Sopenharmony_ci        connection is closed, the underlying socket is closed.
13467db96d56Sopenharmony_ci        """
13477db96d56Sopenharmony_ci
13487db96d56Sopenharmony_ci        # if a prior response has been completed, then forget about it.
13497db96d56Sopenharmony_ci        if self.__response and self.__response.isclosed():
13507db96d56Sopenharmony_ci            self.__response = None
13517db96d56Sopenharmony_ci
13527db96d56Sopenharmony_ci        # if a prior response exists, then it must be completed (otherwise, we
13537db96d56Sopenharmony_ci        # cannot read this response's header to determine the connection-close
13547db96d56Sopenharmony_ci        # behavior)
13557db96d56Sopenharmony_ci        #
13567db96d56Sopenharmony_ci        # note: if a prior response existed, but was connection-close, then the
13577db96d56Sopenharmony_ci        # socket and response were made independent of this HTTPConnection
13587db96d56Sopenharmony_ci        # object since a new request requires that we open a whole new
13597db96d56Sopenharmony_ci        # connection
13607db96d56Sopenharmony_ci        #
13617db96d56Sopenharmony_ci        # this means the prior response had one of two states:
13627db96d56Sopenharmony_ci        #   1) will_close: this connection was reset and the prior socket and
13637db96d56Sopenharmony_ci        #                  response operate independently
13647db96d56Sopenharmony_ci        #   2) persistent: the response was retained and we await its
13657db96d56Sopenharmony_ci        #                  isclosed() status to become true.
13667db96d56Sopenharmony_ci        #
13677db96d56Sopenharmony_ci        if self.__state != _CS_REQ_SENT or self.__response:
13687db96d56Sopenharmony_ci            raise ResponseNotReady(self.__state)
13697db96d56Sopenharmony_ci
13707db96d56Sopenharmony_ci        if self.debuglevel > 0:
13717db96d56Sopenharmony_ci            response = self.response_class(self.sock, self.debuglevel,
13727db96d56Sopenharmony_ci                                           method=self._method)
13737db96d56Sopenharmony_ci        else:
13747db96d56Sopenharmony_ci            response = self.response_class(self.sock, method=self._method)
13757db96d56Sopenharmony_ci
13767db96d56Sopenharmony_ci        try:
13777db96d56Sopenharmony_ci            try:
13787db96d56Sopenharmony_ci                response.begin()
13797db96d56Sopenharmony_ci            except ConnectionError:
13807db96d56Sopenharmony_ci                self.close()
13817db96d56Sopenharmony_ci                raise
13827db96d56Sopenharmony_ci            assert response.will_close != _UNKNOWN
13837db96d56Sopenharmony_ci            self.__state = _CS_IDLE
13847db96d56Sopenharmony_ci
13857db96d56Sopenharmony_ci            if response.will_close:
13867db96d56Sopenharmony_ci                # this effectively passes the connection to the response
13877db96d56Sopenharmony_ci                self.close()
13887db96d56Sopenharmony_ci            else:
13897db96d56Sopenharmony_ci                # remember this, so we can tell when it is complete
13907db96d56Sopenharmony_ci                self.__response = response
13917db96d56Sopenharmony_ci
13927db96d56Sopenharmony_ci            return response
13937db96d56Sopenharmony_ci        except:
13947db96d56Sopenharmony_ci            response.close()
13957db96d56Sopenharmony_ci            raise
13967db96d56Sopenharmony_ci
13977db96d56Sopenharmony_citry:
13987db96d56Sopenharmony_ci    import ssl
13997db96d56Sopenharmony_ciexcept ImportError:
14007db96d56Sopenharmony_ci    pass
14017db96d56Sopenharmony_cielse:
14027db96d56Sopenharmony_ci    class HTTPSConnection(HTTPConnection):
14037db96d56Sopenharmony_ci        "This class allows communication via SSL."
14047db96d56Sopenharmony_ci
14057db96d56Sopenharmony_ci        default_port = HTTPS_PORT
14067db96d56Sopenharmony_ci
14077db96d56Sopenharmony_ci        # XXX Should key_file and cert_file be deprecated in favour of context?
14087db96d56Sopenharmony_ci
14097db96d56Sopenharmony_ci        def __init__(self, host, port=None, key_file=None, cert_file=None,
14107db96d56Sopenharmony_ci                     timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
14117db96d56Sopenharmony_ci                     source_address=None, *, context=None,
14127db96d56Sopenharmony_ci                     check_hostname=None, blocksize=8192):
14137db96d56Sopenharmony_ci            super(HTTPSConnection, self).__init__(host, port, timeout,
14147db96d56Sopenharmony_ci                                                  source_address,
14157db96d56Sopenharmony_ci                                                  blocksize=blocksize)
14167db96d56Sopenharmony_ci            if (key_file is not None or cert_file is not None or
14177db96d56Sopenharmony_ci                        check_hostname is not None):
14187db96d56Sopenharmony_ci                import warnings
14197db96d56Sopenharmony_ci                warnings.warn("key_file, cert_file and check_hostname are "
14207db96d56Sopenharmony_ci                              "deprecated, use a custom context instead.",
14217db96d56Sopenharmony_ci                              DeprecationWarning, 2)
14227db96d56Sopenharmony_ci            self.key_file = key_file
14237db96d56Sopenharmony_ci            self.cert_file = cert_file
14247db96d56Sopenharmony_ci            if context is None:
14257db96d56Sopenharmony_ci                context = ssl._create_default_https_context()
14267db96d56Sopenharmony_ci                # send ALPN extension to indicate HTTP/1.1 protocol
14277db96d56Sopenharmony_ci                if self._http_vsn == 11:
14287db96d56Sopenharmony_ci                    context.set_alpn_protocols(['http/1.1'])
14297db96d56Sopenharmony_ci                # enable PHA for TLS 1.3 connections if available
14307db96d56Sopenharmony_ci                if context.post_handshake_auth is not None:
14317db96d56Sopenharmony_ci                    context.post_handshake_auth = True
14327db96d56Sopenharmony_ci            will_verify = context.verify_mode != ssl.CERT_NONE
14337db96d56Sopenharmony_ci            if check_hostname is None:
14347db96d56Sopenharmony_ci                check_hostname = context.check_hostname
14357db96d56Sopenharmony_ci            if check_hostname and not will_verify:
14367db96d56Sopenharmony_ci                raise ValueError("check_hostname needs a SSL context with "
14377db96d56Sopenharmony_ci                                 "either CERT_OPTIONAL or CERT_REQUIRED")
14387db96d56Sopenharmony_ci            if key_file or cert_file:
14397db96d56Sopenharmony_ci                context.load_cert_chain(cert_file, key_file)
14407db96d56Sopenharmony_ci                # cert and key file means the user wants to authenticate.
14417db96d56Sopenharmony_ci                # enable TLS 1.3 PHA implicitly even for custom contexts.
14427db96d56Sopenharmony_ci                if context.post_handshake_auth is not None:
14437db96d56Sopenharmony_ci                    context.post_handshake_auth = True
14447db96d56Sopenharmony_ci            self._context = context
14457db96d56Sopenharmony_ci            if check_hostname is not None:
14467db96d56Sopenharmony_ci                self._context.check_hostname = check_hostname
14477db96d56Sopenharmony_ci
14487db96d56Sopenharmony_ci        def connect(self):
14497db96d56Sopenharmony_ci            "Connect to a host on a given (SSL) port."
14507db96d56Sopenharmony_ci
14517db96d56Sopenharmony_ci            super().connect()
14527db96d56Sopenharmony_ci
14537db96d56Sopenharmony_ci            if self._tunnel_host:
14547db96d56Sopenharmony_ci                server_hostname = self._tunnel_host
14557db96d56Sopenharmony_ci            else:
14567db96d56Sopenharmony_ci                server_hostname = self.host
14577db96d56Sopenharmony_ci
14587db96d56Sopenharmony_ci            self.sock = self._context.wrap_socket(self.sock,
14597db96d56Sopenharmony_ci                                                  server_hostname=server_hostname)
14607db96d56Sopenharmony_ci
14617db96d56Sopenharmony_ci    __all__.append("HTTPSConnection")
14627db96d56Sopenharmony_ci
14637db96d56Sopenharmony_ciclass HTTPException(Exception):
14647db96d56Sopenharmony_ci    # Subclasses that define an __init__ must call Exception.__init__
14657db96d56Sopenharmony_ci    # or define self.args.  Otherwise, str() will fail.
14667db96d56Sopenharmony_ci    pass
14677db96d56Sopenharmony_ci
14687db96d56Sopenharmony_ciclass NotConnected(HTTPException):
14697db96d56Sopenharmony_ci    pass
14707db96d56Sopenharmony_ci
14717db96d56Sopenharmony_ciclass InvalidURL(HTTPException):
14727db96d56Sopenharmony_ci    pass
14737db96d56Sopenharmony_ci
14747db96d56Sopenharmony_ciclass UnknownProtocol(HTTPException):
14757db96d56Sopenharmony_ci    def __init__(self, version):
14767db96d56Sopenharmony_ci        self.args = version,
14777db96d56Sopenharmony_ci        self.version = version
14787db96d56Sopenharmony_ci
14797db96d56Sopenharmony_ciclass UnknownTransferEncoding(HTTPException):
14807db96d56Sopenharmony_ci    pass
14817db96d56Sopenharmony_ci
14827db96d56Sopenharmony_ciclass UnimplementedFileMode(HTTPException):
14837db96d56Sopenharmony_ci    pass
14847db96d56Sopenharmony_ci
14857db96d56Sopenharmony_ciclass IncompleteRead(HTTPException):
14867db96d56Sopenharmony_ci    def __init__(self, partial, expected=None):
14877db96d56Sopenharmony_ci        self.args = partial,
14887db96d56Sopenharmony_ci        self.partial = partial
14897db96d56Sopenharmony_ci        self.expected = expected
14907db96d56Sopenharmony_ci    def __repr__(self):
14917db96d56Sopenharmony_ci        if self.expected is not None:
14927db96d56Sopenharmony_ci            e = ', %i more expected' % self.expected
14937db96d56Sopenharmony_ci        else:
14947db96d56Sopenharmony_ci            e = ''
14957db96d56Sopenharmony_ci        return '%s(%i bytes read%s)' % (self.__class__.__name__,
14967db96d56Sopenharmony_ci                                        len(self.partial), e)
14977db96d56Sopenharmony_ci    __str__ = object.__str__
14987db96d56Sopenharmony_ci
14997db96d56Sopenharmony_ciclass ImproperConnectionState(HTTPException):
15007db96d56Sopenharmony_ci    pass
15017db96d56Sopenharmony_ci
15027db96d56Sopenharmony_ciclass CannotSendRequest(ImproperConnectionState):
15037db96d56Sopenharmony_ci    pass
15047db96d56Sopenharmony_ci
15057db96d56Sopenharmony_ciclass CannotSendHeader(ImproperConnectionState):
15067db96d56Sopenharmony_ci    pass
15077db96d56Sopenharmony_ci
15087db96d56Sopenharmony_ciclass ResponseNotReady(ImproperConnectionState):
15097db96d56Sopenharmony_ci    pass
15107db96d56Sopenharmony_ci
15117db96d56Sopenharmony_ciclass BadStatusLine(HTTPException):
15127db96d56Sopenharmony_ci    def __init__(self, line):
15137db96d56Sopenharmony_ci        if not line:
15147db96d56Sopenharmony_ci            line = repr(line)
15157db96d56Sopenharmony_ci        self.args = line,
15167db96d56Sopenharmony_ci        self.line = line
15177db96d56Sopenharmony_ci
15187db96d56Sopenharmony_ciclass LineTooLong(HTTPException):
15197db96d56Sopenharmony_ci    def __init__(self, line_type):
15207db96d56Sopenharmony_ci        HTTPException.__init__(self, "got more than %d bytes when reading %s"
15217db96d56Sopenharmony_ci                                     % (_MAXLINE, line_type))
15227db96d56Sopenharmony_ci
15237db96d56Sopenharmony_ciclass RemoteDisconnected(ConnectionResetError, BadStatusLine):
15247db96d56Sopenharmony_ci    def __init__(self, *pos, **kw):
15257db96d56Sopenharmony_ci        BadStatusLine.__init__(self, "")
15267db96d56Sopenharmony_ci        ConnectionResetError.__init__(self, *pos, **kw)
15277db96d56Sopenharmony_ci
15287db96d56Sopenharmony_ci# for backwards compatibility
15297db96d56Sopenharmony_cierror = HTTPException
1530