Skip to content

Commit 5993e05

Browse files
authored
Add Limit (#119)
* Add Limit * Add Limit * fix e2e test * fix e2e test * fix e2e test * fix crd * e2e crd * e2e crd * e2e crd * merge * merge
1 parent 827236e commit 5993e05

File tree

9 files changed

+341
-392
lines changed

9 files changed

+341
-392
lines changed

pkg/apis/guard/v1alpha1/envelop.go

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ import (
2626

2727
// Exposes ValueProfile interface
2828
type EnvelopProfile struct {
29-
ResponseTime CountProfile `json:"responsetime"`
30-
CompletionTime CountProfile `json:"completiontime"`
29+
ResponseTime LimitProfile `json:"responsetime"`
30+
CompletionTime LimitProfile `json:"completiontime"`
3131
}
3232

3333
func (profile *EnvelopProfile) profileI(args ...interface{}) {
@@ -37,26 +37,18 @@ func (profile *EnvelopProfile) profileI(args ...interface{}) {
3737
func (profile *EnvelopProfile) Profile(reqTime time.Time, respTime time.Time, endTime time.Time) {
3838

3939
completionTime := endTime.Sub(reqTime).Seconds()
40-
if completionTime > 255 {
41-
profile.CompletionTime = 255
42-
} else {
43-
profile.CompletionTime = CountProfile(completionTime)
44-
}
40+
profile.CompletionTime.Profile(uint(completionTime))
4541

4642
responseTime := respTime.Sub(reqTime).Seconds()
47-
if responseTime > 255 {
48-
profile.ResponseTime = 255
49-
} else {
50-
profile.ResponseTime = CountProfile(responseTime)
51-
}
43+
profile.ResponseTime.Profile(uint(responseTime))
5244
}
5345

5446
//////////////////// EnvelopPile ////////////////
5547

5648
// Exposes ValuePile interface
5749
type EnvelopPile struct {
58-
ResponseTime CountPile `json:"responsetime"`
59-
CompletionTime CountPile `json:"completiontime"`
50+
ResponseTime LimitPile `json:"responsetime"`
51+
CompletionTime LimitPile `json:"completiontime"`
6052
}
6153

6254
func (pile *EnvelopPile) addI(valProfile ValueProfile) {
@@ -86,8 +78,8 @@ func (pile *EnvelopPile) Merge(otherPile *EnvelopPile) {
8678

8779
// Exposes ValueConfig interface
8880
type EnvelopConfig struct {
89-
ResponseTime CountConfig `json:"responsetime"`
90-
CompletionTime CountConfig `json:"completiontime"`
81+
ResponseTime LimitConfig `json:"responsetime"`
82+
CompletionTime LimitConfig `json:"completiontime"`
9183
}
9284

9385
func (config *EnvelopConfig) decideI(valProfile ValueProfile) *Decision {
@@ -115,8 +107,8 @@ func (config *EnvelopConfig) fuseI(otherValConfig ValueConfig) {
115107
}
116108

117109
func (config *EnvelopConfig) Fuse(otherConfig *EnvelopConfig) {
118-
config.CompletionTime.Fuse(otherConfig.CompletionTime)
119-
config.ResponseTime.Fuse(otherConfig.ResponseTime)
110+
config.CompletionTime.Fuse(&otherConfig.CompletionTime)
111+
config.ResponseTime.Fuse(&otherConfig.ResponseTime)
120112
}
121113

122114
func (config *EnvelopConfig) Prepare() {

pkg/apis/guard/v1alpha1/limit.go

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*
2+
Copyright 2022 The Knative Authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v1alpha1
18+
19+
//////////////////// LimitProfile ////////////////
20+
21+
// Exposes ValueProfile interface
22+
type LimitProfile uint8
23+
24+
func (profile *LimitProfile) profileI(args ...interface{}) {
25+
profile.Profile(args[0].(uint))
26+
}
27+
28+
// Exponentially represent uint up to ~1M using a uint8
29+
// For inputs > ~1M use 255
30+
// Exponential representation help stabilize the limits and avoid unnecessary alerts
31+
// For example 10 means 10, 20 means 24-25, 40 means 80-83 and 50 means 128-135, 80 means 496-527, etc.
32+
func (profile *LimitProfile) Profile(val uint) {
33+
v := val
34+
base := uint(0)
35+
36+
// batch 16, then 32, then 64, etc.
37+
for v >= 16 {
38+
base = base + 16
39+
v -= 16
40+
v = v >> 1
41+
}
42+
43+
res := v + base
44+
if res > 255 {
45+
res = 255
46+
}
47+
*profile = LimitProfile(res)
48+
}
49+
50+
//////////////////// LimitPile ////////////////
51+
52+
// Exposes ValuePile interface
53+
type LimitPile []uint8
54+
55+
func (pile *LimitPile) addI(valProfile ValueProfile) {
56+
pile.Add(*valProfile.(*LimitProfile))
57+
}
58+
59+
// profile is RO and unchanged - never uses profile internal objects
60+
func (pile *LimitPile) Add(profile LimitProfile) {
61+
*pile = append(*pile, uint8(profile))
62+
}
63+
64+
func (pile *LimitPile) Clear() {
65+
*pile = nil
66+
}
67+
68+
func (pile *LimitPile) mergeI(otherValPile ValuePile) {
69+
pile.Merge(*otherValPile.(*LimitPile))
70+
}
71+
72+
// otherPile is RO and unchanged - never uses otherPile internal objects
73+
func (pile *LimitPile) Merge(otherPile LimitPile) {
74+
*pile = append(*pile, otherPile...)
75+
}
76+
77+
// ////////////////// LimitConfig ////////////////
78+
79+
// Exposes ValueConfig interface
80+
type LimitConfig uint8
81+
82+
func (config *LimitConfig) decideI(valProfile ValueProfile) *Decision {
83+
return config.Decide(*valProfile.(*LimitProfile))
84+
}
85+
86+
// profile is RO and unchanged - never uses profile internal objects
87+
func (config *LimitConfig) Decide(profile LimitProfile) *Decision {
88+
var current *Decision
89+
90+
if uint8(profile) <= uint8(*config) { // found ok interval
91+
return nil
92+
}
93+
DecideInner(&current, 1, "Limit out of Range: %d", profile)
94+
return current
95+
}
96+
97+
func (config *LimitConfig) learnI(valPile ValuePile) {
98+
config.Learn(*valPile.(*LimitPile))
99+
}
100+
101+
// Learn now offers the simplest single rule support
102+
func (config *LimitConfig) Learn(pile LimitPile) {
103+
if len(pile) == 0 {
104+
return
105+
}
106+
107+
max := pile[0]
108+
for _, v := range pile {
109+
110+
if max < v {
111+
max = v
112+
}
113+
}
114+
115+
if max > uint8(*config) {
116+
(*config) = LimitConfig(max)
117+
}
118+
}
119+
120+
func (config *LimitConfig) fuseI(otherValConfig ValueConfig) {
121+
config.Fuse(otherValConfig.(*LimitConfig))
122+
}
123+
124+
func (config *LimitConfig) Fuse(otherConfig *LimitConfig) {
125+
126+
}
127+
128+
func (config *LimitConfig) Prepare() {
129+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
Copyright 2022 The Knative Authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v1alpha1
18+
19+
import (
20+
"testing"
21+
)
22+
23+
func TestLimit_V1(t *testing.T) {
24+
arguments := [][]uint{
25+
{4},
26+
{5},
27+
{9},
28+
{254},
29+
{255},
30+
{0},
31+
}
32+
var args []interface{}
33+
var profiles []ValueProfile
34+
var piles []ValuePile
35+
var configs []ValueConfig
36+
for i := 0; i < 10; i++ {
37+
profiles = append(profiles, new(LimitProfile))
38+
piles = append(piles, new(LimitPile))
39+
configs = append(configs, new(LimitConfig))
40+
}
41+
for i := 0; i < len(arguments); i++ {
42+
args = append(args, arguments[i])
43+
}
44+
45+
ValueTests_All(t, profiles, piles, configs, args...)
46+
}

pkg/apis/guard/v1alpha1/sessionData_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ func TestSessionData_Decide(t *testing.T) {
128128
reqData: "abc",
129129
reqTime: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
130130
},
131-
decision: "[Req:[MediaType:[Type:[Unexpected key none in Set,],],Method:[Unexpected key Post in Set,],Proto:[Unexpected key HTTP/1.1 in Set,],Url:[Segments:[Value 2 Not Allowed!,],Val:[Digits:[Value 1 Not Allowed!,],Letters:[Value 3 Not Allowed!,],Sequences:[Value 3 Not Allowed!,],Unicode Blocks:[Unexpected Flags in FlagSlice 400 on Element 0,],Unicodes:[Value 1 Not Allowed!,],],],],ReqBody:[Structured Body not allowed,],Resp:[MediaType:[Type:[Unexpected key none in Set,],],],RespBody:[Structured Body not allowed,],]",
131+
decision: "[Envelop:[CompletionTime:[Limit out of Range: 255,],ResponseTime:[Limit out of Range: 255,],],Req:[MediaType:[Type:[Unexpected key none in Set,],],Method:[Unexpected key Post in Set,],Proto:[Unexpected key HTTP/1.1 in Set,],Url:[Segments:[Value 2 Not Allowed!,],Val:[Digits:[Limit out of Range: 1,],Letters:[Limit out of Range: 3,],Sequences:[Limit out of Range: 3,],Unicode Blocks:[Unexpected Flags in FlagSlice 400 on Element 0,],Unicodes:[Limit out of Range: 1,],],],],ReqBody:[Structured Body not allowed,],Resp:[MediaType:[Type:[Unexpected key none in Set,],],],RespBody:[Structured Body not allowed,],]",
132132
},
133133
}
134134
for _, tt := range tests {

pkg/apis/guard/v1alpha1/simpleVal.go

Lines changed: 35 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,13 @@ const ( // sequence types
105105

106106
// Exposes ValueProfile interface
107107
type SimpleValProfile struct {
108-
Digits CountProfile
109-
Letters CountProfile
110-
Spaces CountProfile
111-
SpecialChars CountProfile
112-
NonReadables CountProfile
113-
Unicodes CountProfile
114-
Sequences CountProfile
108+
Digits LimitProfile
109+
Letters LimitProfile
110+
Spaces LimitProfile
111+
SpecialChars LimitProfile
112+
NonReadables LimitProfile
113+
Unicodes LimitProfile
114+
Sequences LimitProfile
115115
Flags AsciiFlagsProfile
116116
UnicodeFlags FlagSliceProfile
117117
}
@@ -202,38 +202,14 @@ func (profile *SimpleValProfile) Profile(str string) {
202202
seqPrevType = seqType
203203
}
204204
}
205-
if totalCounter > 0xFF {
206-
totalCounter = 0xFF
207-
if digitCounter > 0xFF {
208-
digitCounter = 0xFF
209-
}
210-
if letterCounter > 0xFF {
211-
letterCounter = 0xFF
212-
}
213-
if specialCharCounter > 0xFF {
214-
specialCharCounter = 0xFF
215-
}
216-
if unicodeCounter > 0xFF {
217-
unicodeCounter = 0xFF
218-
}
219-
if spaceCounter > 0xFF {
220-
spaceCounter = 0xFF
221-
}
222-
if nonReadableCounter > 0xFF {
223-
nonReadableCounter = 0xFF
224-
}
225-
if sequenceCounter > 0xFF {
226-
sequenceCounter = 0xFF
227-
}
228-
}
229205

230-
profile.Spaces.Profile(uint8(spaceCounter))
231-
profile.Unicodes.Profile(uint8(unicodeCounter))
232-
profile.NonReadables.Profile(uint8(nonReadableCounter))
233-
profile.Digits.Profile(uint8(digitCounter))
234-
profile.Letters.Profile(uint8(letterCounter))
235-
profile.SpecialChars.Profile(uint8(specialCharCounter))
236-
profile.Sequences.Profile(uint8(sequenceCounter))
206+
profile.Spaces.Profile(uint(spaceCounter))
207+
profile.Unicodes.Profile(uint(unicodeCounter))
208+
profile.NonReadables.Profile(uint(nonReadableCounter))
209+
profile.Digits.Profile(uint(digitCounter))
210+
profile.Letters.Profile(uint(letterCounter))
211+
profile.SpecialChars.Profile(uint(specialCharCounter))
212+
profile.Sequences.Profile(uint(sequenceCounter))
237213

238214
profile.Flags.Profile(flags)
239215
profile.UnicodeFlags.Profile(unicodeFlags)
@@ -243,13 +219,13 @@ func (profile *SimpleValProfile) Profile(str string) {
243219

244220
// Exposes ValuePile interface
245221
type SimpleValPile struct {
246-
Digits CountPile
247-
Letters CountPile
248-
Spaces CountPile
249-
SpecialChars CountPile
250-
NonReadables CountPile
251-
Unicodes CountPile
252-
Sequences CountPile
222+
Digits LimitPile
223+
Letters LimitPile
224+
Spaces LimitPile
225+
SpecialChars LimitPile
226+
NonReadables LimitPile
227+
Unicodes LimitPile
228+
Sequences LimitPile
253229
Flags AsciiFlagsPile
254230
UnicodeFlags FlagSlicePile
255231
}
@@ -302,13 +278,13 @@ func (pile *SimpleValPile) Clear() {
302278

303279
// Exposes ValueConfig interface
304280
type SimpleValConfig struct {
305-
Digits CountConfig `json:"digits"`
306-
Letters CountConfig `json:"letters"`
307-
Spaces CountConfig `json:"spaces"`
308-
SpecialChars CountConfig `json:"schars"`
309-
NonReadables CountConfig `json:"nonreadables"`
310-
Unicodes CountConfig `json:"unicodes"`
311-
Sequences CountConfig `json:"sequences"`
281+
Digits LimitConfig `json:"digits"`
282+
Letters LimitConfig `json:"letters"`
283+
Spaces LimitConfig `json:"spaces"`
284+
SpecialChars LimitConfig `json:"schars"`
285+
NonReadables LimitConfig `json:"nonreadables"`
286+
Unicodes LimitConfig `json:"unicodes"`
287+
Sequences LimitConfig `json:"sequences"`
312288
Flags AsciiFlagsConfig `json:"flags"`
313289
UnicodeFlags FlagSliceConfig `json:"unicodeFlags"`
314290
//Mandatory bool `json:"mandatory"`
@@ -334,13 +310,13 @@ func (config *SimpleValConfig) fuseI(otherValConfig ValueConfig) {
334310
}
335311

336312
func (config *SimpleValConfig) Fuse(otherConfig *SimpleValConfig) {
337-
config.Digits.Fuse(otherConfig.Digits)
338-
config.Letters.Fuse(otherConfig.Letters)
339-
config.Spaces.Fuse(otherConfig.Spaces)
340-
config.SpecialChars.Fuse(otherConfig.SpecialChars)
341-
config.NonReadables.Fuse(otherConfig.NonReadables)
342-
config.Unicodes.Fuse(otherConfig.Unicodes)
343-
config.Sequences.Fuse(otherConfig.Sequences)
313+
config.Digits.Fuse(&otherConfig.Digits)
314+
config.Letters.Fuse(&otherConfig.Letters)
315+
config.Spaces.Fuse(&otherConfig.Spaces)
316+
config.SpecialChars.Fuse(&otherConfig.SpecialChars)
317+
config.NonReadables.Fuse(&otherConfig.NonReadables)
318+
config.Unicodes.Fuse(&otherConfig.Unicodes)
319+
config.Sequences.Fuse(&otherConfig.Sequences)
344320
config.Flags.Fuse(otherConfig.Flags)
345321
config.UnicodeFlags.Fuse(otherConfig.UnicodeFlags)
346322
}

0 commit comments

Comments
 (0)