summaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Lib/http
diff options
context:
space:
mode:
authorshadchin <[email protected]>2022-04-18 12:39:32 +0300
committershadchin <[email protected]>2022-04-18 12:39:32 +0300
commitd4be68e361f4258cf0848fc70018dfe37a2acc24 (patch)
tree153e294cd97ac8b5d7a989612704a0c1f58e8ad4 /contrib/tools/python3/src/Lib/http
parent260c02f5ccf242d9d9b8a873afaf6588c00237d6 (diff)
IGNIETFERRO-1816 Update Python 3 from 3.9.12 to 3.10.4
ref:9f96be6d02ee8044fdd6f124b799b270c20ce641
Diffstat (limited to 'contrib/tools/python3/src/Lib/http')
-rw-r--r--contrib/tools/python3/src/Lib/http/__init__.py1
-rw-r--r--contrib/tools/python3/src/Lib/http/client.py84
-rw-r--r--contrib/tools/python3/src/Lib/http/cookiejar.py40
-rw-r--r--contrib/tools/python3/src/Lib/http/server.py5
4 files changed, 71 insertions, 59 deletions
diff --git a/contrib/tools/python3/src/Lib/http/__init__.py b/contrib/tools/python3/src/Lib/http/__init__.py
index 37be765349e..bf8d7d68868 100644
--- a/contrib/tools/python3/src/Lib/http/__init__.py
+++ b/contrib/tools/python3/src/Lib/http/__init__.py
@@ -2,6 +2,7 @@ from enum import IntEnum
__all__ = ['HTTPStatus']
+
class HTTPStatus(IntEnum):
"""HTTP status codes and reason phrases
diff --git a/contrib/tools/python3/src/Lib/http/client.py b/contrib/tools/python3/src/Lib/http/client.py
index a98432e5685..a6ab135b2c3 100644
--- a/contrib/tools/python3/src/Lib/http/client.py
+++ b/contrib/tools/python3/src/Lib/http/client.py
@@ -75,6 +75,7 @@ import http
import io
import re
import socket
+import sys
import collections.abc
from urllib.parse import urlsplit
@@ -106,9 +107,6 @@ globals().update(http.HTTPStatus.__members__)
# Mapping status codes to official W3C names
responses = {v: v.phrase for v in http.HTTPStatus.__members__.values()}
-# maximal amount of data to read at one time in _safe_read
-MAXAMOUNT = 1048576
-
# maximal line length when calling readline().
_MAXLINE = 65536
_MAXHEADERS = 100
@@ -457,18 +455,25 @@ class HTTPResponse(io.BufferedIOBase):
self._close_conn()
return b""
+ if self.chunked:
+ return self._read_chunked(amt)
+
if amt is not None:
- # Amount is given, implement using readinto
- b = bytearray(amt)
- n = self.readinto(b)
- return memoryview(b)[:n].tobytes()
+ if self.length is not None and amt > self.length:
+ # clip the read to the "end of response"
+ amt = self.length
+ s = self.fp.read(amt)
+ if not s and amt:
+ # Ideally, we would raise IncompleteRead if the content-length
+ # wasn't satisfied, but it might break compatibility.
+ self._close_conn()
+ elif self.length is not None:
+ self.length -= len(s)
+ if not self.length:
+ self._close_conn()
+ return s
else:
# Amount is not given (unbounded read) so we must check self.length
- # and self.chunked
-
- if self.chunked:
- return self._readall_chunked()
-
if self.length is None:
s = self.fp.read()
else:
@@ -569,7 +574,7 @@ class HTTPResponse(io.BufferedIOBase):
self.chunk_left = chunk_left
return chunk_left
- def _readall_chunked(self):
+ def _read_chunked(self, amt=None):
assert self.chunked != _UNKNOWN
value = []
try:
@@ -577,7 +582,15 @@ class HTTPResponse(io.BufferedIOBase):
chunk_left = self._get_chunk_left()
if chunk_left is None:
break
+
+ if amt is not None and amt <= chunk_left:
+ value.append(self._safe_read(amt))
+ self.chunk_left = chunk_left - amt
+ break
+
value.append(self._safe_read(chunk_left))
+ if amt is not None:
+ amt -= chunk_left
self.chunk_left = 0
return b''.join(value)
except IncompleteRead:
@@ -608,43 +621,24 @@ class HTTPResponse(io.BufferedIOBase):
raise IncompleteRead(bytes(b[0:total_bytes]))
def _safe_read(self, amt):
- """Read the number of bytes requested, compensating for partial reads.
-
- Normally, we have a blocking socket, but a read() can be interrupted
- by a signal (resulting in a partial read).
-
- Note that we cannot distinguish between EOF and an interrupt when zero
- bytes have been read. IncompleteRead() will be raised in this
- situation.
+ """Read the number of bytes requested.
This function should be used when <amt> bytes "should" be present for
reading. If the bytes are truly not available (due to EOF), then the
IncompleteRead exception can be used to detect the problem.
"""
- s = []
- while amt > 0:
- chunk = self.fp.read(min(amt, MAXAMOUNT))
- if not chunk:
- raise IncompleteRead(b''.join(s), amt)
- s.append(chunk)
- amt -= len(chunk)
- return b"".join(s)
+ data = self.fp.read(amt)
+ if len(data) < amt:
+ raise IncompleteRead(data, amt-len(data))
+ return data
def _safe_readinto(self, b):
"""Same as _safe_read, but for reading into a buffer."""
- total_bytes = 0
- mvb = memoryview(b)
- while total_bytes < len(b):
- if MAXAMOUNT < len(mvb):
- temp_mvb = mvb[0:MAXAMOUNT]
- n = self.fp.readinto(temp_mvb)
- else:
- n = self.fp.readinto(mvb)
- if not n:
- raise IncompleteRead(bytes(mvb[0:total_bytes]), len(b))
- mvb = mvb[n:]
- total_bytes += n
- return total_bytes
+ amt = len(b)
+ n = self.fp.readinto(b)
+ if n < amt:
+ raise IncompleteRead(bytes(b[:n]), amt-n)
+ return n
def read1(self, n=-1):
"""Read with at most one underlying system call. If at least one
@@ -943,6 +937,7 @@ class HTTPConnection:
def connect(self):
"""Connect to the host and port specified in __init__."""
+ sys.audit("http.client.connect", self, self.host, self.port)
self.sock = self._create_connection(
(self.host,self.port), self.timeout, self.source_address)
# Might fail in OSs that don't implement TCP_NODELAY
@@ -995,8 +990,10 @@ class HTTPConnection:
break
if encode:
datablock = datablock.encode("iso-8859-1")
+ sys.audit("http.client.send", self, datablock)
self.sock.sendall(datablock)
return
+ sys.audit("http.client.send", self, data)
try:
self.sock.sendall(data)
except TypeError:
@@ -1422,6 +1419,9 @@ else:
self.cert_file = cert_file
if context is None:
context = ssl._create_default_https_context()
+ # send ALPN extension to indicate HTTP/1.1 protocol
+ if self._http_vsn == 11:
+ context.set_alpn_protocols(['http/1.1'])
# enable PHA for TLS 1.3 connections if available
if context.post_handshake_auth is not None:
context.post_handshake_auth = True
diff --git a/contrib/tools/python3/src/Lib/http/cookiejar.py b/contrib/tools/python3/src/Lib/http/cookiejar.py
index 47ed5c3d64a..eaa76c26b9c 100644
--- a/contrib/tools/python3/src/Lib/http/cookiejar.py
+++ b/contrib/tools/python3/src/Lib/http/cookiejar.py
@@ -50,10 +50,18 @@ def _debug(*args):
logger = logging.getLogger("http.cookiejar")
return logger.debug(*args)
-
+HTTPONLY_ATTR = "HTTPOnly"
+HTTPONLY_PREFIX = "#HttpOnly_"
DEFAULT_HTTP_PORT = str(http.client.HTTP_PORT)
+NETSCAPE_MAGIC_RGX = re.compile("#( Netscape)? HTTP Cookie File")
MISSING_FILENAME_TEXT = ("a filename was not supplied (nor was the CookieJar "
"instance initialised with one)")
+NETSCAPE_HEADER_TEXT = """\
+# Netscape HTTP Cookie File
+# http://curl.haxx.se/rfc/cookie_spec.html
+# This is a generated file! Do not edit.
+
+"""
def _warn_unhandled_exception():
# There are a few catch-all except: statements in this module, for
@@ -2004,19 +2012,11 @@ class MozillaCookieJar(FileCookieJar):
header by default (Mozilla can cope with that).
"""
- magic_re = re.compile("#( Netscape)? HTTP Cookie File")
- header = """\
-# Netscape HTTP Cookie File
-# http://curl.haxx.se/rfc/cookie_spec.html
-# This is a generated file! Do not edit.
-
-"""
def _really_load(self, f, filename, ignore_discard, ignore_expires):
now = time.time()
- magic = f.readline()
- if not self.magic_re.search(magic):
+ if not NETSCAPE_MAGIC_RGX.match(f.readline()):
raise LoadError(
"%r does not look like a Netscape format cookies file" %
filename)
@@ -2024,8 +2024,17 @@ class MozillaCookieJar(FileCookieJar):
try:
while 1:
line = f.readline()
+ rest = {}
+
if line == "": break
+ # httponly is a cookie flag as defined in rfc6265
+ # when encoded in a netscape cookie file,
+ # the line is prepended with "#HttpOnly_"
+ if line.startswith(HTTPONLY_PREFIX):
+ rest[HTTPONLY_ATTR] = ""
+ line = line[len(HTTPONLY_PREFIX):]
+
# last field may be absent, so keep any trailing tab
if line.endswith("\n"): line = line[:-1]
@@ -2063,7 +2072,7 @@ class MozillaCookieJar(FileCookieJar):
discard,
None,
None,
- {})
+ rest)
if not ignore_discard and c.discard:
continue
if not ignore_expires and c.is_expired(now):
@@ -2083,16 +2092,17 @@ class MozillaCookieJar(FileCookieJar):
else: raise ValueError(MISSING_FILENAME_TEXT)
with open(filename, "w") as f:
- f.write(self.header)
+ f.write(NETSCAPE_HEADER_TEXT)
now = time.time()
for cookie in self:
+ domain = cookie.domain
if not ignore_discard and cookie.discard:
continue
if not ignore_expires and cookie.is_expired(now):
continue
if cookie.secure: secure = "TRUE"
else: secure = "FALSE"
- if cookie.domain.startswith("."): initial_dot = "TRUE"
+ if domain.startswith("."): initial_dot = "TRUE"
else: initial_dot = "FALSE"
if cookie.expires is not None:
expires = str(cookie.expires)
@@ -2107,7 +2117,9 @@ class MozillaCookieJar(FileCookieJar):
else:
name = cookie.name
value = cookie.value
+ if cookie.has_nonstandard_attr(HTTPONLY_ATTR):
+ domain = HTTPONLY_PREFIX + domain
f.write(
- "\t".join([cookie.domain, initial_dot, cookie.path,
+ "\t".join([domain, initial_dot, cookie.path,
secure, expires, name, value])+
"\n")
diff --git a/contrib/tools/python3/src/Lib/http/server.py b/contrib/tools/python3/src/Lib/http/server.py
index 2d2300c2aea..58abadf7377 100644
--- a/contrib/tools/python3/src/Lib/http/server.py
+++ b/contrib/tools/python3/src/Lib/http/server.py
@@ -412,7 +412,7 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
method = getattr(self, mname)
method()
self.wfile.flush() #actually send the response if not already done.
- except socket.timeout as e:
+ except TimeoutError as e:
#a read or a write timed out. Discard this connection
self.log_error("Request timed out: %r", e)
self.close_connection = True
@@ -1091,8 +1091,7 @@ class CGIHTTPRequestHandler(SimpleHTTPRequestHandler):
env['PATH_INFO'] = uqrest
env['PATH_TRANSLATED'] = self.translate_path(uqrest)
env['SCRIPT_NAME'] = scriptname
- if query:
- env['QUERY_STRING'] = query
+ env['QUERY_STRING'] = query
env['REMOTE_ADDR'] = self.client_address[0]
authorization = self.headers.get("authorization")
if authorization: