From 63cd6c72de57245d39b2a914b9675dac69eba637 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Mon, 27 Mar 2017 10:50:21 -0700 Subject: [PATCH] do not add content-disposition header to stremimng request by default #1755 --- CHANGES.rst | 4 +++- aiohttp/client_reqrep.py | 2 +- aiohttp/formdata.py | 10 ++++++++-- aiohttp/payload.py | 10 +++++----- tests/test_client_functional.py | 31 ++++++++++++++++++++++++++++++- tests/test_client_request.py | 9 +++++++++ 6 files changed, 56 insertions(+), 10 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 43e58c5e7c9..d6d53737a53 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,11 +2,13 @@ Changes ======= -2.0.4 (2017-xx-xx) +2.0.4 (2017-03-27) ------------------ - Encoding is always UTF-8 in POST data #1750 +- Do not add "Content-Disposition" header by default #1755 + 2.0.3 (2017-03-24) ------------------ diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py index 277f9b934a7..1aafc877fc1 100644 --- a/aiohttp/client_reqrep.py +++ b/aiohttp/client_reqrep.py @@ -245,7 +245,7 @@ def update_body_from_data(self, body, skip_auto_headers): body = body() try: - body = payload.PAYLOAD_REGISTRY.get(body) + body = payload.PAYLOAD_REGISTRY.get(body, disposition=None) except payload.LookupError: body = FormData(body)() diff --git a/aiohttp/formdata.py b/aiohttp/formdata.py index f001ec3633b..b3a845cd873 100644 --- a/aiohttp/formdata.py +++ b/aiohttp/formdata.py @@ -95,10 +95,16 @@ def _gen_form_urlencoded(self): data.append((type_options['name'], value)) charset = self._charset if self._charset is not None else 'utf-8' + + if charset == 'utf-8': + content_type = 'application/x-www-form-urlencoded' + else: + content_type = ('application/x-www-form-urlencoded; ' + 'charset=%s' % charset) + return payload.BytesPayload( urlencode(data, doseq=True, encoding=charset).encode(), - content_type=('application/x-www-form-urlencoded; ' - 'charset=%s' % charset)) + content_type=content_type) def _gen_form_data(self): """Encode a list of fields using the multipart/form-data MIME format""" diff --git a/aiohttp/payload.py b/aiohttp/payload.py index 25e14056a8b..7ee7876d412 100644 --- a/aiohttp/payload.py +++ b/aiohttp/payload.py @@ -68,8 +68,8 @@ class Payload(ABC): _headers = None _content_type = 'application/octet-stream' - def __init__(self, value, *, headers=None, - content_type=sentinel, filename=None, encoding=None): + def __init__(self, value, *, headers=None, content_type=sentinel, + filename=None, encoding=None, **kwargs): self._value = value self._encoding = encoding self._filename = filename @@ -177,14 +177,14 @@ def __init__(self, value, *args, class IOBasePayload(Payload): - def __init__(self, value, disptype='inline', *args, **kwargs): + def __init__(self, value, disposition='attachment', *args, **kwargs): if 'filename' not in kwargs: kwargs['filename'] = guess_filename(value) super().__init__(value, *args, **kwargs) - if self._filename is not None: - self.set_content_disposition(disptype, filename=self._filename) + if self._filename is not None and disposition is not None: + self.set_content_disposition(disposition, filename=self._filename) @asyncio.coroutine def write(self, writer): diff --git a/tests/test_client_functional.py b/tests/test_client_functional.py index add48352063..d761faa24a7 100644 --- a/tests/test_client_functional.py +++ b/tests/test_client_functional.py @@ -1360,6 +1360,34 @@ def handler(request): @asyncio.coroutine def test_POST_FILES_SINGLE(loop, test_client, fname): + @asyncio.coroutine + def handler(request): + data = yield from request.text() + with fname.open('r') as f: + content = f.read() + assert content == data + # if system cannot determine 'application/pgp-keys' MIME type + # then use 'application/octet-stream' default + assert request.content_type in ['application/pgp-keys', + 'text/plain', + 'application/octet-stream'] + assert 'content-disposition' not in request.headers + + return web.HTTPOk() + + app = web.Application() + app.router.add_post('/', handler) + client = yield from test_client(app) + + with fname.open() as f: + resp = yield from client.post('/', data=f) + assert 200 == resp.status + resp.close() + + +@asyncio.coroutine +def test_POST_FILES_SINGLE_content_disposition(loop, test_client, fname): + @asyncio.coroutine def handler(request): data = yield from request.text() @@ -1381,7 +1409,8 @@ def handler(request): client = yield from test_client(app) with fname.open() as f: - resp = yield from client.post('/', data=f) + resp = yield from client.post( + '/', data=aiohttp.get_payload(f, disposition='inline')) assert 200 == resp.status resp.close() diff --git a/tests/test_client_request.py b/tests/test_client_request.py index 04a8d575343..37775cec0b3 100644 --- a/tests/test_client_request.py +++ b/tests/test_client_request.py @@ -588,6 +588,15 @@ def test_content_type_auto_header_content_length_no_skip(loop, conn): resp.close() +def test_urlencoded_formdata_charset(loop, conn): + req = ClientRequest( + 'post', URL('http://python.org'), + data=aiohttp.FormData({'hey': 'you'}, charset='koi8-r'), loop=loop) + req.send(conn) + assert 'application/x-www-form-urlencoded; charset=koi8-r' == \ + req.headers.get('CONTENT-TYPE') + + @asyncio.coroutine def test_post_data(loop, conn): for meth in ClientRequest.POST_METHODS: