(self, base_msg, append_msg)
| 88 | return accumulating_msg |
| 89 | |
| 90 | def _process_msg(self, base_msg, append_msg): |
| 91 | def find_ctype(payload): |
| 92 | return handlers.type_from_starts_with(payload) |
| 93 | |
| 94 | for part in base_msg.walk(): |
| 95 | if is_skippable(part): |
| 96 | continue |
| 97 | |
| 98 | ctype = None |
| 99 | ctype_orig = part.get_content_type() |
| 100 | payload = util.fully_decoded_payload(part) |
| 101 | was_compressed = False |
| 102 | |
| 103 | # When the message states it is of a gzipped content type ensure |
| 104 | # that we attempt to decode said payload so that the decompressed |
| 105 | # data can be examined (instead of the compressed data). |
| 106 | if ctype_orig in DECOMP_TYPES: |
| 107 | try: |
| 108 | payload = util.decomp_gzip(payload, quiet=False) |
| 109 | # At this point we don't know what the content-type is |
| 110 | # since we just decompressed it. |
| 111 | ctype_orig = None |
| 112 | was_compressed = True |
| 113 | except util.DecompressionError as e: |
| 114 | error_message = ( |
| 115 | "Failed decompressing payload from {} of" |
| 116 | " length {} due to: {}".format( |
| 117 | ctype_orig, len(payload), e |
| 118 | ) |
| 119 | ) |
| 120 | _handle_error(error_message, e) |
| 121 | continue |
| 122 | |
| 123 | # Attempt to figure out the payloads content-type |
| 124 | if not ctype_orig: |
| 125 | ctype_orig = UNDEF_TYPE |
| 126 | # There are known cases where mime-type text/x-shellscript included |
| 127 | # non shell-script content that was user-data instead. It is safe |
| 128 | # to check the true MIME type for x-shellscript type since all |
| 129 | # shellscript payloads must have a #! header. The other MIME types |
| 130 | # that cloud-init supports do not have the same guarantee. |
| 131 | if ctype_orig in TYPE_NEEDED + ["text/x-shellscript"]: |
| 132 | ctype = find_ctype(payload) |
| 133 | if ctype is None: |
| 134 | ctype = ctype_orig |
| 135 | |
| 136 | # In the case where the data was compressed, we want to make sure |
| 137 | # that we create a new message that contains the found content |
| 138 | # type with the uncompressed content since later traversals of the |
| 139 | # messages will expect a part not compressed. |
| 140 | if was_compressed: |
| 141 | maintype, subtype = ctype.split("/", 1) |
| 142 | n_part = MIMENonMultipart(maintype, subtype) |
| 143 | n_part.set_payload(payload) |
| 144 | # Copy various headers from the old part to the new one, |
| 145 | # but don't include all the headers since some are not useful |
| 146 | # after decoding and decompression. |
| 147 | if part.get_filename(): |
no test coverage detected