/
mod_header.go
132 lines (101 loc) · 3.35 KB
/
mod_header.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
package builtin
import (
"net/http"
"regexp"
"strings"
"github.com/zalando/skipper/filters"
)
type modRequestHeader struct {
headerName string
rx *regexp.Regexp
replacement string
}
// NewModRequestHeader returns a new filter Spec, whose instances execute
// regexp.ReplaceAllString on the request host. Instances expect three
// parameters: the header name, the expression to match and the replacement string.
// Name: "modRequestHeader".
func NewModRequestHeader() filters.Spec { return &modRequestHeader{} }
func (spec *modRequestHeader) Name() string {
return filters.ModRequestHeaderName
}
//lint:ignore ST1016 "spec" makes sense here and we reuse the type for the filter
func (spec *modRequestHeader) CreateFilter(config []interface{}) (filters.Filter, error) {
if len(config) != 3 {
return nil, filters.ErrInvalidFilterParameters
}
headerName, ok := config[0].(string)
if !ok {
return nil, filters.ErrInvalidFilterParameters
}
expr, ok := config[1].(string)
if !ok {
return nil, filters.ErrInvalidFilterParameters
}
replacement, ok := config[2].(string)
if !ok {
return nil, filters.ErrInvalidFilterParameters
}
rx, err := regexp.Compile(expr)
if err != nil {
return nil, err
}
return &modRequestHeader{headerName: headerName, rx: rx, replacement: replacement}, nil
}
func (f *modRequestHeader) Request(ctx filters.FilterContext) {
req := ctx.Request()
if strings.ToLower(f.headerName) == "host" {
nh := f.rx.ReplaceAllString(getRequestHost(req), f.replacement)
req.Header.Set(f.headerName, nh)
ctx.SetOutgoingHost(nh)
return
}
if _, ok := req.Header[http.CanonicalHeaderKey(f.headerName)]; !ok {
return
}
req.Header.Set(f.headerName, f.rx.ReplaceAllString(req.Header.Get(f.headerName), f.replacement))
}
func (*modRequestHeader) Response(filters.FilterContext) {}
type modResponseHeader struct {
headerName string
rx *regexp.Regexp
replacement string
}
// NewModResponseHeader returns a new filter Spec, whose instances execute
// regexp.ReplaceAllString on the request host. Instances expect three
// parameters: the header name, the expression to match and the replacement string.
// Name: "modResponseHeader".
func NewModResponseHeader() filters.Spec { return &modResponseHeader{} }
func (spec *modResponseHeader) Name() string {
return filters.ModResponseHeaderName
}
//lint:ignore ST1016 "spec" makes sense here and we reuse the type for the filter
func (spec *modResponseHeader) CreateFilter(config []interface{}) (filters.Filter, error) {
if len(config) != 3 {
return nil, filters.ErrInvalidFilterParameters
}
headerName, ok := config[0].(string)
if !ok {
return nil, filters.ErrInvalidFilterParameters
}
expr, ok := config[1].(string)
if !ok {
return nil, filters.ErrInvalidFilterParameters
}
replacement, ok := config[2].(string)
if !ok {
return nil, filters.ErrInvalidFilterParameters
}
rx, err := regexp.Compile(expr)
if err != nil {
return nil, err
}
return &modResponseHeader{headerName: headerName, rx: rx, replacement: replacement}, nil
}
func (*modResponseHeader) Request(filters.FilterContext) {}
func (f *modResponseHeader) Response(ctx filters.FilterContext) {
resp := ctx.Response()
if _, ok := resp.Header[http.CanonicalHeaderKey(f.headerName)]; !ok {
return
}
resp.Header.Set(f.headerName, f.rx.ReplaceAllString(resp.Header.Get(f.headerName), f.replacement))
}