c++ - 如何使用正则表达式解析 SIP 消息的多行 header ?

标签 c++ regex boost sip

我正在尝试从 SIP 消息的 From: header 中提取 tag

我的正则表达式:^(From:|f:)((?!\\n\\w).)*;[ ]*tag[ ]*=[ ]*([[:alnum:] ]*)

RFC 3261 允许多行 header 。这个新行应该以空格开头。但我对多行标题有疑问。如果 tag 换行,则我的正则表达式不起作用。

示例正确的 SIP 消息:

INVITE sip:13@10.10.1.13 SIP/2.0
Via: SIP/2.0/UDP 10.10.1.99:5060;branch=z9hG4bK343bf628;rport
Contact: <sip:15@10.10.1.99>
Call-ID: 326371826c80e17e6cf6c29861eb2933@10.10.1.99
CSeq: 102 INVITE
User-Agent: Asterisk PBX
Max-Forwards: 70
Date: Wed, 06 Dec 2009 14:12:45 GMT
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY
Supported: replaces
Content-Type: application/sdp
Content-Length: 258
From: "Test 15" <sip:15@10.10.1.99>
 ; tag   =    fromtag
To: <sip:13@10.10.1.13>;tag=totag

v=0
o=root 1821 1821 IN IP4 10.10.1.99
s=session
c=IN IP4 10.10.1.99
t=0 0
m=audio 11424 RTP/AVP 0 8 101
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=silenceSupp:off - - - -
a=ptime:20
a=sendrecv

如何正确解析多行标题?提前致谢。

最佳答案

我赞同使用/生成合适的解析器的动议。

没有什么可以阻止您在单独的步骤中解析 header ,但您仍然可以声明性地指定语法,这是要点。

这里最好的部分确实是

  • 声明式风格使其更容易扩展更多语法(周围的位或更多细节,如不允许 CTL 字符)
  • “免费”调试工具(#define BOOST_SPIRIT_DEBUG,完成)

这是一个简单的多行标题语法:

  • rfc 2616

    Header fields can be extended over multiple lines by preceding each extra line with at least one SP or HT

  • rfc 822

     field       =  field-name ":" [ field-body ] CRLF
    
     field-name  =  1*<any CHAR, excluding CTLs, SPACE, and ":">
    
     field-body  =  field-body-contents
                    [CRLF LWSP-char field-body]
    
     field-body-contents =
                   <the ASCII characters making up the field-body, as
                    defined in the following sections, and consisting
                    of combinations of atom, quoted-string, and
                    specials tokens, or else consisting of texts>
    

所以事不宜迟,这里有一个大致的简单语法,从任何范围的输入迭代器解析为 std::map:

using Headers = std::map<std::string, std::string>;

这是解析器的核心:

    auto& crlf       = "\r\n";
    auto& tspecials = " \t><@,;:\\\"/][?=}{:";

    rule<It, std::string()> token, value;

    token = +~char_(tspecials); // FIXME? should filter CTLs
    value = *(char_ - (crlf >> &(~blank | eoi)));

    Headers headers;
    bool ok = phrase_parse(first, last, (token >> ':' >> value) % crlf >> omit[*lit(crlf)], blank, headers);

#ifdef DEBUG
    if (ok)          std::cerr << "DEBUG: Parse success\n";
    else             std::cerr << "DEBUG: Parse failed\n";
    if (first!=last) std::cerr << "DEBUG: Remaining unparsed input: '" << std::string(first,last) << "'\n";
#endif

您可以看到一个实时演示,它从您的问题中解析示例 header :

Live On Coliru

打印:

Key: 'Allow', Value: 'INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY'
Key: 'CSeq', Value: '102 INVITE'
Key: 'Call-ID', Value: '326371826c80e17e6cf6c29861eb2933@10.10.1.99'
Key: 'Contact', Value: '<sip:15@10.10.1.99>'
Key: 'Content-Length', Value: '258'
Key: 'Content-Type', Value: 'application/sdp'
Key: 'Date', Value: 'Wed, 06 Dec 2009 14:12:45 GMT'
Key: 'From', Value: '"Test 15" <sip:15@10.10.1.99>
; tag   =    fromtag'
Key: 'Max-Forwards', Value: '70'
Key: 'Supported', Value: 'replaces'
Key: 'To', Value: '<sip:13@10.10.1.13>;tag=totag'
Key: 'User-Agent', Value: 'Asterisk PBX'
Key: 'Via', Value: 'SIP/2.0/UDP 10.10.1.99:5060;branch=z9hG4bK343bf628;rport'

请注意,\r\n 组合在 From header 的值中保持原样。如果您想将其规范化为其他一些 LWS 字符,例如简单的 ' ',请使用例如

value = *(omit[ crlf >> !(~blank | eoi) ] >> attr(' ') | (char_ - crlf));

关于c++ - 如何使用正则表达式解析 SIP 消息的多行 header ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32231680/

相关文章:

javascript - 获取字符串中两个符号之间的字符串并将它们插入数组

c++ - 将 std::exception_ptr 转换为 boost::exception_ptr

c++ - 使用 boost 日期的工作日持续时间

c++ - 如何使用 boost 将流放入缓冲区

javascript - 为匹配/不匹配的正则表达式返回 true/false

c# - 如何向 MFC 应用程序添加 list 并设置支持的操作系统?

c++ - libc++ ios_base::clear 的定义在哪里?

c++ - 如何快速生成C++项目树状结构

C++将多大小数组存储在变量中

javascript - 正则表达式尝试将除特定模式之外的任何内容与允许的模式中的字符进行匹配