7. SIP消息 (SIP Messages)
SIP是基于文本的协议, 使用UTF-8字符集 (RFC 2279 [7])。
SIP消息要么是从客户端到服务器的请求 (Request), 要么是从服务器到客户端的响应 (Response)。
请求 (第7.1节) 和响应 (第7.2节) 消息都使用RFC 2822 [3] 的基本格式, 尽管语法在字符集和语法细节上有所不同。(例如, SIP允许的头字段可能不是有效的RFC 2822头字段。) 两种类型的消息都由起始行 (Start-Line)、一个或多个头字段 (Header Field)、指示头字段结束的空行以及可选的消息体 (Message-Body) 组成。
generic-message = start-line
*message-header
CRLF
[ message-body ]
start-line = Request-Line / Status-Line
起始行、每个消息头行和空行必须以回车换行序列 (CRLF) 终止。请注意, 即使消息体不存在, 空行也必须存在。
除了上述字符集的差异外, SIP的大部分消息和头字段语法与HTTP/1.1相同。我们使用 [HX.Y] 来引用当前HTTP/1.1规范 (RFC 2616 [8]) 的第X.Y节, 而不是在此重复语法和语义。
然而, SIP不是HTTP的扩展。
7.1 请求 (Requests)
SIP请求通过具有请求行 (Request-Line) 作为起始行来区分。请求行包含方法名称、请求URI和协议版本, 由单个空格 (SP) 字符分隔。
请求行以CRLF结束。除了行尾CRLF序列外, 不允许使用CR或LF。任何元素中都不允许线性空白 (LWS)。
Request-Line = Method SP Request-URI SP SIP-Version CRLF
Method (方法)
本规范定义了六种方法:
- REGISTER: 用于注册联系信息
- INVITE: 用于建立会话
- ACK: 用于确认INVITE
- CANCEL: 用于取消会话建立
- BYE: 用于终止会话
- OPTIONS: 用于查询服务器能力
在标准跟踪RFC中记录的SIP扩展可以定义额外的方法。
Request-URI (请求URI)
Request-URI是第19.1节中描述的SIP或SIPS URI, 或一般URI (RFC 2396 [5])。它指示此请求所针对的用户或服务。Request-URI不得包含未转义的空格或控制字符, 并且不得用 <> 括起来。
SIP元素可以支持除"sip"和"sips"之外的其他方案的Request-URI, 例如RFC 2806 [9] 的"tel" URI方案。SIP元素可以使用任何可用的机制转换非SIP URI, 生成SIP URI、SIPS URI或其他方案。
SIP-Version (SIP版本)
请求和响应消息都包括正在使用的SIP版本, 并遵循 [H3.1] (将HTTP替换为SIP, 将HTTP/1.1替换为SIP/2.0) 关于版本排序、合规性要求和版本号升级的规定。要符合本规范, 发送SIP消息的应用程序必须包含"SIP/2.0"的SIP-Version。SIP-Version字符串不区分大小写, 但实现必须发送大写。
与HTTP/1.1不同, SIP将版本号视为文字字符串。在实践中, 这应该没有区别。
7.2 响应 (Responses)
SIP响应通过具有状态行 (Status-Line) 作为起始行来与请求区分。状态行由协议版本、数字状态代码及其关联的文本短语组成, 每个元素由单个SP字符分隔。
除了最终CRLF序列外, 不允许使用CR或LF。
Status-Line = SIP-Version SP Status-Code SP Reason-Phrase CRLF
Status-Code (状态代码)
状态代码是一个3位整数结果代码, 指示理解和满足请求的尝试的结果。原因短语 (Reason-Phrase) 旨在给出状态代码的简短文本描述。状态代码旨在供自动机使用, 而原因短语旨在供人类用户使用。客户端不需要检查或显示原因短语。
虽然本规范为原因短语建议了特定措辞, 但实现可以选择其他文本, 例如, 使用请求的Accept-Language头字段中指示的语言。
响应类别 (Response Classes)
状态代码的第一位数字定义响应的类别。最后两位数字没有任何分类作用。因此, 状态代码在100到199之间的任何响应被称为"1xx响应", 状态代码在200到299之间的任何响应被称为"2xx响应", 依此类推。SIP/2.0允许第一位数字有六个值:
- 1xx: 临时响应 (Provisional) - 已收到请求, 继续处理请求;
- 2xx: 成功 (Success) - 操作已成功接收、理解和接受;
- 3xx: 重定向 (Redirection) - 需要采取进一步行动才能完成请求;
- 4xx: 客户端错误 (Client Error) - 请求包含错误的语法或无法在此服务器上完成;
- 5xx: 服务器错误 (Server Error) - 服务器未能完成明显有效的请求;
- 6xx: 全局故障 (Global Failure) - 请求无法在任何服务器上完成。
第21节定义了这些类别并描述了各个代码。
7.3 头字段 (Header Fields)
SIP头字段在语法和语义上都类似于HTTP头字段。特别是, SIP头字段遵循 [H4.2] 对消息头的语法定义以及在多行上扩展头字段的规则。但是, 后者在HTTP中使用隐式空白和折叠指定。本规范符合RFC 2234 [10], 仅使用显式空白和折叠作为语法的组成部分。
[H4.2] 还指定, 值为逗号分隔列表的相同字段名称的多个头字段可以组合成一个头字段。这也适用于SIP, 但由于语法不同, 具体规则也不同。具体来说, 语法形式为以下的任何SIP头:
header = "header-name" HCOLON header-value *(COMMA header-value)
允许将同名的头字段组合成逗号分隔列表。Contact头字段允许逗号分隔列表, 除非头字段值为"*"。
7.3.1 头字段格式 (Header Field Format)
头字段遵循RFC 2822 [3] 第2.2节中给出的相同通用头格式。每个头字段由字段名称、冒号 (":") 和字段值组成。
field-name: field-value
第25节中指定的消息头的正式语法允许冒号两侧有任意数量的空白; 但是, 实现应避免在字段名称和冒号之间使用空格, 并在冒号和字段值之间使用单个空格 (SP)。
Subject: lunch
Subject : lunch
Subject :lunch
Subject: lunch
因此, 上述都是有效且等效的, 但最后一个是首选形式。
头字段可以通过在每个额外行前加上至少一个SP或水平制表符 (HT) 来扩展到多行。换行符和下一行开头的空白被视为单个SP字符。因此, 以下是等效的:
Subject: I know you're there, pick up the phone and talk to me!
Subject: I know you're there,
pick up the phone
and talk to me!
具有不同字段名称的头字段的相对顺序不重要。但是, 建议将代理处理所需的头字段 (例如Via、Route、Record-Route、Proxy-Require、Max-Forwards和Proxy-Authorization) 放在消息顶部以便快速解析。具有相同字段名称的头字段行的相对顺序很重要。如果并且仅当该头字段的整个字段值定义为逗号分隔列表 (即, 如果遵循第7.3节中定义的语法) 时, 具有相同字段名称的多个头字段行才可以出现在消息中。必须可以通过将每个后续字段值附加到第一个字段值 (每个由逗号分隔) 来将多个头字段行组合成一个"field-name: field-value"对, 而不更改消息的语义。此规则的例外是WWW-Authenticate、Authorization、Proxy-Authenticate和Proxy-Authorization头字段。具有这些名称的多个头字段行可以出现在消息中, 但由于它们的语法不遵循第7.3节中列出的一般形式, 因此它们不得组合成单个头字段行。
实现必须能够处理同名的多个头字段行, 无论是单值每行形式还是逗号分隔值形式的任何组合。
以下头字段行组是有效且等效的:
Route: <sip:[email protected]>
Subject: Lunch
Route: <sip:[email protected]>
Route: <sip:[email protected]>
Route: <sip:[email protected]>, <sip:[email protected]>
Route: <sip:[email protected]>
Subject: Lunch
Subject: Lunch
Route: <sip:[email protected]>, <sip:[email protected]>,
<sip:[email protected]>
以下每个块都有效但彼此不等效:
Route: <sip:[email protected]>
Route: <sip:[email protected]>
Route: <sip:[email protected]>
Route: <sip:[email protected]>
Route: <sip:[email protected]>
Route: <sip:[email protected]>
Route: <sip:[email protected]>,<sip:[email protected]>,
<sip:[email protected]>
头字段值的格式根据头名称定义。它将始终是TEXT-UTF8八位字节的不透明序列, 或空白、标记、分隔符和引用字符串的组合。许多现有头字段将遵循值后跟分号分隔的参数名称、参数值对序列的一般形式:
field-name: field-value *(;parameter-name=parameter-value)
即使可以将任意数量的参数对附加到头字段值, 任何给定的参数名称不得出现多次。
在比较头字段时, 字段名称始终不区分大小写。除非在特定头字段的定义中另有说明, 否则字段值、参数名称和参数值不区分大小写。标记始终不区分大小写。除非另有规定, 表示为引用字符串的值区分大小写。例如,
Contact: <sip:[email protected]>;expires=3600
等同于
CONTACT: <sip:[email protected]>;ExPiReS=3600
并且
Content-Disposition: session;handling=optional
等同于
content-disposition: Session;HANDLING=OPTIONAL
以下两个头字段不等效:
Warning: 370 devnull "Choose a bigger pipe"
Warning: 370 devnull "CHOOSE A BIGGER PIPE"
7.3.2 头字段分类 (Header Field Classification)
某些头字段仅在请求或响应中有意义。这些分别称为请求头字段 (Request Header Field) 和响应头字段 (Response Header Field)。如果头字段出现在与其类别不匹配的消息中 (例如响应中的请求头字段), 则必须忽略它。第20节定义了每个头字段的分类。
7.3.3 紧凑形式 (Compact Form)
SIP提供了一种机制来以缩写形式表示常见头字段名称。当消息由于其他原因变得太大而无法在可用的传输上承载 (例如, 使用UDP时超过最大传输单元 (MTU)) 时, 这可能很有用。这些紧凑形式在第20节中定义。紧凑形式可以随时替代头字段名称的较长形式, 而不改变消息的语义。头字段名称可以在同一消息中以长形式和短形式出现。实现必须接受每个头名称的长形式和短形式。
7.4 消息体 (Bodies)
请求 (包括本规范的扩展中定义的新请求) 可以包含消息体, 除非另有说明。消息体的解释取决于请求方法。
对于响应消息, 请求方法和响应状态代码确定任何消息体的类型和解释。所有响应都可以包含消息体。
7.4.1 消息体类型 (Message Body Type)
消息体的互联网媒体类型必须由Content-Type头字段给出。如果消息体经过任何编码 (例如压缩), 则必须由Content-Encoding头字段指示; 否则, 必须省略Content-Encoding。如果适用, 消息体的字符集作为Content-Type头字段值的一部分指示。
RFC 2046 [11] 中定义的"multipart" MIME类型可以在消息体中使用。发送包含多部分消息体的请求的实现必须将会话描述作为非多部分消息体发送, 如果远程实现通过不包含multipart的Accept头字段请求这样做。
SIP消息可以包含二进制消息体或消息体部分。当发送方未提供显式字符集参数时, "text"类型的媒体子类型被定义为具有"UTF-8"的默认字符集值。
7.4.2 消息体长度 (Message Body Length)
消息体的字节长度由Content-Length头字段提供。第20.14节详细描述了此头字段的必要内容。
HTTP/1.1的"chunked"传输编码不得用于SIP。(注意: chunked编码修改消息体以将其作为一系列块传输, 每个块都有自己的大小指示器。)
7.5 SIP消息的成帧 (Framing SIP Messages)
与HTTP不同, SIP实现可以使用UDP或其他不可靠的数据报协议。每个这样的数据报承载一个请求或响应。有关使用不可靠传输的约束, 请参见第18节。
通过面向流的传输处理SIP消息的实现必须忽略起始行之前出现的任何CRLF [H4.1]。
Content-Length头字段值用于定位流中每个SIP消息的结尾。当通过面向流的传输发送SIP消息时, 它将始终存在。
消息结构总结:
SIP消息
├── 起始行 (Start-Line)
│ ├── 请求行 (Request-Line): Method SP Request-URI SP SIP-Version CRLF
│ └── 状态行 (Status-Line): SIP-Version SP Status-Code SP Reason-Phrase CRLF
├── 头字段 (Header Fields)
│ ├── 必需头字段
│ └── 可选头字段
├── 空行 (CRLF)
└── 消息体 (Message-Body) [可选]