-
Notifications
You must be signed in to change notification settings - Fork 319
/
definition.go
172 lines (142 loc) · 5.15 KB
/
definition.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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package proxy
import (
"fmt"
"strconv"
"strings"
"time"
"github.com/asaskevich/govalidator"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/bsontype"
"github.com/hellofresh/janus/pkg/proxy/balancer"
"github.com/hellofresh/janus/pkg/router"
)
// Definition defines proxy rules for a route
type Definition struct {
PreserveHost bool `bson:"preserve_host" json:"preserve_host" mapstructure:"preserve_host"`
ListenPath string `bson:"listen_path" json:"listen_path" mapstructure:"listen_path" valid:"required~proxy.listen_path is required,urlpath"`
Upstreams *Upstreams `bson:"upstreams" json:"upstreams" mapstructure:"upstreams"`
InsecureSkipVerify bool `bson:"insecure_skip_verify" json:"insecure_skip_verify" mapstructure:"insecure_skip_verify"`
StripPath bool `bson:"strip_path" json:"strip_path" mapstructure:"strip_path"`
AppendPath bool `bson:"append_path" json:"append_path" mapstructure:"append_path"`
Methods []string `bson:"methods" json:"methods"`
Hosts []string `bson:"hosts" json:"hosts"`
ForwardingTimeouts ForwardingTimeouts `bson:"forwarding_timeouts" json:"forwarding_timeouts" mapstructure:"forwarding_timeouts"`
}
// RouterDefinition represents an API that you want to proxy with internal router routines
type RouterDefinition struct {
*Definition
middleware []router.Constructor
}
// Upstreams represents a collection of targets where the requests will go to
type Upstreams struct {
Balancing string `bson:"balancing" json:"balancing"`
Targets Targets `bson:"targets" json:"targets"`
}
// Target is an ip address/hostname with a port that identifies an instance of a backend service
type Target struct {
Target string `bson:"target" json:"target" valid:"url,required"`
Weight int `bson:"weight" json:"weight"`
}
// Targets is a set of target
type Targets []*Target
// Duration is the time.Duration that can be unmarshalled from JSON
type Duration time.Duration
// MarshalJSON implements marshalling from JSON
func (d *Duration) MarshalJSON() ([]byte, error) {
s := (*time.Duration)(d).String()
s = strconv.Quote(s)
return []byte(s), nil
}
// UnmarshalJSON implements unmarshalling from JSON
func (d *Duration) UnmarshalJSON(data []byte) (err error) {
s := string(data)
if s == "null" {
return
}
// if Unquote returns error - assume that string is not quoted at all
if sUnquoted, err := strconv.Unquote(s); err == nil {
s = sUnquoted
}
t, err := time.ParseDuration(s)
if err != nil {
return
}
*d = Duration(t)
return
}
// GetBSON implements marshalling to BSON
func (d Duration) GetBSON() (interface{}, error) {
return time.Duration(d).String(), nil
}
// SetBSON implements unmarshalling from BSON
func (d *Duration) SetBSON(raw bson.RawValue) error {
// took BSON string parsing logic from BSON decoder
if raw.Type != bsontype.String {
return fmt.Errorf("expected %q type, but got %q", bsontype.String.String(), raw.Type.String())
}
// l := d.readInt32()
b := raw.Value[0:4]
l := int32((uint32(b[0]) << 0) |
(uint32(b[1]) << 8) |
(uint32(b[2]) << 16) |
(uint32(b[3]) << 24))
// b := d.readBytes(l - 1)
b = raw.Value[4 : 4+l-1]
return d.UnmarshalJSON(b)
}
// ForwardingTimeouts contains timeout configurations for forwarding requests to the backend servers.
type ForwardingTimeouts struct {
DialTimeout Duration `bson:"dial_timeout" json:"dial_timeout"`
ResponseHeaderTimeout Duration `bson:"response_header_timeout" json:"response_header_timeout"`
}
// NewDefinition creates a new Proxy Definition with default values
func NewDefinition() *Definition {
return &Definition{
Methods: []string{"GET"},
Hosts: make([]string, 0),
Upstreams: &Upstreams{
Targets: make([]*Target, 0),
},
}
}
// NewRouterDefinition creates a new Proxy RouterDefinition from Proxy Definition
func NewRouterDefinition(def *Definition) *RouterDefinition {
return &RouterDefinition{Definition: def}
}
// Middleware returns s.middleware (useful for tests).
func (d *RouterDefinition) Middleware() []router.Constructor {
return d.middleware
}
// AddMiddleware adds a middleware to a site's middleware stack.
func (d *RouterDefinition) AddMiddleware(m router.Constructor) {
d.middleware = append(d.middleware, m)
}
// Validate validates proxy data
func (d *Definition) Validate() (bool, error) {
return govalidator.ValidateStruct(d)
}
// IsBalancerDefined checks if load balancer is defined
func (d *Definition) IsBalancerDefined() bool {
return d.Upstreams != nil && d.Upstreams.Targets != nil && len(d.Upstreams.Targets) > 0
}
// ToBalancerTargets returns the balancer expected type
func (t Targets) ToBalancerTargets() []*balancer.Target {
var balancerTargets []*balancer.Target
for _, t := range t {
balancerTargets = append(balancerTargets, &balancer.Target{
Target: t.Target,
Weight: t.Weight,
})
}
return balancerTargets
}
func init() {
// initializes custom validators
govalidator.CustomTypeTagMap.Set("urlpath", func(i interface{}, o interface{}) bool {
s, ok := i.(string)
if !ok {
return false
}
return strings.Index(s, "/") == 0
})
}