Skip to content

reading nested multipart messages does not work correctly #1526

Closed
@terencehonles

Description

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))

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions