6. Content-Transfer-Encoding头字段
通过邮件传输的一些数据可能会被声明成它们的“原始”格式,如8位字符(8bit character)或二进制数据(binary data)。这些数据不通过一些传输协议进行传输。如:RFC821(SMTP)中限制邮件消息中只可以由一些包括行结束符CRLF序列在内,长度不超过1000字节的行组成,而且所有的字符都是7位的US-ASCII字符。
因此需要定义一种机制来将这些数据编码为7位数据(7bit data)的短行。并且,当在限制很少的系统中直接传输无限制的格式时,需要对其中未编码内容进行适当的标记。本文档通过一个新的“Content-Transfer-Encoding”头字段来指定这类编码。这个头字段并没有在以前的标准中进行过定义。
6.1 Content-Transfer-Encoding 句法
“Content-Transfer-Encoding”头字段中只有一个值,它指定了编码类型,格式如下:
encoding := "Content-Transfer-Encoding" ":" mechanism
mechanism := "7bit" / "8bit" / "binary" /
"quoted-printable" / "base64" /
ietf-token / x-token
这些值都是大小写无关的,“Base64”、“BASE64”、“bAsE64”的意义相同。
编码方式“7bit”要求实体体中的内容都是7位字节。而且它也是缺省值,这就是说,如果没有“Content-Transfer-Encoding”头字段,则假定其为:“"Content-Transfer-Encoding: 7BIT”。
6.2 Content-Transfer-Encoding 语义
字符串“Content-Transfer-Encoding”实际上提供了两条信息。它指明了在传输主体(body)的时候,采用了哪种编码方式及必须用哪种解码方式将数据解码成它的原始状态。同时,它还指明了解码结果所处的范围。任何“Content-Transfer-Encoding”的转换部分――无论是确定的还是缺省的――都指定了一个单一的、详细定义的解码算法。这个算法可以将编码后的任意字节序列转换为编码前的原始序列,或说明某部分内容是非法的编码序列。“Content-Transfer-Encoding”转换永远不会依赖于附加的外部信息。注意,解码器必须为每一个合法的编码内容提供一个单一的、详细定义的输出。而对于编码器却不存在这样的限制。对同一个输入序列,编码器可以给出不同的,等价的编码序列――这是完全合法的。
目前定义了三种转换方式:恒等的、“quoted-printable”编码、“base64”编码。范围是“binary”、“8bit”、“7bit”。
“Content-Transfer-Encoding”的值为“7bit”、“8bit”、“binary”时,说明编码转换已经完成(也就是没有编码),同时,作为简单的标识符,它们给出了实体体数据的范围,并提供了在某个特定的传输系统中传输数据时可能会采用某种编码方式的相关信息。术语“7bit data”、“8bit data”、“binary data”的定义见第二节。
“quoted-printable”及“base64”会将任意的输入内容转换到“7bit”范围中,以使数据可以在受限制的系统中传输。转换的定义将在下文中给出。
必须始终使用正确的“Content-Transfer-Encoding”标志。不允许将未编码的8位字符(8bit characters)标志为“7bit”。而且,未编码的与行无关的内容只能被标识为“binary”。
与媒体子类型不同,“Content-Transfer-Encoding”值不需要有子类型值。然而,不可能只建立一个单一的到“7bit”的转化方式。因为要在以下两个方面进行权衡:对较长的二进制内容进行简洁、高效的编码,或是需要一个更易读的编码内容,而编码可以不完全是7bit的。由于这个原因,至少要提供两种编码机制:或多或少可读的编码(quoted-printable)和“紧凑”、“均匀”的编码(base64)。
在RFC1652中定义了传输未编码的8位数据的方式。到最初公布本文档时为止,还没有为在因特网上传输包含未编码二进制数据邮件而制定的标准。因此就不存在“二进制”(binary) Content-Transfer-Encoding类型值合法的出现在因特网邮件中的情况。然而,当传输“二进制”邮件成为可能时,或MIME被用来连接其它任何的可传输“二进制”邮件的邮件传输机构时,就必须用这种机制对“二进制”内容进行标识。
注意:为“Content-Transfer-Encoding”头字段所定义的五个值只是为媒体类型提供了编码或解码的算法。
6.3 新的Content-Transfer-Encoding
如果需要,实现者可以定义私有的“Content-Transfer-Encoding”值。但是必须使用x标记,就是指要在名字前面加上“X-”,以说明它是一个非标准的状态。如,“Content-Transfer-Encoding: x-my-new-encoding”。 其它的“Content-Transfer-Encoding”标准值,则必须通过标准途径RFC来定义。在RFC2048中给出了这些说明须符合的要求。同样的,除了以“X-”开头的“Content-Transfer-Encoding”名字之外,所有的名字都是为IETF将来的使用而保留的。
与媒体类型及子类型不同,不提倡创建新的“Content-Transfer-Encoding”值。因为它会阻碍互用性,并且几乎没有一点潜在的好处。
6.4 解释及使用
如果“Content-Transfer-Encoding”头字段是消息头信息的一部分,那么它对这个消息中的全部主体(body)都适用。如果“Content-Transfer-Encoding”头字段是实体(entity)头信息的一部分,那么它只适用于这个实体(entity)的主体(body)。如果实体类型是“multipart”,则“Content-Transfer-Encoding”只能是“7bit”、“8bit”、“binary”中的一个。一些更为严格的约束将应用于“message”媒体类型的子类型。
应该注意到,大部分的媒体类型都是按照字节而不是位而定义的,因此,这里描述的机制是解码任意字节流而非位流。如果需要通过这些机制对位流进行编码,则必须要先使用网络位顺序标准(大端字节序[big-endian])将位流转换成8位字节流――位流中靠前的位出现在字节的高位中。如果位流中剩下的部分不足8位,则必须补0。RFC2046中提供了用参数为“padding”的“application/octet-stream”媒体类型来说明上述这种填充机制。
这里定义的编码机制可以将任何数据编码为US-ASCII字符集的内容。因此,如果假设一个实体有如下头字段:
Content-Type: text/plain; charset=ISO-8859-1
Content-transfer-encoding: base64
则必须被解释为:实体内容是BASE64 US-ASCII编码的数据,而原始数据为ISO-8859-1字符集内容,而且解码后内容也处于同一字符集ISO-8859-1中。
特定的“Content-Transfer-Encoding”值可以被用于特定的媒体类型。特别的,明确禁止将除“7bit”、“8bit”、“binary”之外的编码方式应用于任何复合的媒体类型,如递归包含其它“Content-Type”头字段的媒体类型。当前仅有的复合媒体类型是“multipart”和“message”。想要对“multipart”或“message”类型的实体编码时,必须在最里面的一层中,对需要编码的真实实体进行编码。
同样要注意,如果一个实体的编码类型被定义为“7bit”,而其中还包含有一个编码类型为“8bit”的实体。这时,或者外部的“7bit”标签是错误的,因为它包含了8位的数据;或者内部的“8bit”标签对传输系统提出了不必要的要求,因为实际上它包含的数据类型只是7位的。
关于编码约束的注释:虽然禁止在复合结构中使用“Content-Transfer-Encoding”可能有些过度严格,但是必须要防止嵌套编码――这样会导致对数据进行多次编码,以及为正确显示出数据内容必须进行多次解码。嵌套编码会给用户代理的工作增加很大的复杂度:多次编码除了会带来效率问题,还会使消息的原始结构变得含糊。特别的,它们暗示了只有在进行所有的解码操作之后,才可以知道消息内容的类型是什么。禁止嵌套编码会使邮件网关的工作变得复杂,但是,与重复编码可能给用户代理所带来的影响相比,这个问题要小得多。
对于任何带有不可识别的“Content-Transfer-Encoding”值的实体,不论其“Content-Type”真实值是什么,都要将其看作为“application/octet-stream”类型。
“Content-Type”与“Content-Transfer-Encoding”的关系:看起来似乎可以通过被编码媒体的特征来推断出“Content-Transfer-Encoding”的值,或者至少可以通过对一些特定媒体类型的使用来确定“Content-Transfer-Encoding”。但实际上,这些假设是不正确的,这里给出几个原因:首先,对于邮件,存在不同的传输方式,一些编码可能只适用于某些而不是全部的媒体类型或传输方式。(如,在8位传输系统中,不需要对特定字符集中的文本进行编码,而在7位传输系统中,却一定需要编码。)
其次,同一媒体类型在不同的环境中,可能会需要不同的传输编码方式。例如,许多邮件的附言(PostScript)部分完全是由7位数据的短行组成,因此不需要编码。而其它的(特别是那些使用Level 2 PostScript二进制编码机制的)附言可能需要使用二进制传输编码进行描述。
最后,因为“Content-Type”已经被制定为可扩充式的规范机制,所以,如果严格定义媒体类型与编码的关系,就会将应用协议的定义与更低层的传输细节相结合。而这是不合乎要求的,因为媒体类型的设计者不一定需要知道所有会被使用的传输方式及其局限性。
6.5编码转换
可以在“quoted-printable”和“base64”编码方式之间进行转换操作。只有当需要在“quoted-printable”编码中强制输出换行符的时候才需要这种操作。从“quoted-printable”转换到“base64”格式的时候,“quoted-printable”编码中的换行符被表示为CRLF序列。因此,它必须被转换为用“base64”方式编码后的相应内容。同样,解码后数据中的CRLF序列也必须被转换成“quoted-printable”的强制换行符,但这只适用于文本情况。