...
1
16
17 package echo
18
19 import (
20 "fmt"
21 "net/http"
22 "regexp"
23 "sort"
24 "strings"
25 )
26
27
28 type Field string
29
30 const (
31 RequestIDField Field = "X-Request-Id"
32 ServiceVersionField Field = "ServiceVersion"
33 ServicePortField Field = "ServicePort"
34 StatusCodeField Field = "StatusCode"
35 URLField Field = "URL"
36 ForwarderURLField Field = "Url"
37 ForwarderMessageField Field = "Echo"
38 ForwarderHeaderField Field = "Header"
39 HostField Field = "Host"
40 HostnameField Field = "Hostname"
41 MethodField Field = "Method"
42 ProtocolField Field = "Proto"
43 AlpnField Field = "Alpn"
44 RequestHeaderField Field = "RequestHeader"
45 ResponseHeaderField Field = "ResponseHeader"
46 ClusterField Field = "Cluster"
47 IPField Field = "IP"
48 LatencyField Field = "Latency"
49 ActiveRequestsField Field = "ActiveRequests"
50 DNSProtocolField Field = "Protocol"
51 DNSQueryField Field = "Query"
52 DNSServerField Field = "DnsServer"
53 CipherField Field = "Cipher"
54 TLSVersionField Field = "Version"
55 TLSServerName Field = "ServerName"
56 )
57
58 var (
59 requestIDFieldRegex = regexp.MustCompile("(?i)" + string(RequestIDField) + "=(.*)")
60 serviceVersionFieldRegex = regexp.MustCompile(string(ServiceVersionField) + "=(.*)")
61 servicePortFieldRegex = regexp.MustCompile(string(ServicePortField) + "=(.*)")
62 statusCodeFieldRegex = regexp.MustCompile(string(StatusCodeField) + "=(.*)")
63 hostFieldRegex = regexp.MustCompile(string(HostField) + "=(.*)")
64 hostnameFieldRegex = regexp.MustCompile(string(HostnameField) + "=(.*)")
65 requestHeaderFieldRegex = regexp.MustCompile(string(RequestHeaderField) + "=(.*)")
66 responseHeaderFieldRegex = regexp.MustCompile(string(ResponseHeaderField) + "=(.*)")
67 URLFieldRegex = regexp.MustCompile(string(URLField) + "=(.*)")
68 ClusterFieldRegex = regexp.MustCompile(string(ClusterField) + "=(.*)")
69 IPFieldRegex = regexp.MustCompile(string(IPField) + "=(.*)")
70 methodFieldRegex = regexp.MustCompile(string(MethodField) + "=(.*)")
71 protocolFieldRegex = regexp.MustCompile(string(ProtocolField) + "=(.*)")
72 alpnFieldRegex = regexp.MustCompile(string(AlpnField) + "=(.*)")
73 )
74
75
76 type Response struct {
77
78
79 RequestURL string
80
81 Method string
82
83 Protocol string
84
85 Alpn string
86
87 RawContent string
88
89 ID string
90
91 URL string
92
93 Version string
94
95 Port string
96
97 Code string
98
99 Host string
100
101 Hostname string
102
103 Cluster string
104
105 IP string
106
107 rawBody map[string]string
108 RequestHeaders http.Header
109 ResponseHeaders http.Header
110 }
111
112 func ParseResponse(output string) Response {
113 out := Response{
114 RawContent: output,
115 RequestHeaders: make(http.Header),
116 ResponseHeaders: make(http.Header),
117 }
118
119 match := requestIDFieldRegex.FindStringSubmatch(output)
120 if match != nil {
121 out.ID = match[1]
122 }
123
124 match = methodFieldRegex.FindStringSubmatch(output)
125 if match != nil {
126 out.Method = match[1]
127 }
128
129 match = protocolFieldRegex.FindStringSubmatch(output)
130 if match != nil {
131 out.Protocol = match[1]
132 }
133
134 match = alpnFieldRegex.FindStringSubmatch(output)
135 if match != nil {
136 out.Alpn = match[1]
137 }
138
139 match = serviceVersionFieldRegex.FindStringSubmatch(output)
140 if match != nil {
141 out.Version = match[1]
142 }
143
144 match = servicePortFieldRegex.FindStringSubmatch(output)
145 if match != nil {
146 out.Port = match[1]
147 }
148
149 match = statusCodeFieldRegex.FindStringSubmatch(output)
150 if match != nil {
151 out.Code = match[1]
152 }
153
154 match = hostFieldRegex.FindStringSubmatch(output)
155 if match != nil {
156 out.Host = match[1]
157 }
158
159 match = hostnameFieldRegex.FindStringSubmatch(output)
160 if match != nil {
161 out.Hostname = match[1]
162 }
163
164 match = URLFieldRegex.FindStringSubmatch(output)
165 if match != nil {
166 out.URL = match[1]
167 }
168
169 match = ClusterFieldRegex.FindStringSubmatch(output)
170 if match != nil {
171 out.Cluster = match[1]
172 }
173
174 match = IPFieldRegex.FindStringSubmatch(output)
175 if match != nil {
176 out.IP = match[1]
177 }
178
179 out.rawBody = map[string]string{}
180
181 matches := requestHeaderFieldRegex.FindAllStringSubmatch(output, -1)
182 for _, kv := range matches {
183 sl := strings.SplitN(kv[1], ":", 2)
184 if len(sl) != 2 {
185 continue
186 }
187 out.RequestHeaders.Set(sl[0], sl[1])
188 }
189
190 matches = responseHeaderFieldRegex.FindAllStringSubmatch(output, -1)
191 for _, kv := range matches {
192 sl := strings.SplitN(kv[1], ":", 2)
193 if len(sl) != 2 {
194 continue
195 }
196 out.ResponseHeaders.Set(sl[0], sl[1])
197 }
198
199 for _, l := range strings.Split(output, "\n") {
200 prefixSplit := strings.Split(l, "body] ")
201 if len(prefixSplit) != 2 {
202 continue
203 }
204 kv := strings.SplitN(prefixSplit[1], "=", 2)
205 if len(kv) != 2 {
206 continue
207 }
208 out.rawBody[kv[0]] = kv[1]
209 }
210
211 return out
212 }
213
214
215 type HeaderType string
216
217 const (
218 RequestHeader HeaderType = "request"
219 ResponseHeader HeaderType = "response"
220 )
221
222
223 func (r Response) GetHeaders(hType HeaderType) http.Header {
224 switch hType {
225 case RequestHeader:
226 return r.RequestHeaders
227 case ResponseHeader:
228 return r.ResponseHeaders
229 default:
230 panic("invalid HeaderType enum: " + hType)
231 }
232 }
233
234
235 func (r Response) Body() []string {
236 type keyValue struct {
237 k, v string
238 }
239 var keyValues []keyValue
240
241 for k, v := range r.rawBody {
242 keyValues = append(keyValues, keyValue{k, v})
243 }
244 sort.Slice(keyValues, func(i, j int) bool {
245 return keyValues[i].k < keyValues[j].k
246 })
247 var resp []string
248 for _, kv := range keyValues {
249 resp = append(resp, kv.v)
250 }
251 return resp
252 }
253
254 func (r Response) String() string {
255 out := ""
256 out += fmt.Sprintf("RawContent: %s\n", r.RawContent)
257 out += fmt.Sprintf("ID: %s\n", r.ID)
258 out += fmt.Sprintf("Method: %s\n", r.Method)
259 out += fmt.Sprintf("Protocol: %s\n", r.Protocol)
260 out += fmt.Sprintf("Alpn: %s\n", r.Alpn)
261 out += fmt.Sprintf("URL: %s\n", r.URL)
262 out += fmt.Sprintf("Version: %s\n", r.Version)
263 out += fmt.Sprintf("Port: %s\n", r.Port)
264 out += fmt.Sprintf("Code: %s\n", r.Code)
265 out += fmt.Sprintf("Host: %s\n", r.Host)
266 out += fmt.Sprintf("Hostname: %s\n", r.Hostname)
267 out += fmt.Sprintf("Cluster: %s\n", r.Cluster)
268 out += fmt.Sprintf("IP: %s\n", r.IP)
269 out += fmt.Sprintf("Request Headers: %v\n", r.RequestHeaders)
270 out += fmt.Sprintf("Response Headers: %v\n", r.ResponseHeaders)
271
272 return out
273 }
274
View as plain text