Skip to content

Commit

Permalink
Do not send Content-length: 0 in GET/HEAD/TRACE requests (aio-libs#…
Browse files Browse the repository at this point in the history
  • Loading branch information
socketpair authored and asvetlov committed Oct 16, 2017
1 parent 411af98 commit dad3652
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 28 deletions.
14 changes: 9 additions & 5 deletions aiohttp/client_reqrep.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,14 @@


class ClientRequest:

GET_METHODS = {hdrs.METH_GET, hdrs.METH_HEAD, hdrs.METH_OPTIONS}
GET_METHODS = {
hdrs.METH_GET,
hdrs.METH_HEAD,
hdrs.METH_OPTIONS,
hdrs.METH_TRACE,
}
POST_METHODS = {hdrs.METH_PATCH, hdrs.METH_POST, hdrs.METH_PUT}
ALL_METHODS = GET_METHODS.union(POST_METHODS).union(
{hdrs.METH_DELETE, hdrs.METH_TRACE})
ALL_METHODS = GET_METHODS.union(POST_METHODS).union({hdrs.METH_DELETE})

DEFAULT_HEADERS = {
hdrs.ACCEPT: '*/*',
Expand Down Expand Up @@ -129,7 +132,8 @@ def __init__(self, method, url, *,
self.update_fingerprint(fingerprint)

self.update_body_from_data(data)
self.update_transfer_encoding()
if data or self.method not in self.GET_METHODS:
self.update_transfer_encoding()
self.update_expect_continue(expect100)

@property
Expand Down
1 change: 1 addition & 0 deletions changes/2167.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Do not add `Content-Length: 0` to GET/HEAD/TRACE/OPTIONS requests by default.
2 changes: 1 addition & 1 deletion tests/test_client_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -2201,7 +2201,7 @@ def handler_redirect(request):
client = yield from test_client(app)

with pytest.warns(DeprecationWarning):
yield from client.get('/', chunked=1024)
yield from client.post('/', chunked=1024)


@asyncio.coroutine
Expand Down
31 changes: 16 additions & 15 deletions tests/test_client_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ def test_skip_default_useragent_header(make_request):


def test_headers(make_request):
req = make_request('get', 'http://python.org/',
req = make_request('post', 'http://python.org/',
headers={'Content-Type': 'text/plain'})

assert 'CONTENT-TYPE' in req.headers
Expand All @@ -273,7 +273,7 @@ def test_headers(make_request):


def test_headers_list(make_request):
req = make_request('get', 'http://python.org/',
req = make_request('post', 'http://python.org/',
headers=[('Content-Type', 'text/plain')])
assert 'CONTENT-TYPE' in req.headers
assert req.headers['CONTENT-TYPE'] == 'text/plain'
Expand Down Expand Up @@ -529,16 +529,16 @@ def test_connection_header(loop, conn):
def test_no_content_length(loop, conn):
req = ClientRequest('get', URL('http://python.org'), loop=loop)
resp = req.send(conn)
assert '0' == req.headers.get('CONTENT-LENGTH')
assert req.headers.get('CONTENT-LENGTH') is None
yield from req.close()
resp.close()


@asyncio.coroutine
def test_no_content_length2(loop, conn):
def test_no_content_length_head(loop, conn):
req = ClientRequest('head', URL('http://python.org'), loop=loop)
resp = req.send(conn)
assert '0' == req.headers.get('CONTENT-LENGTH')
assert req.headers.get('CONTENT-LENGTH') is None
yield from req.close()
resp.close()

Expand Down Expand Up @@ -586,7 +586,7 @@ def test_content_type_skip_auto_header_form(loop, conn):


def test_content_type_auto_header_content_length_no_skip(loop, conn):
req = ClientRequest('get', URL('http://python.org'),
req = ClientRequest('post', URL('http://python.org'),
data=io.BytesIO(b'hey'),
skip_auto_headers={'Content-Length'},
loop=loop)
Expand Down Expand Up @@ -645,6 +645,7 @@ def test_pass_falsy_data_file(loop, tmpdir):
yield from req.close()


# Elasticsearch API requires to send request body with GET-requests
@asyncio.coroutine
def test_get_with_data(loop):
for meth in ClientRequest.GET_METHODS:
Expand Down Expand Up @@ -673,7 +674,7 @@ def test_bytes_data(loop, conn):

@asyncio.coroutine
def test_content_encoding(loop, conn):
req = ClientRequest('get', URL('http://python.org/'), data='foo',
req = ClientRequest('post', URL('http://python.org/'), data='foo',
compress='deflate', loop=loop)
with mock.patch('aiohttp.client_reqrep.PayloadWriter') as m_writer:
resp = req.send(conn)
Expand All @@ -687,7 +688,7 @@ def test_content_encoding(loop, conn):

@asyncio.coroutine
def test_content_encoding_dont_set_headers_if_no_body(loop, conn):
req = ClientRequest('get', URL('http://python.org/'),
req = ClientRequest('post', URL('http://python.org/'),
compress='deflate', loop=loop)
with mock.patch('aiohttp.client_reqrep.http'):
resp = req.send(conn)
Expand All @@ -700,7 +701,7 @@ def test_content_encoding_dont_set_headers_if_no_body(loop, conn):
@asyncio.coroutine
def test_content_encoding_header(loop, conn):
req = ClientRequest(
'get', URL('http://python.org/'), data='foo',
'post', URL('http://python.org/'), data='foo',
headers={'Content-Encoding': 'deflate'}, loop=loop)
with mock.patch('aiohttp.client_reqrep.PayloadWriter') as m_writer:
resp = req.send(conn)
Expand All @@ -714,15 +715,15 @@ def test_content_encoding_header(loop, conn):
@asyncio.coroutine
def test_compress_and_content_encoding(loop, conn):
with pytest.raises(ValueError):
ClientRequest('get', URL('http://python.org/'), data='foo',
ClientRequest('post', URL('http://python.org/'), data='foo',
headers={'content-encoding': 'deflate'},
compress='deflate', loop=loop)


@asyncio.coroutine
def test_chunked(loop, conn):
req = ClientRequest(
'get', URL('http://python.org/'),
'post', URL('http://python.org/'),
headers={'TRANSFER-ENCODING': 'gzip'}, loop=loop)
resp = req.send(conn)
assert 'gzip' == req.headers['TRANSFER-ENCODING']
Expand All @@ -733,7 +734,7 @@ def test_chunked(loop, conn):
@asyncio.coroutine
def test_chunked2(loop, conn):
req = ClientRequest(
'get', URL('http://python.org/'),
'post', URL('http://python.org/'),
headers={'Transfer-encoding': 'chunked'}, loop=loop)
resp = req.send(conn)
assert 'chunked' == req.headers['TRANSFER-ENCODING']
Expand All @@ -744,7 +745,7 @@ def test_chunked2(loop, conn):
@asyncio.coroutine
def test_chunked_explicit(loop, conn):
req = ClientRequest(
'get', URL('http://python.org/'), chunked=True, loop=loop)
'post', URL('http://python.org/'), chunked=True, loop=loop)
with mock.patch('aiohttp.client_reqrep.PayloadWriter') as m_writer:
resp = req.send(conn)

Expand All @@ -758,15 +759,15 @@ def test_chunked_explicit(loop, conn):
def test_chunked_length(loop, conn):
with pytest.raises(ValueError):
ClientRequest(
'get', URL('http://python.org/'),
'post', URL('http://python.org/'),
headers={'CONTENT-LENGTH': '1000'}, chunked=True, loop=loop)


@asyncio.coroutine
def test_chunked_transfer_encoding(loop, conn):
with pytest.raises(ValueError):
ClientRequest(
'get', URL('http://python.org/'),
'post', URL('http://python.org/'),
headers={'TRANSFER-ENCODING': 'chunked'}, chunked=True, loop=loop)


Expand Down
14 changes: 7 additions & 7 deletions tests/test_web_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -700,10 +700,10 @@ def handler(request):
return web.Response()

app = web.Application()
app.router.add_get('/', handler)
app.router.add_post('/', handler)
client = yield from test_client(app)

resp = yield from client.get('/')
resp = yield from client.post('/')
assert 200 == resp.status


Expand Down Expand Up @@ -767,12 +767,12 @@ def handler(request):
return web.Response()

app = web.Application()
app.router.add_get('/', handler)
app.router.add_post('/', handler)
server = yield from test_server(app, max_field_size=81920)
client = yield from test_client(server)

headers = {'Long-Header': 'ab' * 8129}
resp = yield from client.get('/', headers=headers)
resp = yield from client.post('/', headers=headers)
assert 200 == resp.status


Expand Down Expand Up @@ -997,18 +997,18 @@ def test_bad_request_payload(loop, test_client):

@asyncio.coroutine
def handler(request):
assert request.method == 'GET'
assert request.method == 'POST'

with pytest.raises(aiohttp.web.RequestPayloadError):
yield from request.content.read()

return web.Response()

app = web.Application()
app.router.add_get('/', handler)
app.router.add_post('/', handler)
client = yield from test_client(app)

resp = yield from client.get(
resp = yield from client.post(
'/', data=b'test', headers={'content-encoding': 'gzip'})
assert 200 == resp.status

Expand Down

0 comments on commit dad3652

Please sign in to comment.