// Copyright 2020 Justine Alexandra Roberts Tunney // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // SIP URI Library // // We can't use net.URL because it doesn't support SIP URIs. This is because: // a) it doesn't support semicolon parameters; b) it doesn't extract the user // and host information when the "//" isn't present. // // For example: // // jart@example.test;isup-oli=29 // // Roughly equates to: // // {Scheme: "sip", // User: "jart", // Pass: "", // Host: "example.test", // Port: "", // Params: {"isup-oli": "29"}} // package sip import ( "bytes" "github.com/jart/gosip/util" ) const ( delims = ":/@;?#<>" ) type URI struct { Scheme string // e.g. sip, sips, tel, etc. User string // e.g. sip:USER@host Pass string // e.g. sip:user:PASS@host Host string // e.g. example.com, 1.2.3.4, etc. Port uint16 // e.g. 5060, 80, etc. Param *URIParam // e.g. ;isup-oli=00;day=tuesday Header *URIHeader // e.g. ?subject=project%20x&lol=cat } //go:generate ragel -Z -G2 -o uri_parse.go uri_parse.rl // Deep copies a URI object. func (uri *URI) Copy() *URI { if uri == nil { return nil } res := new(URI) *res = *uri res.Param = uri.Param res.Header = uri.Header return res } // TODO(jart): URI Comparison https://tools.ietf.org/html/rfc3261#section-19.1.4 func (uri *URI) String() string { var b bytes.Buffer uri.Append(&b) return b.String() } func (uri *URI) Append(b *bytes.Buffer) { if uri == nil { return } if uri.Scheme == "" { b.WriteString("sip:") } else { b.WriteString(uri.Scheme) b.WriteByte(':') } if uri.User != "" { if uri.Pass != "" { appendEscaped(b, []byte(uri.User), userc) b.WriteByte(':') appendEscaped(b, []byte(uri.Pass), passc) } else { appendEscaped(b, []byte(uri.User), userc) } b.WriteByte('@') } if util.IsIPv6(uri.Host) { b.WriteByte('[') b.WriteString(uri.Host) b.WriteByte(']') } else { b.WriteString(uri.Host) } if uri.Port > 0 { b.WriteByte(':') b.WriteString(util.Portstr(uri.Port)) } uri.Param.Append(b) uri.Header.Append(b) } func (uri *URI) CompareHostPort(other *URI) bool { if uri != nil && other != nil { if uri.Host == other.Host && uri.GetPort() == other.GetPort() { return true } } return false } func (uri *URI) GetPort() uint16 { if uri.Port == 0 { if uri.Scheme == "sips" { return 5061 } else { return 5060 } } else { return uri.Port } }