summaryrefslogtreecommitdiffstats
path: root/Lib/http
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/http')
-rw-r--r--Lib/http/client.py88
1 files changed, 60 insertions, 28 deletions
diff --git a/Lib/http/client.py b/Lib/http/client.py
index 6547f85..4885f5a 100644
--- a/Lib/http/client.py
+++ b/Lib/http/client.py
@@ -204,6 +204,12 @@ responses = {
MAXAMOUNT = 1048576
class HTTPMessage(email.message.Message):
+ # XXX The only usage of this method is in
+ # http.server.CGIHTTPRequestHandler. Maybe move the code there so
+ # that it doesn't need to be part of the public API. The API has
+ # never been defined so this could cause backwards compatibility
+ # issues.
+
def getallmatchingheaders(self, name):
"""Find all header lines matching a given header name.
@@ -261,20 +267,26 @@ class HTTPResponse(io.RawIOBase):
# text following RFC 2047. The basic status line parsing only
# accepts iso-8859-1.
- def __init__(self, sock, debuglevel=0, strict=0, method=None):
- # If the response includes a content-length header, we
- # need to make sure that the client doesn't read more than the
+ def __init__(self, sock, debuglevel=0, strict=0, method=None, url=None):
+ # If the response includes a content-length header, we need to
+ # make sure that the client doesn't read more than the
# specified number of bytes. If it does, it will block until
- # the server times out and closes the connection. (The only
- # applies to HTTP/1.1 connections.) This will happen if a self.fp.read()
- # is done (without a size) whether self.fp is buffered or not.
- # So, no self.fp.read() by clients unless they know what they are doing.
+ # the server times out and closes the connection. This will
+ # happen if a self.fp.read() is done (without a size) whether
+ # self.fp is buffered or not. So, no self.fp.read() by
+ # clients unless they know what they are doing.
self.fp = sock.makefile("rb")
self.debuglevel = debuglevel
self.strict = strict
self._method = method
- self.msg = None
+ # The HTTPResponse object is returned via urllib. The clients
+ # of http and urllib expect different attributes for the
+ # headers. headers is used here and supports urllib. msg is
+ # provided as a backwards compatibility layer for http
+ # clients.
+
+ self.headers = self.msg = None
# from the Status-Line of the response
self.version = _UNKNOWN # HTTP-Version
@@ -326,7 +338,7 @@ class HTTPResponse(io.RawIOBase):
return version, status, reason
def begin(self):
- if self.msg is not None:
+ if self.headers is not None:
# we've already started reading the response
return
@@ -343,7 +355,7 @@ class HTTPResponse(io.RawIOBase):
if self.debuglevel > 0:
print("header:", skip)
- self.status = status
+ self.code = self.status = status
self.reason = reason.strip()
if version == "HTTP/1.0":
self.version = 10
@@ -358,17 +370,17 @@ class HTTPResponse(io.RawIOBase):
self.length = None
self.chunked = False
self.will_close = True
- self.msg = email.message_from_string('')
+ self.headers = self.msg = email.message_from_string('')
return
- self.msg = parse_headers(self.fp)
+ self.headers = self.msg = parse_headers(self.fp)
if self.debuglevel > 0:
- for hdr in self.msg:
+ for hdr in self.headers:
print("header:", hdr, end=" ")
# are we using the chunked-style of transfer encoding?
- tr_enc = self.msg.get("transfer-encoding")
+ tr_enc = self.headers.get("transfer-encoding")
if tr_enc and tr_enc.lower() == "chunked":
self.chunked = True
self.chunk_left = None
@@ -381,10 +393,10 @@ class HTTPResponse(io.RawIOBase):
# do we have a Content-Length?
# NOTE: RFC 2616, S4.4, #3 says we ignore this if tr_enc is "chunked"
self.length = None
- length = self.msg.get("content-length")
+ length = self.headers.get("content-length")
# are we using the chunked-style of transfer encoding?
- tr_enc = self.msg.get("transfer-encoding")
+ tr_enc = self.headers.get("transfer-encoding")
if length and not self.chunked:
try:
self.length = int(length)
@@ -411,11 +423,11 @@ class HTTPResponse(io.RawIOBase):
self.will_close = True
def _check_close(self):
- conn = self.msg.get("connection")
+ conn = self.headers.get("connection")
if self.version == 11:
# An HTTP/1.1 proxy is assumed to stay open unless
# explicitly closed.
- conn = self.msg.get("connection")
+ conn = self.headers.get("connection")
if conn and "close" in conn.lower():
return True
return False
@@ -424,7 +436,7 @@ class HTTPResponse(io.RawIOBase):
# connections, using rules different than HTTP/1.1.
# For older HTTP, Keep-Alive indicates persistent connection.
- if self.msg.get("keep-alive"):
+ if self.headers.get("keep-alive"):
return False
# At least Akamai returns a "Connection: Keep-Alive" header,
@@ -433,7 +445,7 @@ class HTTPResponse(io.RawIOBase):
return False
# Proxy-Connection is a netscape hack.
- pconn = self.msg.get("proxy-connection")
+ pconn = self.headers.get("proxy-connection")
if pconn and "keep-alive" in pconn.lower():
return False
@@ -584,21 +596,31 @@ class HTTPResponse(io.RawIOBase):
return self.fp.fileno()
def getheader(self, name, default=None):
- if self.msg is None:
+ if self.headers is None:
raise ResponseNotReady()
- return ', '.join(self.msg.get_all(name, default))
+ return ', '.join(self.headers.get_all(name, default))
def getheaders(self):
"""Return list of (header, value) tuples."""
- if self.msg is None:
+ if self.headers is None:
raise ResponseNotReady()
- return list(self.msg.items())
+ return list(self.headers.items())
# We override IOBase.__iter__ so that it doesn't check for closed-ness
def __iter__(self):
return self
+ # For compatibility with old-style urllib responses.
+
+ def info(self):
+ return self.headers
+
+ def geturl(self):
+ return self.url
+
+ def getcode(self):
+ return self.status
class HTTPConnection:
@@ -757,7 +779,7 @@ class HTTPConnection:
if self.__state == _CS_IDLE:
self.__state = _CS_REQ_STARTED
else:
- raise CannotSendRequest()
+ raise CannotSendRequest(self.__state)
# Save the method we use, we need it later in the response phase
self._method = method
@@ -906,13 +928,23 @@ class HTTPConnection:
self.endheaders(body)
def getresponse(self):
- """Get the response from the server."""
+ """Get the response from the server.
+
+ If the HTTPConnection is in the correct state, returns an
+ instance of HTTPResponse or of whatever object is returned by
+ class the response_class variable.
+
+ If a request has not been sent or if a previous response has
+ not be handled, ResponseNotReady is raised. If the HTTP
+ response indicates that the connection should be closed, then
+ it will be closed before the response is returned. When the
+ connection is closed, the underlying socket is closed.
+ """
# if a prior response has been completed, then forget about it.
if self.__response and self.__response.isclosed():
self.__response = None
- #
# if a prior response exists, then it must be completed (otherwise, we
# cannot read this response's header to determine the connection-close
# behavior)
@@ -929,7 +961,7 @@ class HTTPConnection:
# isclosed() status to become true.
#
if self.__state != _CS_REQ_SENT or self.__response:
- raise ResponseNotReady()
+ raise ResponseNotReady(self.__state)
if self.debuglevel > 0:
response = self.response_class(self.sock, self.debuglevel,