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

reading nested multipart messages does not work correctly #1526

Closed
terencehonles opened this issue Jan 4, 2017 · 6 comments
Closed

reading nested multipart messages does not work correctly #1526

terencehonles opened this issue Jan 4, 2017 · 6 comments
Labels

Comments

@terencehonles
Copy link
Contributor

Long story short

Multipart reader breaks after reading a sub multipart end boundary and starting the next part

Expected behaviour

Nested multipart reader reads a message created with the multipart writer correctly

Actual behaviour

ValueError: Invalid boundary b'', expected b'--b0b69248b3a345cf8256a8dd25f07874'

Steps to reproduce

Receive the multipart response from #1525

Server:

from aiohttp.multipart import MultipartWriter
from aiohttp.web import Response

def handle(request):
  with MultipartWriter('mixed') as root:
    with MultipartWriter('mixed') as subwriter1:
      subwriter1.append('first message')
    root.append(subwriter1, headers=subwriter1.headers)

    with MultipartWriter('mixed') as subwriter2:
      subwriter2.append('second message')
    root.append(subwriter2, headers=subwriter2.headers)
  return Response(body=b''.join(root.serialize()), headers=root.headers)

# ... create web app which responds with the handler above ...

Client:

import aiohttp
import asyncio
from aiohttp.multipart import BodyPartReader, MultipartReader

@asyncio.coroutine
def read_multipart(reader):
  while True:
    part = yield from reader.next()
    if part is None: break
    if isinstance(part, BodyPartReader):
      body = yield from part.read(decode=True)
      print('body part: %r' % body)
    else:
      print('nested part')
      yield from read_multipart(part)

@asyncio.coroutine
def request(url):
  response = yield from aiohttp.get(url)
  yield from read_multipart(MultipartReader.from_response(response))

# ... drive event loop and call request(handler_url) ...

Issue

Lines multipart.py:767 and multipart.py:969 have line endings which result in an empty line after the end boundary of a multipart message (valid). However the reader terminates after the end boundary and the parent reader now expects the next boundary, but what is found is the blank line from multipart.py:767

Possible fix

diff --git a/aiohttp/multipart.py b/aiohttp/multipart.py
index af7f19b1..82ad2306 100644
--- a/aiohttp/multipart.py
+++ b/aiohttp/multipart.py
@@ -639,6 +639,7 @@ class MultipartReader(object):
             pass
         elif chunk == self._boundary + b'--':
             self._at_eof = True
+            yield from self._readline()
         else:
             raise ValueError('Invalid boundary %r, expected %r'
                              % (chunk, self._boundary))
@fafhrd91
Copy link
Member

fafhrd91 commented Jan 4, 2017

@kxepal could you check this

@kxepal
Copy link
Member

kxepal commented Jan 4, 2017

Hm...it seems like some of our tests lies us since we have covered nested parts case there. Will check it in a moment.

terencehonles added a commit to terencehonles/aiohttp that referenced this issue Jan 7, 2017
Currently a multipart message epilogue is left unread which when nested
in another multipart message causes a ValueError to be raised because
the parent reader expects to find its multipart boundary not the
sub-message's epilogue.

fixes issue aio-libs#1526
terencehonles added a commit to terencehonles/aiohttp that referenced this issue Jan 7, 2017
Currently a multipart message epilogue is left unread which when nested
in another multipart message causes a ValueError to be raised because
the parent reader expects to find its multipart boundary not the
sub-message's epilogue.

fixes issue aio-libs#1526
@terencehonles
Copy link
Contributor Author

@kxepal the tests are hand coded strings and do not include a multipart epilogue. From what I have been seeing around when researching if the epilogue is required it does appear it is, but if you know otherwise please correct me.

@kxepal
Copy link
Member

kxepal commented Jan 7, 2017

@terencehonles Ah, epilogue. The epilogue must not be used. So it wasn't counted upon. Thought not sure if it's better crash or silently swallow it.

@terencehonles
Copy link
Contributor Author

@kxepal let's keep conversation on the PR #1532 for now

@lock
Copy link

lock bot commented Oct 29, 2019

This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue for
related bugs.

If you feel like there's important points made in this discussion,
please include those exceprts into that new issue.

@lock lock bot added the outdated label Oct 29, 2019
@lock lock bot locked as resolved and limited conversation to collaborators Oct 29, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

3 participants