forked from jjeffery/stomp
/
frame.go
118 lines (109 loc) · 3.29 KB
/
frame.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
package client
import (
"gopkg.in/stomp.v1"
"gopkg.in/stomp.v1/frame"
"regexp"
"sort"
"strconv"
"strings"
)
const (
// Maximum permitted heart-beat timeout, about 11.5 days.
// Any client CONNECT frame with a larger value than this
// will be rejected.
maxHeartBeat = 999999999
)
var (
// Regexp for heart-beat header value
heartBeatRegexp = regexp.MustCompile("^[0-9]{1,9},[0-9]{1,9}$")
)
// Determine the most acceptable version based on the accept-version
// header of a CONNECT or STOMP frame.
//
// Returns stomp.V10 if a CONNECT frame and the accept-version header is missing.
//
// Returns an error if the frame is not a CONNECT or STOMP frame, or
// if the accept-header is malformed or does not contain any compatible
// version numbers. Also returns an error if the accept-header is missing
// for a STOMP frame.
//
// Otherwise, returns the highest compatible version specified in the
// accept-version header. Compatible versions are V1_0, V1_1 and V1_2.
func determineVersion(f *stomp.Frame) (version stomp.Version, err error) {
// frame can be CONNECT or STOMP with slightly different
// handling of accept-verion for each
isConnect := f.Command == frame.CONNECT
if !isConnect && f.Command != frame.STOMP {
err = notConnectFrame
return
}
// start with an error, and remove if successful
err = unknownVersion
if acceptVersion, ok := f.Header.Contains(frame.AcceptVersion); ok {
// sort the versions so that the latest version comes last
versions := strings.Split(acceptVersion, ",")
sort.Strings(versions)
for _, v := range versions {
switch stomp.Version(v) {
case stomp.V10:
version = stomp.V10
err = nil
case stomp.V11:
version = stomp.V11
err = nil
case stomp.V12:
version = stomp.V12
err = nil
}
}
} else {
// CONNECT frames can be missing the accept-version header,
// we assume V1.0 in this case. STOMP frames were introduced
// in V1.1, so they must have an accept-version header.
if isConnect {
// no "accept-version" header, so we assume 1.0
version = stomp.V10
err = nil
} else {
err = missingHeader(frame.AcceptVersion)
}
}
return
}
// Determine the heart-beat values in a CONNECT or STOMP frame.
//
// Returns 0,0 if the heart-beat header is missing. Otherwise
// returns the cx and cy values in the frame.
//
// Returns an error if the heart-beat header is malformed, or if
// the frame is not a CONNECT or STOMP frame. In this implementation,
// a heart-beat header is considered malformed if either cx or cy
// is greater than MaxHeartBeat.
func getHeartBeat(f *stomp.Frame) (cx, cy int, err error) {
if f.Command != frame.CONNECT &&
f.Command != frame.STOMP &&
f.Command != frame.CONNECTED {
err = invalidOperationForFrame
return
}
if heartBeat, ok := f.Header.Contains(frame.HeartBeat); ok {
if !heartBeatRegexp.MatchString(heartBeat) {
err = invalidHeartBeat
return
}
// no error checking here because we are confident
// that everything will work because the regexp matches.
slice := strings.Split(heartBeat, ",")
value1, _ := strconv.ParseUint(slice[0], 10, 32)
value2, _ := strconv.ParseUint(slice[1], 10, 32)
cx = int(value1)
cy = int(value2)
} else {
// heart-beat header not present
// this else clause is not necessary, but
// included for clarity.
cx = 0
cy = 0
}
return
}