Ejemplo n.º 1
0
    def test_parse_chunked_data(self):
        # See: https://en.wikipedia.org/wiki/Chunked_transfer_encoding
        chunked = '4\r\nWiki\r\n5\r\npedia\r\nE\r\n in\r\n\r\nchunks.\r\n0\r\n\r\n'
        expected = 'Wikipedia in\r\n\r\nchunks.'

        # test parsing
        parsed = parse_chunked_data(chunked)
        self.assertEqual(expected.strip(), parsed.strip())

        # test roundtrip
        chunked_computed = create_chunked_data(expected)
        parsed = parse_chunked_data(chunked_computed)
        self.assertEqual(expected.strip(), parsed.strip())
Ejemplo n.º 2
0
    def forward(self, method):
        data = self.data_bytes
        path = self.path
        forward_headers = CaseInsensitiveDict(self.headers)

        # force close connection
        connection_header = forward_headers.get('Connection') or ''
        if connection_header.lower() not in ['keep-alive', '']:
            self.close_connection = 1

        client_address = self.client_address[0]
        server_address = ':'.join(map(str, self.server.server_address))

        try:
            # run the actual response forwarding
            response = modify_and_forward(
                method=method,
                path=path,
                data_bytes=data,
                headers=forward_headers,
                forward_base_url=self.proxy.forward_base_url,
                listeners=self._listeners(),
                request_handler=self,
                client_address=client_address,
                server_address=server_address)

            # copy headers and return response
            self.send_response(response.status_code)

            # set content for chunked encoding
            is_chunked = uses_chunked_encoding(response)
            if is_chunked:
                response._content = create_chunked_data(response._content)

            # send headers
            content_length_sent = False
            for header_key, header_value in iteritems(response.headers):
                # filter out certain headers that we don't want to transmit
                if header_key.lower() not in ('transfer-encoding', 'date',
                                              'server'):
                    self.send_header(header_key, header_value)
                    content_length_sent = content_length_sent or header_key.lower(
                    ) == 'content-length'

            # fix content-type header if needed
            if not content_length_sent and not is_chunked:
                self.send_header(
                    'Content-Length',
                    '%s' % len(response.content) if response.content else 0)

            if isinstance(response, LambdaResponse):
                self.send_multi_value_headers(response.multi_value_headers)

            self.end_headers()
            if response.content and len(response.content):
                self.wfile.write(to_bytes(response.content))
        except Exception as e:
            trace = str(traceback.format_exc())
            conn_errors = ('ConnectionRefusedError', 'NewConnectionError',
                           'Connection aborted', 'Unexpected EOF',
                           'Connection reset by peer',
                           'cannot read from timed out object')
            conn_error = any(e in trace for e in conn_errors)
            error_msg = 'Error forwarding request: %s %s' % (e, trace)
            if 'Broken pipe' in trace:
                LOG.warn(
                    'Connection prematurely closed by client (broken pipe).')
            elif not self.proxy.quiet or not conn_error:
                LOG.error(error_msg)
                if is_local_test_mode():
                    # During a test run, we also want to print error messages, because
                    # log messages are delayed until the entire test run is over, and
                    # hence we are missing messages if the test hangs for some reason.
                    print('ERROR: %s' % error_msg)
            self.send_response(502)  # bad gateway
            self.end_headers()
            # force close connection
            self.close_connection = 1
        finally:
            try:
                self.wfile.flush()
            except Exception as e:
                LOG.warning('Unable to flush write file: %s' % e)