Skip to content

Commit

Permalink
Merge pull request #507 from elastic-coders/skip_content_type_auto_he…
Browse files Browse the repository at this point in the history
…ader

Skip auto-generation of Content-Type header.
  • Loading branch information
asvetlov committed Sep 14, 2015
2 parents 62e165e + 2ff2f19 commit dcf843e
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 6 deletions.
11 changes: 7 additions & 4 deletions aiohttp/client_reqrep.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def __init__(self, method, url, *,
'not supported at the same time.')
data = files

self.update_body_from_data(data)
self.update_body_from_data(data, skip_auto_headers)
self.update_transfer_encoding()
self.update_expect_continue(expect100)

Expand Down Expand Up @@ -260,7 +260,7 @@ def update_auth(self, auth):

self.headers[hdrs.AUTHORIZATION] = auth.encode()

def update_body_from_data(self, data):
def update_body_from_data(self, data, skip_auto_headers):
if not data:
return

Expand All @@ -269,7 +269,8 @@ def update_body_from_data(self, data):

if isinstance(data, (bytes, bytearray)):
self.body = data
if hdrs.CONTENT_TYPE not in self.headers:
if (hdrs.CONTENT_TYPE not in self.headers and
hdrs.CONTENT_TYPE not in skip_auto_headers):
self.headers[hdrs.CONTENT_TYPE] = 'application/octet-stream'
if hdrs.CONTENT_LENGTH not in self.headers and not self.chunked:
self.headers[hdrs.CONTENT_LENGTH] = str(len(self.body))
Expand Down Expand Up @@ -310,6 +311,7 @@ def update_body_from_data(self, data):
raise ValueError('file {!r} should be open in binary mode'
''.format(data))
if (hdrs.CONTENT_TYPE not in self.headers and
hdrs.CONTENT_TYPE not in skip_auto_headers and
hasattr(data, 'name')):
mime = mimetypes.guess_type(data.name)[0]
mime = 'application/octet-stream' if mime is None else mime
Expand All @@ -326,7 +328,8 @@ def update_body_from_data(self, data):

self.body = data(self.encoding)

if hdrs.CONTENT_TYPE not in self.headers:
if (hdrs.CONTENT_TYPE not in self.headers and
hdrs.CONTENT_TYPE not in skip_auto_headers):
self.headers[hdrs.CONTENT_TYPE] = data.content_type

if data.is_multipart:
Expand Down
3 changes: 2 additions & 1 deletion docs/client_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ The client session supports context manager protocol for self closing::
*aiohttp* autogenerates headers like ``User-Agent`` or
``Content-Type`` if these headers are not explicitly
passed. Using ``skip_auto_headers`` parameter allows to skip
that generation.
that generation. Note that ``Content-Length`` autogeneration can't
be skipped.

Iterable of :class:`str` or :class:`~aiohttp.multidict.upstr` (optional)

Expand Down
44 changes: 43 additions & 1 deletion tests/test_client_request.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# coding: utf-8

import asyncio
import gc
import unittest
Expand Down Expand Up @@ -251,6 +253,46 @@ def test_no_content_length(self):
self.loop.run_until_complete(req.close())
resp.close()

def test_content_type_auto_header_get(self):
req = ClientRequest('get', 'http://python.org', loop=self.loop)
req.send(self.transport, self.protocol)
self.assertNotIn('CONTENT-TYPE', req.headers)

def test_content_type_auto_header_form(self):
req = ClientRequest('post', 'http://python.org', data={'hey': 'you'},
loop=self.loop)
req.send(self.transport, self.protocol)
self.assertEqual('application/x-www-form-urlencoded',
req.headers.get('CONTENT-TYPE'))

def test_content_type_auto_header_bytes(self):
req = ClientRequest('post', 'http://python.org', data=b'hey you',
loop=self.loop)
req.send(self.transport, self.protocol)
self.assertEqual('application/octet-stream',
req.headers.get('CONTENT-TYPE'))

def test_content_type_skip_auto_header_bytes(self):
req = ClientRequest('post', 'http://python.org', data=b'hey you',
skip_auto_headers=set('CONTENT-TYPE'),
loop=self.loop)
req.send(self.transport, self.protocol)
self.assertNotIn('application/octet-stream', req.headers)

def test_content_type_skip_auto_header_form(self):
req = ClientRequest('post', 'http://python.org', data={'hey': 'you'},
loop=self.loop, skip_auto_headers={'CONTENT-TYPE'})
req.send(self.transport, self.protocol)
self.assertNotIn('CONTENT-TYPE', req.headers)

def test_content_type_auto_header_content_length_no_skip(self):
req = ClientRequest('get', 'http://python.org',
data=io.BytesIO(b'hey'),
skip_auto_headers={'CONTENT-LENGTH'},
loop=self.loop)
req.send(self.transport, self.protocol)
self.assertEqual(req.headers.get('CONTENT-LENGTH'), '3')

def test_path_is_not_double_encoded(self):
req = ClientRequest('get', "http://0.0.0.0/get/test case",
loop=self.loop)
Expand Down Expand Up @@ -367,7 +409,7 @@ def test_pass_falsy_data(self, _):
req = ClientRequest(
'post', 'http://python.org/',
data={}, loop=self.loop)
req.update_body_from_data.assert_called_once_with({})
req.update_body_from_data.assert_called_once_with({}, frozenset())
self.loop.run_until_complete(req.close())

def test_get_with_data(self):
Expand Down

0 comments on commit dcf843e

Please sign in to comment.