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