Example #1
0
class ChunkedTransferStreamReader(object):
    '''Read chunked transfer encoded stream.

    Args:
        io_stream: An instance of :class:`.extended.IOStream`.

    Attributes:
        data_event (Event): An instance of :class:`.actor.Event` that will
            be fired when raw data is read from the stream.
        content_event (Event): An instance of :class:`.actor.Event` that will
            be fired when content data is decoded from the stream.
    '''
    def __init__(self, io_stream):
        self._io_stream = io_stream
        self.data_event = Event()
        self.content_event = Event()

    @tornado.gen.coroutine
    def read_chunk(self):
        '''Read a single chunk of the chunked transfer encoding.

        Returns:
            int: The size of the content in the chunk.
        '''
        _logger.debug('Reading chunk.')
        chunk_size_hex = yield self._io_stream.read_until(b'\n')

        self.data_event.fire(chunk_size_hex)

        try:
            chunk_size = int(chunk_size_hex.split(b';', 1)[0].strip(), 16)
        except ValueError as error:
            raise ProtocolError(error.args[0]) from error

        _logger.debug(__('Getting chunk size={0}.', chunk_size))

        if not chunk_size:
            raise tornado.gen.Return(chunk_size)

        def callback(data):
            self.data_event.fire(data)
            self.content_event.fire(data)

        yield self._io_stream.read_bytes(
            chunk_size, streaming_callback=callback
        )

        newline_data = yield self._io_stream.read_until(b'\n')

        self.data_event.fire(newline_data)

        if len(newline_data) > 2:
            # Should be either CRLF or LF
            # This could our problem or the server's problem
            raise ProtocolError('Error reading newline after chunk.')

        raise tornado.gen.Return(chunk_size)

    @tornado.gen.coroutine
    def read_trailer(self):
        '''Read the HTTP trailer fields.

        Returns:
            bytes: The trailer data.
        '''
        _logger.debug('Reading chunked trailer.')

        trailer_data_list = []

        while True:
            trailer_data = yield self._io_stream.read_until(b'\n')

            self.data_event.fire(trailer_data)
            trailer_data_list.append(trailer_data)

            if not trailer_data.strip():
                break

        raise tornado.gen.Return(b''.join(trailer_data_list))
Example #2
0
class ChunkedTransferStreamReader(object):
    '''Read chunked transfer encoded stream.

    Args:
        io_stream: An instance of :class:`.extended.IOStream`.

    Attributes:
        data_event (Event): An instance of :class:`.actor.Event` that will
            be fired when raw data is read from the stream.
        content_event (Event): An instance of :class:`.actor.Event` that will
            be fired when content data is decoded from the stream.
    '''
    def __init__(self, io_stream):
        self._io_stream = io_stream
        self.data_event = Event()
        self.content_event = Event()

    @tornado.gen.coroutine
    def read_chunk(self):
        '''Read a single chunk of the chunked transfer encoding.

        Returns:
            int: The size of the content in the chunk.
        '''
        _logger.debug('Reading chunk.')
        chunk_size_hex = yield self._io_stream.read_until(b'\n')

        self.data_event.fire(chunk_size_hex)

        try:
            chunk_size = int(chunk_size_hex.split(b';', 1)[0].strip(), 16)
        except ValueError as error:
            raise ProtocolError(error.args[0]) from error

        _logger.debug('Getting chunk size={0}.'.format(chunk_size))

        if not chunk_size:
            raise tornado.gen.Return(chunk_size)

        def callback(data):
            self.data_event.fire(data)
            self.content_event.fire(data)

        yield self._io_stream.read_bytes(chunk_size,
                                         streaming_callback=callback)

        newline_data = yield self._io_stream.read_until(b'\n')

        self.data_event.fire(newline_data)

        if len(newline_data) > 2:
            # Should be either CRLF or LF
            # This could our problem or the server's problem
            raise ProtocolError('Error reading newline after chunk.')

        raise tornado.gen.Return(chunk_size)

    @tornado.gen.coroutine
    def read_trailer(self):
        '''Read the HTTP trailer fields.

        Returns:
            bytes: The trailer data.
        '''
        _logger.debug('Reading chunked trailer.')

        trailer_data_list = []

        while True:
            trailer_data = yield self._io_stream.read_until(b'\n')

            self.data_event.fire(trailer_data)
            trailer_data_list.append(trailer_data)

            if not trailer_data.strip():
                break

        raise tornado.gen.Return(b''.join(trailer_data_list))