-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathumami_utils.go
More file actions
141 lines (116 loc) · 2.83 KB
/
umami_utils.go
File metadata and controls
141 lines (116 loc) · 2.83 KB
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
package traefik_rybbit_feeder
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"regexp"
"strings"
"time"
)
func sendRequest(ctx context.Context, url string, body interface{}, headers http.Header) (*http.Response, error) {
var req *http.Request
var err error
if body != nil {
bodyJson, err := json.Marshal(body)
if err != nil {
return nil, err
}
req, err = http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(bodyJson))
} else {
req, err = http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
}
if err != nil {
return nil, err
}
if headers != nil {
req.Header = headers
}
if body != nil {
req.Header.Set("Content-Type", "application/json")
}
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
status := resp.StatusCode
if status < 200 || status >= 300 {
defer func() {
_ = resp.Body.Close()
}()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("request failed with status %d (failed to read body: %v)", status, err)
}
return nil, fmt.Errorf("request failed with status %d (%v)", status, string(respBody))
}
return resp, nil
}
func sendRequestAndParse(ctx context.Context, url string, body interface{}, headers http.Header, value interface{}) error {
resp, err := sendRequest(ctx, url, body, headers)
if err != nil {
return err
}
defer func() {
_ = resp.Body.Close()
}()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
err = json.Unmarshal(respBody, &value)
if err != nil {
return err
}
return nil
}
func parseDomainFromHost(host string) string {
// check if the host has a port
if strings.Contains(host, ":") {
host = strings.Split(host, ":")[0]
}
if strings.HasSuffix(host, ".") {
host = strings.TrimSuffix(host, ".")
}
return strings.ToLower(host)
}
const parseAcceptLanguagePattern = `([a-zA-Z\-]+)(?:;q=\d\.\d)?(?:,\s)?`
var parseAcceptLanguageRegexp = regexp.MustCompile(parseAcceptLanguagePattern)
func parseAcceptLanguage(acceptLanguage string) string {
matches := parseAcceptLanguageRegexp.FindAllStringSubmatch(acceptLanguage, -1)
if len(matches) == 0 {
return ""
}
return matches[0][1]
}
func extractRemoteIP(req *http.Request) string {
if ip := req.Header.Get("CF-Connecting-IP"); ip != "" {
return ip
}
if ip := req.Header.Get("x-vercel-ip"); ip != "" {
return ip
}
// Standard proxy headers
if xff := req.Header.Get("X-Forwarded-For"); xff != "" {
ips := strings.Split(xff, ",")
if len(ips) > 0 {
return strings.TrimSpace(ips[0])
}
}
if xrip := req.Header.Get("X-Real-IP"); xrip != "" {
return xrip
}
// Direct connection
if req.RemoteAddr != "" {
ip, _, err := net.SplitHostPort(req.RemoteAddr)
if err == nil {
return ip
}
return req.RemoteAddr
}
return ""
}