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