def test_encoding_multipart_quopri(self):
        import quopri
        from email.mime import multipart
        from email.mime import nonmultipart
        from repoze.sendmail._compat import b

        latin_1_encoded = b('LaPe\xf1a')
        latin_1 = latin_1_encoded.decode('latin_1')
        plain_string = 'I know what you did last ' + latin_1

        message = multipart.MIMEMultipart('alternative')

        plain_part = nonmultipart.MIMENonMultipart('plain', 'plain')
        plain_part.set_payload(plain_string)
        message.attach(plain_part)

        html_string = '<p>' + plain_string + '</p>'
        html_part = nonmultipart.MIMENonMultipart('text', 'html')
        html_part.set_payload(html_string)
        message.attach(html_part)

        encoded = self._callFUT(message)

        self.assertEqual(
            encoded.count(quopri.encodestring(plain_string.encode('latin_1'))),
            2)
Esempio n. 2
0
    def __ConfigureMultipartRequest(self, http_request):
        """Configure http_request as a multipart request for this upload."""
        # This is a multipart/related upload.
        msg_root = mime_multipart.MIMEMultipart('related')
        # msg_root should not write out its own headers
        setattr(msg_root, '_write_headers', lambda self: None)

        # attach the body as one part
        msg = mime_nonmultipart.MIMENonMultipart(
            *http_request.headers['content-type'].split('/'))
        msg.set_payload(http_request.body)
        msg_root.attach(msg)

        # attach the media as the second part
        msg = mime_nonmultipart.MIMENonMultipart(*self.mime_type.split('/'))
        msg['Content-Transfer-Encoding'] = 'binary'
        msg.set_payload(self.stream.read())
        msg_root.attach(msg)

        # encode the body: note that we can't use `as_string`, because
        # it plays games with `From ` lines.
        fp = StringIO.StringIO()
        g = email_generator.Generator(fp, mangle_from_=False)
        g.flatten(msg_root, unixfrom=False)
        http_request.body = fp.getvalue()

        multipart_boundary = msg_root.get_boundary()
        http_request.headers['content-type'] = (
            'multipart/related; boundary=%r' % multipart_boundary)
    def test_encoding_multipart(self):
        from email.mime import application
        from email.mime import multipart
        from email.mime import nonmultipart
        from repoze.sendmail._compat import b
        from repoze.sendmail._compat import encodestring
        from repoze.sendmail._compat import from_octets

        message = multipart.MIMEMultipart('alternative')

        utf_8_encoded = b('mo \xe2\x82\xac')
        utf_8 = utf_8_encoded.decode('utf-8')

        plain_string = utf_8
        plain_part = nonmultipart.MIMENonMultipart('plain', 'plain')
        plain_part.set_payload(plain_string)
        message.attach(plain_part)

        html_string = '<p>' + utf_8 + '</p>'
        html_part = nonmultipart.MIMENonMultipart('text', 'html')
        html_part.set_payload(html_string)
        message.attach(html_part)

        binary = from_octets([x for x in range(256)])
        binary_b64 = encodestring(binary)
        binary_part = application.MIMEApplication(binary)
        message.attach(binary_part)

        encoded = self._callFUT(message)

        self.assertTrue(encodestring(plain_string.encode('utf-8')) in encoded)
        self.assertTrue(encodestring(html_string.encode('utf-8')) in encoded)
        self.assertTrue(binary_b64 in encoded)
Esempio n. 4
0
    def _Execute(self, http):
        """Serialize batch request, send to server, process response.

        Args:
          http: A httplib2.Http object to be used to make the request with.

        Raises:
          httplib2.HttpLib2Error if a transport error has occured.
          apiclient.errors.BatchError if the response is the wrong format.
        """
        message = mime_multipart.MIMEMultipart('mixed')
        # Message should not write out its own headers.
        setattr(message, '_write_headers', lambda self: None)

        # Add all the individual requests.
        for key in self.__request_response_handlers:
            msg = mime_nonmultipart.MIMENonMultipart('application', 'http')
            msg['Content-Transfer-Encoding'] = 'binary'
            msg['Content-ID'] = self._ConvertIdToHeader(key)

            body = self._SerializeRequest(
                self.__request_response_handlers[key].request)
            msg.set_payload(body)
            message.attach(msg)

        request = http_wrapper.Request(self.__batch_url, 'POST')
        request.body = message.as_string()
        request.headers['content-type'] = (
            'multipart/mixed; boundary="%s"') % message.get_boundary()

        response = http_wrapper.MakeRequest(http, request)

        if response.status_code >= 300:
            raise exceptions.HttpError.FromResponse(response)

        # Prepend with a content-type header so Parser can handle it.
        header = 'content-type: %s\r\n\r\n' % response.info['content-type']

        content = response.content
        if isinstance(content, bytes) and self.__response_encoding:
            content = response.content.decode(self.__response_encoding)

        parser = email_parser.Parser()
        mime_response = parser.parsestr(header + content)

        if not mime_response.is_multipart():
            raise exceptions.BatchError(
                'Response not in multipart/mixed format.')

        for part in mime_response.get_payload():
            request_id = self._ConvertHeaderToId(part['Content-ID'])
            response = self._DeserializeResponse(part.get_payload())

            # Disable protected access because namedtuple._replace(...)
            # is not actually meant to be protected.
            # pylint: disable=protected-access
            self.__request_response_handlers[request_id] = (
                self.__request_response_handlers[request_id]._replace(
                    response=response))
Esempio n. 5
0
    def __ConfigureMultipartRequest(self, http_request):
        """Configure http_request as a multipart request for this upload."""
        # This is a multipart/related upload.
        msg_root = mime_multipart.MIMEMultipart('related')
        # msg_root should not write out its own headers
        setattr(msg_root, '_write_headers', lambda self: None)

        # attach the body as one part
        msg = mime_nonmultipart.MIMENonMultipart(
            *http_request.headers['content-type'].split('/'))
        msg.set_payload(http_request.body)
        msg_root.attach(msg)

        # attach the media as the second part
        msg = mime_nonmultipart.MIMENonMultipart(*self.mime_type.split('/'))
        msg['Content-Transfer-Encoding'] = 'binary'
        msg.set_payload(self.stream.read())
        msg_root.attach(msg)

        # NOTE: We encode the body, but can't use
        #       `email.message.Message.as_string` because it prepends
        #       `> ` to `From ` lines.
        fp = six.BytesIO()
        if six.PY3:
            generator_class = email_generator.BytesGenerator
        else:
            generator_class = email_generator.Generator
        g = generator_class(fp, mangle_from_=False)
        g.flatten(msg_root, unixfrom=False)
        http_request.body = fp.getvalue()

        multipart_boundary = msg_root.get_boundary()
        http_request.headers['content-type'] = (
            'multipart/related; boundary=%r' % multipart_boundary)
        if isinstance(multipart_boundary, six.text_type):
            multipart_boundary = multipart_boundary.encode('ascii')

        body_components = http_request.body.split(multipart_boundary)
        headers, _, _ = body_components[-2].partition(b'\n\n')
        body_components[-2] = b'\n\n'.join([headers, b'<media body>\n\n--'])
        http_request.loggable_body = multipart_boundary.join(body_components)
Esempio n. 6
0
    def _configure_multipart_request(self, http_request):
        """Helper for 'configure_request': set up multipart request."""
        # This is a multipart/related upload.
        msg_root = mime_multipart.MIMEMultipart('related')
        # msg_root should not write out its own headers
        setattr(msg_root, '_write_headers', lambda self: None)

        # attach the body as one part
        msg = mime_nonmultipart.MIMENonMultipart(
            *http_request.headers['content-type'].split('/'))
        msg.set_payload(http_request.body)
        msg_root.attach(msg)

        # attach the media as the second part
        msg = mime_nonmultipart.MIMENonMultipart(*self.mime_type.split('/'))
        msg['Content-Transfer-Encoding'] = 'binary'
        msg.set_payload(self.stream.read())
        msg_root.attach(msg)

        # NOTE: generate multipart message as bytes, not text
        stream = six.BytesIO()
        if six.PY3:  # pragma: NO COVER  Python3
            generator_class = email_generator.BytesGenerator
        else:
            generator_class = email_generator.Generator
        generator = generator_class(stream, mangle_from_=False)
        generator.flatten(msg_root, unixfrom=False)
        http_request.body = stream.getvalue()

        multipart_boundary = msg_root.get_boundary()
        http_request.headers['content-type'] = (
            'multipart/related; boundary="%s"' % multipart_boundary)

        boundary_bytes = _to_bytes(multipart_boundary)
        body_components = http_request.body.split(boundary_bytes)
        headers, _, _ = body_components[-2].partition(b'\n\n')
        body_components[-2] = b'\n\n'.join([headers, b'<media body>\n\n--'])
        http_request.loggable_body = boundary_bytes.join(body_components)
Esempio n. 7
0
    def __ConfigureMultipartRequest(self, http_request):
        """Configure http_request as a multipart request for this upload."""
        # This is a multipart/related upload.
        msg_root = mime_multipart.MIMEMultipart('related')
        # msg_root should not write out its own headers
        setattr(msg_root, '_write_headers', lambda self: None)

        # attach the body as one part
        msg = mime_nonmultipart.MIMENonMultipart(
            *http_request.headers['content-type'].split('/'))
        msg.set_payload(http_request.body)
        msg_root.attach(msg)

        # attach the media as the second part
        msg = mime_nonmultipart.MIMENonMultipart(*self.mime_type.split('/'))
        msg['Content-Transfer-Encoding'] = 'binary'
        msg.set_payload(self.stream.read())
        msg_root.attach(msg)

        http_request.body = msg_root.as_string()
        multipart_boundary = msg_root.get_boundary()
        http_request.headers['content-type'] = (
            'multipart/related; boundary=%r' % multipart_boundary)
Esempio n. 8
0
    def _configure_multipart_request(self, http_request):
        """Helper for 'configure_request': set up multipart request."""
        # This is a multipart/related upload.
        msg_root = mime_multipart.MIMEMultipart('related')
        # msg_root should not write out its own headers
        setattr(msg_root, '_write_headers', lambda self: None)

        # attach the body as one part
        msg = mime_nonmultipart.MIMENonMultipart(
            *http_request.headers['content-type'].split('/'))
        msg.set_payload(http_request.body)
        msg_root.attach(msg)

        # attach the media as the second part
        msg = mime_nonmultipart.MIMENonMultipart(*self.mime_type.split('/'))
        msg['Content-Transfer-Encoding'] = 'binary'
        msg.set_payload(self.stream.read())
        msg_root.attach(msg)

        # NOTE: We encode the body, but can't use
        #       `email.message.Message.as_string` because it prepends
        #       `> ` to `From ` lines.
        # NOTE: We must use six.StringIO() instead of io.StringIO() since the
        #       `email` library uses cStringIO in Py2 and io.StringIO in Py3.
        stream = six.StringIO()
        generator = email_generator.Generator(stream, mangle_from_=False)
        generator.flatten(msg_root, unixfrom=False)
        http_request.body = stream.getvalue()

        multipart_boundary = msg_root.get_boundary()
        http_request.headers['content-type'] = (
            'multipart/related; boundary="%s"' % multipart_boundary)

        body_components = http_request.body.split(multipart_boundary)
        headers, _, _ = body_components[-2].partition('\n\n')
        body_components[-2] = '\n\n'.join([headers, '<media body>\n\n--'])
        http_request.loggable_body = multipart_boundary.join(body_components)
Esempio n. 9
0
    def _SerializeRequest(self, request):
        """Convert a http_wrapper.Request object into a string.

        Args:
          request: A http_wrapper.Request to serialize.

        Returns:
          The request as a string in application/http format.
        """
        # Construct status line
        parsed = urllib_parse.urlsplit(request.url)
        request_line = urllib_parse.urlunsplit(
            (None, None, parsed.path, parsed.query, None))
        status_line = u' '.join((
            request.http_method,
            request_line.decode('utf-8'),
            u'HTTP/1.1\n'
        ))
        major, minor = request.headers.get(
            'content-type', 'application/json').split('/')
        msg = mime_nonmultipart.MIMENonMultipart(major, minor)

        # MIMENonMultipart adds its own Content-Type header.
        # Keep all of the other headers in `request.headers`.
        for key, value in request.headers.items():
            if key == 'content-type':
                continue
            msg[key] = value

        msg['Host'] = parsed.netloc
        msg.set_unixfrom(None)

        if request.body is not None:
            msg.set_payload(request.body)

        # Serialize the mime message.
        str_io = six.StringIO()
        # maxheaderlen=0 means don't line wrap headers.
        gen = generator.Generator(str_io, maxheaderlen=0)
        gen.flatten(msg, unixfrom=False)
        body = str_io.getvalue()

        # Strip off the \n\n that the MIME lib tacks onto the end of the
        # payload.
        if request.body is None:
            body = body[:-2]

        return status_line + body