diff options
author | R David Murray <rdmurray@bitdance.com> | 2015-03-22 19:18:23 (GMT) |
---|---|---|
committer | R David Murray <rdmurray@bitdance.com> | 2015-03-22 19:18:23 (GMT) |
commit | beed8402ca2b44681f939238c8ea02deeb8a06a2 (patch) | |
tree | f5169d001eff31904177045e7046445497acffba /Lib/http | |
parent | 75ed90a4cf07cd9236b4ed52d1c7cf09810a1749 (diff) | |
download | cpython-beed8402ca2b44681f939238c8ea02deeb8a06a2.zip cpython-beed8402ca2b44681f939238c8ea02deeb8a06a2.tar.gz cpython-beed8402ca2b44681f939238c8ea02deeb8a06a2.tar.bz2 |
#23539: Set Content-Length to 0 for PUT, POST, and PATCH if body is None.
Some http servers will reject PUT, POST, and PATCH requests if they
do not have a Content-Length header.
Patch by James Rutherford, with additional cleaning up of the
'request' documentation by me.
Diffstat (limited to 'Lib/http')
-rw-r--r-- | Lib/http/client.py | 37 |
1 files changed, 24 insertions, 13 deletions
diff --git a/Lib/http/client.py b/Lib/http/client.py index 3f9e67b..b27aa5d 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -246,6 +246,10 @@ _MAXHEADERS = 100 _is_legal_header_name = re.compile(rb'[^:\s][^:\r\n]*').fullmatch _is_illegal_header_value = re.compile(rb'\n(?![ \t])|\r(?![ \t\n])').search +# We always set the Content-Length header for these methods because some +# servers will otherwise respond with a 411 +_METHODS_EXPECTING_BODY = {'PATCH', 'POST', 'PUT'} + class HTTPMessage(email.message.Message): # XXX The only usage of this method is in @@ -1126,19 +1130,26 @@ class HTTPConnection: """Send a complete request to the server.""" self._send_request(method, url, body, headers) - def _set_content_length(self, body): - # Set the content-length based on the body. + def _set_content_length(self, body, method): + # Set the content-length based on the body. If the body is "empty", we + # set Content-Length: 0 for methods that expect a body (RFC 7230, + # Section 3.3.2). If the body is set for other methods, we set the + # header provided we can figure out what the length is. thelen = None - try: - thelen = str(len(body)) - except TypeError as te: - # If this is a file-like object, try to - # fstat its file descriptor + method_expects_body = method.upper() in _METHODS_EXPECTING_BODY + if body is None and method_expects_body: + thelen = '0' + elif body is not None: try: - thelen = str(os.fstat(body.fileno()).st_size) - except (AttributeError, OSError): - # Don't send a length if this failed - if self.debuglevel > 0: print("Cannot stat!!") + thelen = str(len(body)) + except TypeError: + # If this is a file-like object, try to + # fstat its file descriptor + try: + thelen = str(os.fstat(body.fileno()).st_size) + except (AttributeError, OSError): + # Don't send a length if this failed + if self.debuglevel > 0: print("Cannot stat!!") if thelen is not None: self.putheader('Content-Length', thelen) @@ -1154,8 +1165,8 @@ class HTTPConnection: self.putrequest(method, url, **skips) - if body is not None and ('content-length' not in header_names): - self._set_content_length(body) + if 'content-length' not in header_names: + self._set_content_length(body, method) for hdr, value in headers.items(): self.putheader(hdr, value) if isinstance(body, str): |