diff -r 325aec842e3e Lib/httplib.py --- a/Lib/httplib.py Wed Feb 25 10:12:26 2015 -0500 +++ b/Lib/httplib.py Fri Feb 27 22:08:31 2015 +0000 @@ -1005,19 +1005,30 @@ """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, te: - # If this is a file-like object, try to - # fstat its file descriptor + + method_expects_body = ( + method.upper() in ('OPTIONS', 'PATCH', 'POST', 'PUT') + ) + + 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, te: + # 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) @@ -1033,8 +1044,8 @@ 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.iteritems(): self.putheader(hdr, value) self.endheaders(body) diff -r 325aec842e3e Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py Wed Feb 25 10:12:26 2015 -0500 +++ b/Lib/test/test_httplib.py Fri Feb 27 22:08:31 2015 +0000 @@ -1,4 +1,5 @@ import httplib +import itertools import array import StringIO import socket @@ -122,21 +123,14 @@ self.content_length = kv[1].strip() list.append(self, item) - # POST with empty body - conn = httplib.HTTPConnection('example.com') - conn.sock = FakeSocket(None) - conn._buffer = ContentLengthChecker() - conn.request('POST', '/', '') - self.assertEqual(conn._buffer.content_length, '0', - 'Header Content-Length not set') - - # PUT request with empty body - conn = httplib.HTTPConnection('example.com') - conn.sock = FakeSocket(None) - conn._buffer = ContentLengthChecker() - conn.request('PUT', '/', '') - self.assertEqual(conn._buffer.content_length, '0', - 'Header Content-Length not set') + methods = ('PUT', 'POST', 'PATCH', 'OPTIONS') + for method, body in itertools.product(methods, [None, '']): + conn = httplib.HTTPConnection('example.com') + conn.sock = FakeSocket(None) + conn._buffer = ContentLengthChecker() + conn.request(method, '/', body) + self.assertEqual(conn._buffer.content_length, '0', + 'Header Content-Length not set') def test_putheader(self): conn = httplib.HTTPConnection('example.com')