Browse Source

OK I think I got Via parsing working.

pull/2/head
Justine Alexandra Roberts Tunney 11 years ago
parent
commit
44e9d49e3f
3 changed files with 6894 additions and 6328 deletions
  1. +6709
    -6172
      sip/msg_parse.go
  2. +50
    -21
      sip/msg_parse.rl
  3. +135
    -135
      sip/msg_test.go

+ 6709
- 6172
sip/msg_parse.go
File diff suppressed because it is too large
View File


+ 50
- 21
sip/msg_parse.rl View File

@ -12,11 +12,12 @@
// but are phenomenally more complicated.
//
// SIP messages are quite insane. Whitespace can be used liberally in a variety
// of different ways. Header values can have line continuations or even
// comments. Header names are case-insensitive and sometimes have shorthand
// notation. Custom headers may be specified. Via and address headers can be
// repeated, or contain repeating values. URIs can be specified with or without
// address angle brackets. URI parameters can belong to either the URI or the
// of different ways. Like they even let you put a colon between a via hostname
// and port! Header values can have line continuations or even comments. Header
// names are case-insensitive and sometimes have shorthand notation. Custom
// headers may be specified. Via and address headers can be repeated, or
// contain repeating values. URIs can be specified with or without address
// angle brackets. URI parameters can belong to either the URI or the
// address. Values can be escaped. String literals can be quoted. Oh the
// humanity. See the torture messages in msg_test.go for examples.
//
@ -141,14 +142,10 @@ func ParseMsgBytes(data []byte) (msg *Msg, err error) {
msg.Phrase = string(buf[0:amt])
}
action NewVia {
via = new(Via)
}
action Via {
*viap = via
viap = &via.Next
via = nil
// via = nil
}
action ViaProtocol {
@ -186,6 +183,24 @@ func ParseMsgBytes(data []byte) (msg *Msg, err error) {
fgoto value;
}
action goto_via {
via = new(Via)
fgoto via;
}
action goto_via_port {
fgoto via_port;
}
action goto_via_pname {
amt = 0 // Needed so ViaParam action works when there's no value.
fgoto via_pname;
}
action goto_via_pvalue {
fgoto via_pvalue;
}
action gxh {
fhold;
fgoto xheader;
@ -352,8 +367,10 @@ func ParseMsgBytes(data []byte) (msg *Msg, err error) {
# Via Parsing
#
# This header is defined in a relatively deterministic manner by the SIP
# RFC and as such can be defined rather eloquently in Ragel.
# Parsing these is kind of difficult because infinite whitespace is allowed
# between colons, semicolons, commas, and don't forget that lines can
# continue. So we're going to break things down into four separate machines
# that jump between each other.
ViaProtocol = token >mark %ViaProtocol;
ViaVersion = token >mark %ViaVersion;
ViaTransport = token >mark %ViaTransport;
@ -362,16 +379,28 @@ func ParseMsgBytes(data []byte) (msg *Msg, err error) {
ViaHostIPv6 = "[" ( xdigit | "." | ":" )+ >mark %ViaHost "]";
ViaHostName = ( alnum | "." | "-" )+ >mark %ViaHost;
ViaHost = ViaHostIPv4 | ViaHostIPv6 | ViaHostName;
ViaPort = digit {1,5} @ViaPort;
ViaPort = digit+ @ViaPort;
ViaParamName = token >mark %name;
ViaParamContent = tokenhost >start @append;
ViaParamValue = ViaParamContent | quoted_string;
ViaParamEntry = ViaParamName ( EQUAL ViaParamValue )?;
ViaParam = ViaParamEntry %ViaParam;
ViaSentBy = ViaHost ( COLON ViaPort )?;
ViaEntry = ViaSent LWS ViaSentBy ( SEMI ViaParam )* <: any @hold;
Via = ViaEntry >NewVia %Via;
Vias = Via ( COMMA Via )* <: any @hold;
via_pvalue_end = ( CR when !lookAheadWSP ) LF @ViaParam @Via @goto_header
| SEMI <: any @hold @ViaParam @goto_via_pname
| COMMA <: any @hold @ViaParam @Via @goto_via;
via_pvalue := ViaParamValue via_pvalue_end;
via_pname_end = ( CR when !lookAheadWSP ) LF @ViaParam @Via @goto_header
| EQUAL <: any @hold @goto_via_pvalue
| SEMI <: any @hold @ViaParam @goto_via_pname
| COMMA <: any @hold @ViaParam @Via @goto_via;
via_pname := ViaParamName via_pname_end;
via_port_end = ( CR when !lookAheadWSP ) LF @Via @goto_header
| SEMI <: any @hold @goto_via_pname
| COMMA <: any @hold @Via @goto_via;
via_port := ViaPort via_port_end;
via_end = ( CR when !lookAheadWSP ) LF @Via @goto_header
| COLON <: any @hold @goto_via_port
| SEMI <: any @hold @goto_via_pname
| COMMA <: any @hold @Via @goto_via;
via := ViaSent LWS ViaHost via_end;
# Address Header Name Definitions
#
@ -439,7 +468,6 @@ func ParseMsgBytes(data []byte) (msg *Msg, err error) {
| ("Expires"i | "l"i) $!gxh HCOLON digit+ >{msg.Expires=0} @Expires
| ("Max-Forwards"i | "l"i) $!gxh HCOLON digit+ >{msg.MaxForwards=0} @MaxForwards
| ("Min-Expires"i | "l"i) $!gxh HCOLON digit+ >{msg.MinExpires=0} @MinExpires
| ("Via"i | "v"i) $!gxh HCOLON Vias
;
# Header Parsing
@ -477,7 +505,8 @@ func ParseMsgBytes(data []byte) (msg *Msg, err error) {
xheader := token %name HCOLON <: any @{value=nil;addr=nil} @hold @goto_value;
sheader = cheader <: CRLF @goto_header
| aname $!gxh HCOLON <: any @{value=nil} @hold @goto_value
| sname $!gxh HCOLON <: any @{addr=nil} @hold @goto_value;
| sname $!gxh HCOLON <: any @{addr=nil} @hold @goto_value
| ("Via"i | "v"i) $!gxh HCOLON <: any @hold @goto_via;
header := CRLF @break
| tokenc @mark @hold sheader;


+ 135
- 135
sip/msg_test.go View File

@ -403,7 +403,7 @@ var msgTests = []msgTest{
msgTest{
name: "Via Line Continuation",
s: "SIP/2.0 200 OK\r\n" +
"Via: SIP/2.0/UDP 10.11.34.37,\r\n" +
"Via: SIP/2.0/UDP 10.11.34.37 ,\r\n" +
" SIP/2.0/UDP 10.11.34.38\r\n" +
"Warning: Maids heard the goblins cry\r\n" +
"\r\n",
@ -912,139 +912,139 @@ var msgTests = []msgTest{
},
},
// msgTest{
// name: "RFC4475 Torture Message #1",
// s: "INVITE sip:vivekg@chair-dnrc.example.com;unknownparam SIP/2.0\r\n" +
// "TO :\r\n" +
// " sip:vivekg@chair-dnrc.example.com ; tag = 1918181833n\r\n" +
// "from : \"J Rosenberg \\\\\\\"\" <sip:jdrosen@example.com>\r\n" +
// " ;\r\n" +
// " tag = 98asjd8\r\n" +
// "MaX-fOrWaRdS: 0068\r\n" +
// "Call-ID: wsinv.ndaksdj@192.0.2.1\r\n" +
// "Content-Length : 150\r\n" +
// "cseq: 0009\r\n" +
// " INVITE\r\n" +
// "Via : SIP / 2.0\r\n" +
// " /UDP\r\n" +
// " 192.0.2.2;branch=390skdjuw\r\n" +
// "s :\r\n" +
// "NewFangledHeader: newfangled value\r\n" +
// " continued newfangled value\r\n" +
// "UnknownHeaderWithUnusualValue: ;;,,;;,;\r\n" +
// "Content-Type: application/sdp-JART\r\n" +
// "Route:\r\n" +
// " <sip:services.example.com;lr;unknownwith=value;unknown-no-value>\r\n" +
// "v: SIP / 2.0 / TCP spindle.example.com ;\r\n" +
// " branch = z9hG4bK9ikj8 ,\r\n" +
// " SIP / 2.0 / UDP 192.168.255.111 ; branch=\r\n" +
// " z9hG4bK30239\r\n" +
// "m:\"Quoted string \\\"\\\"\" <sip:jdrosen@example.com> ; newparam =\r\n" +
// " newvalue ;\r\n" +
// " secondparam ; q = 0.33\r\n" +
// "\r\n" +
// "v=0\r\n" +
// "o=mhandley 29739 7272939 IN IP4 192.0.2.3\r\n" +
// "s=-\r\n" +
// "c=IN IP4 192.0.2.4\r\n" +
// "t=0 0\r\n" +
// "m=audio 49217 RTP/AVP 0 12\r\n" +
// "m=video 3227 RTP/AVP 31\r\n" +
// "a=rtpmap:31 LPC\r\n",
// msg: sip.Msg{
// Method: "INVITE",
// VersionMajor: 2,
// Request: &sip.URI{
// Scheme: "sip",
// User: "vivekg",
// Host: "chair-dnrc.example.com",
// Params: sip.Params{"unknownparam": ""},
// },
// To: &sip.Addr{
// Uri: &sip.URI{
// Scheme: "sip",
// User: "vivekg",
// Host: "chair-dnrc.example.com",
// },
// Params: sip.Params{"tag": "1918181833n"},
// },
// From: &sip.Addr{
// Display: "J Rosenberg \\\"",
// Uri: &sip.URI{
// Scheme: "sip",
// User: "vivekg",
// Host: "chair-dnrc.example.com",
// Params: sip.Params{"tag": "98asjd8"},
// },
// },
// MaxForwards: 68,
// CallID: "wsinv.ndaksdj@192.0.2.1",
// CSeq: 9,
// CSeqMethod: "INVITE",
// Via: &sip.Via{
// Protocol: "SIP",
// Version: "2.0",
// Transport: "UDP",
// Host: "192.0.2.2",
// Params: sip.Params{"branch": "390skdjuw"},
// Next: &sip.Via{
// Protocol: "SIP",
// Version: "2.0",
// Transport: "TCP",
// Host: "spindle.example.com",
// Params: sip.Params{"branch": "z9hG4bK9ikj8"},
// Next: &sip.Via{
// Protocol: "SIP",
// Version: "2.0",
// Transport: "UDP",
// Host: "192.168.255.111",
// Params: sip.Params{"branch": "z9hG4bK30239"},
// },
// },
// },
// Subject: "",
// Headers: sip.Headers{
// "NewFangledHeader": "newfangled value\r\n" +
// " continued newfangled value",
// "UnknownHeaderWithUnusualValue": ";;,,;;,;",
// },
// Route: &sip.Addr{
// Uri: &sip.URI{
// Scheme: "sip",
// Host: "services.example.com",
// Params: sip.Params{
// "lr": "",
// "unknownwith": "value",
// "unknown-no-value": "",
// },
// },
// },
// Contact: &sip.Addr{
// Display: "Quoted string \"\"",
// Uri: &sip.URI{
// Scheme: "sip",
// User: "jdrosen",
// Host: "example.com",
// },
// Params: sip.Params{
// "newparam": "newvalue",
// "secondparam": "",
// "q": "0.33",
// },
// },
// Payload: &sip.MiscPayload{
// T: "application/sdp-JART",
// D: []byte("v=0\r\n" +
// "o=mhandley 29739 7272939 IN IP4 192.0.2.3\r\n" +
// "s=-\r\n" +
// "c=IN IP4 192.0.2.4\r\n" +
// "t=0 0\r\n" +
// "m=audio 49217 RTP/AVP 0 12\r\n" +
// "m=video 3227 RTP/AVP 31\r\n" +
// "a=rtpmap:31 LPC\r\n"),
// },
// },
// },
msgTest{
name: "RFC4475 Torture Message #1",
s: "INVITE sip:vivekg@chair-dnrc.example.com;unknownparam SIP/2.0\r\n" +
"TO :\r\n" +
" sip:vivekg@chair-dnrc.example.com ; tag = 1918181833n\r\n" +
"from : \"J Rosenberg \\\\\\\"\" <sip:jdrosen@example.com>\r\n" +
" ;\r\n" +
" tag = 98asjd8\r\n" +
"MaX-fOrWaRdS: 0068\r\n" +
"Call-ID: wsinv.ndaksdj@192.0.2.1\r\n" +
"Content-Length : 150\r\n" +
"cseq: 0009\r\n" +
" INVITE\r\n" +
"Via : SIP / 2.0\r\n" +
" /UDP\r\n" +
" 192.0.2.2;branch=390skdjuw\r\n" +
"s :\r\n" +
"NewFangledHeader: newfangled value\r\n" +
" continued newfangled value\r\n" +
"UnknownHeaderWithUnusualValue: ;;,,;;,;\r\n" +
"Content-Type: application/sdp-JART\r\n" +
"Route:\r\n" +
" <sip:services.example.com;lr;unknownwith=value;unknown-no-value>\r\n" +
"v: SIP / 2.0 / TCP spindle.example.com ;\r\n" +
" branch = z9hG4bK9ikj8 ,\r\n" +
" SIP / 2.0 / UDP 192.168.255.111 ; branch=\r\n" +
" z9hG4bK30239\r\n" +
"m:\"Quoted string \\\"\\\"\" <sip:jdrosen@example.com> ; newparam =\r\n" +
" newvalue ;\r\n" +
" secondparam ; q = 0.33\r\n" +
"\r\n" +
"v=0\r\n" +
"o=mhandley 29739 7272939 IN IP4 192.0.2.3\r\n" +
"s=-\r\n" +
"c=IN IP4 192.0.2.4\r\n" +
"t=0 0\r\n" +
"m=audio 49217 RTP/AVP 0 12\r\n" +
"m=video 3227 RTP/AVP 31\r\n" +
"a=rtpmap:31 LPC\r\n",
msg: sip.Msg{
Method: "INVITE",
VersionMajor: 2,
Request: &sip.URI{
Scheme: "sip",
User: "vivekg",
Host: "chair-dnrc.example.com",
Params: sip.Params{"unknownparam": ""},
},
To: &sip.Addr{
Uri: &sip.URI{
Scheme: "sip",
User: "vivekg",
Host: "chair-dnrc.example.com",
},
Params: sip.Params{"tag": "1918181833n"},
},
From: &sip.Addr{
Display: "J Rosenberg \\\"",
Uri: &sip.URI{
Scheme: "sip",
User: "vivekg",
Host: "chair-dnrc.example.com",
Params: sip.Params{"tag": "98asjd8"},
},
},
MaxForwards: 68,
CallID: "wsinv.ndaksdj@192.0.2.1",
CSeq: 9,
CSeqMethod: "INVITE",
Via: &sip.Via{
Protocol: "SIP",
Version: "2.0",
Transport: "UDP",
Host: "192.0.2.2",
Params: sip.Params{"branch": "390skdjuw"},
Next: &sip.Via{
Protocol: "SIP",
Version: "2.0",
Transport: "TCP",
Host: "spindle.example.com",
Params: sip.Params{"branch": "z9hG4bK9ikj8"},
Next: &sip.Via{
Protocol: "SIP",
Version: "2.0",
Transport: "UDP",
Host: "192.168.255.111",
Params: sip.Params{"branch": "z9hG4bK30239"},
},
},
},
Subject: "",
Headers: sip.Headers{
"NewFangledHeader": "newfangled value\r\n" +
" continued newfangled value",
"UnknownHeaderWithUnusualValue": ";;,,;;,;",
},
Route: &sip.Addr{
Uri: &sip.URI{
Scheme: "sip",
Host: "services.example.com",
Params: sip.Params{
"lr": "",
"unknownwith": "value",
"unknown-no-value": "",
},
},
},
Contact: &sip.Addr{
Display: "Quoted string \"\"",
Uri: &sip.URI{
Scheme: "sip",
User: "jdrosen",
Host: "example.com",
},
Params: sip.Params{
"newparam": "newvalue",
"secondparam": "",
"q": "0.33",
},
},
Payload: &sip.MiscPayload{
T: "application/sdp-JART",
D: []byte("v=0\r\n" +
"o=mhandley 29739 7272939 IN IP4 192.0.2.3\r\n" +
"s=-\r\n" +
"c=IN IP4 192.0.2.4\r\n" +
"t=0 0\r\n" +
"m=audio 49217 RTP/AVP 0 12\r\n" +
"m=video 3227 RTP/AVP 31\r\n" +
"a=rtpmap:31 LPC\r\n"),
},
},
},
}
func TestParseMsg(t *testing.T) {
@ -1070,7 +1070,7 @@ func TestParseMsg(t *testing.T) {
t.Errorf("Via:\n%#v !=\n%#v", test.msg.Via, msg.Via)
t.Errorf("Via #2:\n%#v !=\n%#v", test.msg.Via.Next, msg.Via.Next)
t.Errorf("Via #3:\n%#v !=\n%#v", test.msg.Via.Next.Next, msg.Via.Next.Next)
t.Errorf("Via #4:\n%#v !=\n%#v", test.msg.Via.Next.Next.Next, msg.Via.Next.Next.Next)
// t.Errorf("Via #4:\n%#v !=\n%#v", test.msg.Via.Next.Next.Next, msg.Via.Next.Next.Next)
}
if !reflect.DeepEqual(test.msg.Request, msg.Request) {
t.Errorf("Request:\n%#v !=\n%#v", test.msg.Request, msg.Request)


Loading…
Cancel
Save