-
Notifications
You must be signed in to change notification settings - Fork 109
/
headers.go
701 lines (553 loc) · 16.2 KB
/
headers.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
package base
import (
"github.com/stefankopieczek/gossip/log"
"github.com/stefankopieczek/gossip/utils"
)
import "bytes"
import "fmt"
import "strconv"
import "strings"
// Whitespace recognised by SIP protocol.
const c_ABNF_WS = " \t"
// Maybestring contains a string, or nil.
type MaybeString interface {
implementsMaybeString()
}
// NoString represents the absence of a string.
type NoString struct{}
func (n NoString) implementsMaybeString() {}
// String represents an actual string.
type String struct {
S string
}
func (s String) implementsMaybeString() {}
func (s String) String() string {
return s.S
}
// A single logical header from a SIP message.
type SipHeader interface {
// Produce the string representation of the header.
String() string
// Produce the name of the header (e.g. "To", "Via")
Name() string
// Produce an exact copy of this header.
Copy() SipHeader
}
// A URI from any schema (e.g. sip:, tel:, callto:)
type Uri interface {
// Determine if the two URIs are equal according to the rules in RFC 3261 s. 19.1.4.
Equals(other Uri) bool
// Produce the string representation of the URI.
String() string
// Produce an exact copy of this URI.
Copy() Uri
}
// A URI from a schema suitable for inclusion in a Contact: header.
// The only such URIs are sip/sips URIs and the special wildcard URI '*'.
type ContactUri interface {
Uri
// Return true if and only if the URI is the special wildcard URI '*'; that is, if it is
// a WildcardUri struct.
IsWildcard() bool
}
// A SIP or SIPS URI, including all params and URI header params.
type SipUri struct {
// True if and only if the URI is a SIPS URI.
IsEncrypted bool
// The user part of the URI: the 'joe' in sip:joe@bloggs.com
// This is a pointer, so that URIs without a user part can have 'nil'.
User MaybeString
// The password field of the URI. This is represented in the URI as joe:hunter2@bloggs.com.
// Note that if a URI has a password field, it *must* have a user field as well.
// This is a pointer, so that URIs without a password field can have 'nil'.
// Note that RFC 3261 strongly recommends against the use of password fields in SIP URIs,
// as they are fundamentally insecure.
Password MaybeString
// The host part of the URI. This can be a domain, or a string representation of an IP address.
Host string
// The port part of the URI. This is optional, and so is represented here as a pointer type.
Port *uint16
// Any parameters associated with the URI.
// These are used to provide information about requests that may be constructed from the URI.
// (For more details, see RFC 3261 section 19.1.1).
// These appear as a semicolon-separated list of key=value pairs following the host[:port] part.
UriParams Params
// Any headers to be included on requests constructed from this URI.
// These appear as a '&'-separated list at the end of the URI, introduced by '?'.
// Although the values of the map are MaybeStrings, they will never be NoString in practice as the parser
// guarantees to not return blank values for header elements in SIP URIs.
// You should not set the values of headers to NoString.
Headers Params
}
func copyWithNil(params Params) Params {
if (params == nil) {
return NewParams()
}
return params.Copy()
}
// Copy the Sip URI.
func (uri *SipUri) Copy() Uri {
var port *uint16
if uri.Port != nil {
temp := *uri.Port
port = &temp
}
return &SipUri{
uri.IsEncrypted,
uri.User,
uri.Password,
uri.Host,
port,
copyWithNil(uri.UriParams),
copyWithNil(uri.Headers),
}
}
// IsWildcard() always returns 'false' for SIP URIs as they are not equal to the wildcard '*' URI.
// This method is required since SIP URIs are valid in Contact: headers.
func (uri *SipUri) IsWildcard() bool {
return false
}
// Determine if the SIP URI is equal to the specified URI according to the rules laid down in RFC 3261 s. 19.1.4.
// TODO: The Equals method is not currently RFC-compliant; fix this!
func (uri *SipUri) Equals(otherUri Uri) bool {
otherPtr, ok := otherUri.(*SipUri)
if !ok {
return false
}
other := *otherPtr
result := uri.IsEncrypted == other.IsEncrypted &&
uri.User == other.User &&
uri.Password == other.Password &&
uri.Host == other.Host &&
utils.Uint16PtrEq(uri.Port, other.Port)
if !result {
return false
}
if !uri.UriParams.Equals(other.UriParams) {
return false
}
if !uri.Headers.Equals(other.Headers) {
return false
}
return true
}
// Generates the string representation of a SipUri struct.
func (uri *SipUri) String() string {
var buffer bytes.Buffer
// Compulsory protocol identifier.
if uri.IsEncrypted {
buffer.WriteString("sips")
buffer.WriteString(":")
} else {
buffer.WriteString("sip")
buffer.WriteString(":")
}
// Optional userinfo part.
switch user := uri.User.(type) {
case String:
buffer.WriteString(user.String())
switch pw := uri.Password.(type) {
case String:
buffer.WriteString(":")
buffer.WriteString(pw.String())
}
buffer.WriteString("@")
}
// Compulsory hostname.
buffer.WriteString(uri.Host)
// Optional port number.
if uri.Port != nil {
buffer.WriteString(":")
buffer.WriteString(strconv.Itoa(int(*uri.Port)))
}
if (uri.UriParams != nil) && uri.UriParams.Length() > 0 {
buffer.WriteString(";")
buffer.WriteString(uri.UriParams.ToString(';'))
}
if (uri.Headers != nil) && uri.Headers.Length() > 0 {
buffer.WriteString("?")
buffer.WriteString(uri.Headers.ToString('&'))
}
return buffer.String()
}
// The special wildcard URI used in Contact: headers in REGISTER requests when expiring all registrations.
type WildcardUri struct{}
// Copy the wildcard URI. Not hard!
func (uri WildcardUri) Copy() Uri { return uri }
// Always returns 'true'.
func (uri WildcardUri) IsWildcard() bool {
return true
}
// Always returns '*' - the representation of a wildcard URI in a SIP message.
func (uri WildcardUri) String() string {
return "*"
}
// Determines if this wildcard URI equals the specified other URI.
// This is true if and only if the other URI is also a wildcard URI.
func (uri WildcardUri) Equals(other Uri) bool {
switch other.(type) {
case WildcardUri:
return true
default:
return false
}
}
// Generic list of parameters on a header.
type Params interface {
Get(k string) (MaybeString, bool)
Add(k string, v MaybeString) Params
Copy() Params
Equals(p Params) bool
ToString(sep uint8) string
Length() int
Items() map[string]MaybeString
Keys() []string
}
type params struct {
params map[string]MaybeString
paramOrder []string
}
// Create an empty set of parameters.
func NewParams() Params {
return ¶ms{map[string]MaybeString{}, []string{}}
}
// Returns the entire parameter map.
func (p *params) Items() map[string]MaybeString {
return p.params
}
// Returns a slice of keys, in order.
func (p *params) Keys() []string {
return p.paramOrder
}
// Returns the requested parameter value.
func (p *params) Get(k string) (MaybeString, bool) {
v, ok := p.params[k]
return v, ok
}
// Add a new parameter.
func (p *params) Add(k string, v MaybeString) Params {
// Add param to order list if new.
if _, ok := p.params[k]; !ok {
p.paramOrder = append(p.paramOrder, k)
}
// Set param value.
p.params[k] = v
// Return the params so calls can be chained.
return p
}
// Copy a list of params.
func (p *params) Copy() Params {
dup := NewParams()
for _, k := range p.Keys() {
if v, ok := p.Get(k); ok {
dup.Add(k, v)
} else {
log.Severe("Internal consistency error. Key %v present in param.Keys() but failed to Get()!", k)
}
}
return dup
}
// Render params to a string.
// Note that this does not escape special characters, this should already have been done before calling this method.
func (p *params) ToString(sep uint8) string {
var buffer bytes.Buffer
first := true
for _, k := range p.Keys() {
v, ok := p.Get(k)
if !ok {
log.Severe("Internal consistency error. Key %v present in param.Keys() but failed to Get()!", k)
continue
}
if !first {
buffer.WriteString(fmt.Sprintf("%c", sep))
}
first = false
buffer.WriteString(fmt.Sprintf("%s", k))
switch v := v.(type) {
case String:
if strings.ContainsAny(v.String(), c_ABNF_WS) {
buffer.WriteString(fmt.Sprintf("=\"%s\"", v.String()))
} else {
buffer.WriteString(fmt.Sprintf("=%s", v.String()))
}
}
}
return buffer.String()
}
// Returns number of params.
func (p *params) Length() int {
return len(p.params)
}
// Check if two maps of parameters are equal in the sense of having the same keys with the same values.
// This does not rely on any ordering of the keys of the map in memory.
func (p *params) Equals(q Params) bool {
if p.Length() == 0 && q.Length() == 0 {
return true
}
if p.Length() != q.Length() {
return false
}
for k, p_val := range p.Items() {
q_val, ok := q.Get(k)
if !ok {
return false
}
if p_val != q_val {
return false
}
}
return true
}
// Encapsulates a header that gossip does not natively support.
// This allows header data that is not understood to be parsed by gossip and relayed to the parent application.
type GenericHeader struct {
// The name of the header.
HeaderName string
// The contents of the header, including any parameters.
// This is transparent data that is not natively understood by gossip.
Contents string
}
// Convert the header to a flat string representation.
func (header *GenericHeader) String() string {
return header.HeaderName + ": " + header.Contents
}
// Pull out the header name.
func (h *GenericHeader) Name() string {
return h.HeaderName
}
// Copy the header.
func (h *GenericHeader) Copy() SipHeader {
return &GenericHeader{h.HeaderName, h.Contents}
}
type ToHeader struct {
// The display name from the header, may be omitted.
DisplayName MaybeString
Address Uri
// Any parameters present in the header.
Params Params
}
func (to *ToHeader) String() string {
var buffer bytes.Buffer
buffer.WriteString("To: ")
switch s := to.DisplayName.(type) {
case String:
buffer.WriteString(fmt.Sprintf("\"%s\" ", s.String()))
}
buffer.WriteString(fmt.Sprintf("<%s>", to.Address))
if to.Params.Length() > 0 {
buffer.WriteString(";")
buffer.WriteString(to.Params.ToString(';'))
}
return buffer.String()
}
func (h *ToHeader) Name() string { return "To" }
// Copy the header.
func (h *ToHeader) Copy() SipHeader {
return &ToHeader{h.DisplayName, h.Address.Copy(), h.Params.Copy()}
}
type FromHeader struct {
// The display name from the header, may be omitted.
DisplayName MaybeString
Address Uri
// Any parameters present in the header.
Params Params
}
func (from *FromHeader) String() string {
var buffer bytes.Buffer
buffer.WriteString("From: ")
switch s := from.DisplayName.(type) {
case String:
buffer.WriteString(fmt.Sprintf("\"%s\" ", s.String()))
}
buffer.WriteString(fmt.Sprintf("<%s>", from.Address))
if from.Params.Length() > 0 {
buffer.WriteString(";")
buffer.WriteString(from.Params.ToString(';'))
}
return buffer.String()
}
func (h *FromHeader) Name() string { return "From" }
// Copy the header.
func (h *FromHeader) Copy() SipHeader {
return &FromHeader{h.DisplayName, h.Address.Copy(), h.Params.Copy()}
}
type ContactHeader struct {
// The display name from the header, may be omitted.
DisplayName MaybeString
Address ContactUri
// Any parameters present in the header.
Params Params
}
func (contact *ContactHeader) String() string {
var buffer bytes.Buffer
buffer.WriteString("Contact: ")
switch s := contact.DisplayName.(type) {
case String:
buffer.WriteString(fmt.Sprintf("\"%s\" ", s.String()))
}
switch contact.Address.(type) {
case *WildcardUri:
// Treat the Wildcard URI separately as it must not be contained in < > angle brackets.
buffer.WriteString("*")
default:
buffer.WriteString(fmt.Sprintf("<%s>", contact.Address.String()))
}
if (contact.Params != nil) && (contact.Params.Length() > 0) {
buffer.WriteString(";")
buffer.WriteString(contact.Params.ToString(';'))
}
return buffer.String()
}
func (h *ContactHeader) Name() string { return "Contact" }
// Copy the header.
func (h *ContactHeader) Copy() SipHeader {
return &ContactHeader{h.DisplayName, h.Address.Copy().(ContactUri), h.Params.Copy()}
}
type CallId string
func (callId CallId) String() string {
return "Call-Id: " + (string)(callId)
}
func (h *CallId) Name() string { return "Call-Id" }
func (h *CallId) Copy() SipHeader {
temp := *h
return &temp
}
type CSeq struct {
SeqNo uint32
MethodName Method
}
func (cseq *CSeq) String() string {
return fmt.Sprintf("CSeq: %d %s", cseq.SeqNo, cseq.MethodName)
}
func (h *CSeq) Name() string { return "CSeq" }
func (h *CSeq) Copy() SipHeader { return &CSeq{h.SeqNo, h.MethodName} }
type MaxForwards uint32
func (maxForwards MaxForwards) String() string {
return fmt.Sprintf("Max-Forwards: %d", ((int)(maxForwards)))
}
func (h MaxForwards) Name() string { return "Max-Forwards" }
func (h MaxForwards) Copy() SipHeader { return h }
type ContentLength uint32
func (contentLength ContentLength) String() string {
return fmt.Sprintf("Content-Length: %d", ((int)(contentLength)))
}
func (h ContentLength) Name() string { return "Content-Length" }
func (h ContentLength) Copy() SipHeader { return h }
type ViaHeader []*ViaHop
// A single component in a Via header.
// Via headers are composed of several segments of the same structure, added by successive nodes in a routing chain.
type ViaHop struct {
// E.g. 'SIP'.
ProtocolName string
// E.g. '2.0'.
ProtocolVersion string
Transport string
Host string
// The port for this via hop. This is stored as a pointer type, since it is an optional field.
Port *uint16
Params Params
}
func (hop *ViaHop) String() string {
var buffer bytes.Buffer
buffer.WriteString(fmt.Sprintf("%s/%s/%s %s",
hop.ProtocolName, hop.ProtocolVersion,
hop.Transport,
hop.Host))
if hop.Port != nil {
buffer.WriteString(fmt.Sprintf(":%d", *hop.Port))
}
if hop.Params.Length() > 0 {
buffer.WriteString(";")
buffer.WriteString(hop.Params.ToString(';'))
}
return buffer.String()
}
// Return an exact copy of this ViaHop.
func (hop *ViaHop) Copy() *ViaHop {
var port *uint16 = nil
if hop.Port != nil {
temp := *hop.Port
port = &temp
}
return &ViaHop{
hop.ProtocolName,
hop.ProtocolVersion,
hop.Transport,
hop.Host,
port,
hop.Params.Copy(),
}
}
func (via ViaHeader) String() string {
var buffer bytes.Buffer
buffer.WriteString("Via: ")
for idx, hop := range via {
buffer.WriteString(hop.String())
if idx != len(via)-1 {
buffer.WriteString(", ")
}
}
return buffer.String()
}
func (h ViaHeader) Name() string { return "Via" }
func (h ViaHeader) Copy() SipHeader {
dup := make([]*ViaHop, 0, len(h))
for _, hop := range h {
dup = append(dup, hop.Copy())
}
return ViaHeader(dup)
}
type RequireHeader struct {
Options []string
}
func (header *RequireHeader) String() string {
return fmt.Sprintf("Require: %s",
strings.Join(header.Options, ", "))
}
func (h *RequireHeader) Name() string { return "Require" }
func (h *RequireHeader) Copy() SipHeader {
dup := make([]string, len(h.Options))
copy(h.Options, dup)
return &RequireHeader{dup}
}
type SupportedHeader struct {
Options []string
}
func (header *SupportedHeader) String() string {
return fmt.Sprintf("Supported: %s",
strings.Join(header.Options, ", "))
}
func (h *SupportedHeader) Name() string { return "Supported" }
func (h *SupportedHeader) Copy() SipHeader {
dup := make([]string, len(h.Options))
copy(h.Options, dup)
return &SupportedHeader{dup}
}
type ProxyRequireHeader struct {
Options []string
}
func (header *ProxyRequireHeader) String() string {
return fmt.Sprintf("Proxy-Require: %s",
strings.Join(header.Options, ", "))
}
func (h *ProxyRequireHeader) Name() string { return "Proxy-Require" }
func (h *ProxyRequireHeader) Copy() SipHeader {
dup := make([]string, len(h.Options))
copy(h.Options, dup)
return &ProxyRequireHeader{dup}
}
// 'Unsupported:' is a SIP header type - this doesn't indicate that the
// header itself is not supported by gossip!
type UnsupportedHeader struct {
Options []string
}
func (header *UnsupportedHeader) String() string {
return fmt.Sprintf("Unsupported: %s",
strings.Join(header.Options, ", "))
}
func (h *UnsupportedHeader) Name() string { return "Unsupported" }
func (h *UnsupportedHeader) Copy() SipHeader {
dup := make([]string, len(h.Options))
copy(h.Options, dup)
return &UnsupportedHeader{dup}
}