forked from buger/goreplay
/
http_modifier.go
97 lines (77 loc) · 2 KB
/
http_modifier.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
package main
import (
"github.com/buger/gor/proto"
"hash/fnv"
)
type HTTPModifierConfig struct {
urlRegexp HTTPUrlRegexp
urlRewrite UrlRewriteMap
headerFilters HTTPHeaderFilters
headerHashFilters HTTPHeaderHashFilters
headers HTTPHeaders
methods HTTPMethods
}
type HTTPModifier struct {
config *HTTPModifierConfig
}
func NewHTTPModifier(config *HTTPModifierConfig) *HTTPModifier {
// Optimization to skip modifier completely if we do not need it
if config.urlRegexp.regexp == nil &&
len(config.urlRewrite) == 0 &&
len(config.headerFilters) == 0 &&
len(config.headerHashFilters) == 0 &&
len(config.headers) == 0 &&
len(config.methods) == 0 {
return nil
}
return &HTTPModifier{config: config}
}
func (m *HTTPModifier) Rewrite(payload []byte) (response []byte) {
if len(m.config.methods) > 0 && !m.config.methods.Contains(proto.Method(payload)) {
return
}
if m.config.urlRegexp.regexp != nil {
host, _, _, _ := proto.Header(payload, []byte("Host"))
fullPath := append(host, proto.Path(payload)...)
if !m.config.urlRegexp.regexp.Match(fullPath) {
return
}
}
if len(m.config.headerFilters) > 0 {
for _, f := range m.config.headerFilters {
value, s, _, _ := proto.Header(payload, f.name)
if s != -1 && !f.regexp.Match(value) {
return
}
}
}
if len(m.config.headerHashFilters) > 0 {
for _, f := range m.config.headerHashFilters {
value, s, _, _ := proto.Header(payload, f.name)
if s == -1 {
return
}
hasher := fnv.New32a()
hasher.Write(value)
if (hasher.Sum32() % 100) >= f.percent {
return
}
}
}
if len(m.config.urlRewrite) > 0 {
path := proto.Path(payload)
for _, f := range m.config.urlRewrite {
if f.src.Match(path) {
path = f.src.ReplaceAll(path, f.target)
payload = proto.SetPath(payload, path)
break
}
}
}
if len(m.config.headers) > 0 {
for _, header := range m.config.headers {
payload = proto.SetHeader(payload, []byte(header.Name), []byte(header.Value))
}
}
return payload
}