Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Form data processed #4351

Merged
merged 9 commits into from
Nov 18, 2019
Merged
1 change: 1 addition & 0 deletions CHANGES/4345.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Raise ClientPayloadError if FormData re-processed.
4 changes: 4 additions & 0 deletions aiohttp/formdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def __init__(self, fields:
self._writer = multipart.MultipartWriter('form-data')
self._fields = [] # type: List[Any]
self._is_multipart = False
self._is_processed = False
self._quote_fields = quote_fields
self._charset = charset

Expand Down Expand Up @@ -115,6 +116,8 @@ def _gen_form_urlencoded(self) -> payload.BytesPayload:

def _gen_form_data(self) -> multipart.MultipartWriter:
"""Encode a list of fields using the multipart/form-data MIME format"""
if self._is_processed:
raise RuntimeError('Form data has been processed already')
for dispparams, headers, value in self._fields:
try:
if hdrs.CONTENT_TYPE in headers:
Expand All @@ -141,6 +144,7 @@ def _gen_form_data(self) -> multipart.MultipartWriter:

self._writer.append_payload(part)

self._is_processed = True
return self._writer

def __call__(self) -> Payload:
Expand Down
15 changes: 14 additions & 1 deletion tests/test_formdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import pytest

from aiohttp.formdata import FormData
from aiohttp import ClientSession, FormData


@pytest.fixture
Expand Down Expand Up @@ -86,3 +86,16 @@ async def test_formdata_field_name_is_not_quoted(buf, writer) -> None:
payload = form()
await payload.write(writer)
assert b'name="emails[]"' in buf


async def test_mark_formdata_as_processed() -> None:
async with ClientSession() as session:
url = "http://httpbin.org/anything"
data = FormData()
data.add_field("test", "test_value", content_type="application/json")

await session.post(url, data=data)
assert len(data._writer._parts) == 1

with pytest.raises(RuntimeError):
await session.post(url, data=data)
21 changes: 10 additions & 11 deletions tests/test_web_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ def fname(here):
return here / 'conftest.py'


def new_dummy_form():
form = FormData()
form.add_field('name', b'123',
content_transfer_encoding='base64')
return form


async def test_simple_get(aiohttp_client) -> None:

async def handler(request):
Expand Down Expand Up @@ -513,15 +520,11 @@ async def expect_handler(request):
if request.version == HttpVersion11:
await request.writer.write(b"HTTP/1.1 100 Continue\r\n\r\n")

form = FormData()
form.add_field('name', b'123',
content_transfer_encoding='base64')

app = web.Application()
app.router.add_post('/', handler, expect_handler=expect_handler)
client = await aiohttp_client(app)

resp = await client.post('/', data=form, expect100=True)
resp = await client.post('/', data=new_dummy_form(), expect100=True)
assert 200 == resp.status
assert expect_received

Expand All @@ -540,20 +543,16 @@ async def expect_handler(request):

await request.writer.write(b"HTTP/1.1 100 Continue\r\n\r\n")

form = FormData()
form.add_field('name', b'123',
content_transfer_encoding='base64')

app = web.Application()
app.router.add_post('/', handler, expect_handler=expect_handler)
client = await aiohttp_client(app)

auth_err = False
resp = await client.post('/', data=form, expect100=True)
resp = await client.post('/', data=new_dummy_form(), expect100=True)
assert 200 == resp.status

auth_err = True
resp = await client.post('/', data=form, expect100=True)
resp = await client.post('/', data=new_dummy_form(), expect100=True)
assert 403 == resp.status


Expand Down