mirror of
https://github.com/caddyserver/caddy.git
synced 2026-08-28 04:39:52 +00:00
reverseproxy: validate on weighted_round_robin loadbalancing policy (#7807)
Some checks failed
Tests / test (./cmd/caddy/caddy, ~1.26.0, macos-14, 0, 1.26, mac) (push) Has been cancelled
Tests / test (./cmd/caddy/caddy, ~1.26.0, ubuntu-latest, 0, 1.26, linux) (push) Has been cancelled
Tests / test (./cmd/caddy/caddy.exe, ~1.26.0, windows-latest, True, 1.26, windows) (push) Has been cancelled
Tests / test (s390x on IBM Z) (push) Has been cancelled
Tests / goreleaser-check (push) Has been cancelled
Cross-Build / build (~1.26.0, 1.26, aix) (push) Has been cancelled
Cross-Build / build (~1.26.0, 1.26, darwin) (push) Has been cancelled
Cross-Build / build (~1.26.0, 1.26, dragonfly) (push) Has been cancelled
Cross-Build / build (~1.26.0, 1.26, freebsd) (push) Has been cancelled
Cross-Build / build (~1.26.0, 1.26, illumos) (push) Has been cancelled
Cross-Build / build (~1.26.0, 1.26, linux) (push) Has been cancelled
Cross-Build / build (~1.26.0, 1.26, netbsd) (push) Has been cancelled
Cross-Build / build (~1.26.0, 1.26, openbsd) (push) Has been cancelled
Cross-Build / build (~1.26.0, 1.26, solaris) (push) Has been cancelled
Cross-Build / build (~1.26.0, 1.26, windows) (push) Has been cancelled
Lint / lint (push) Has been cancelled
Lint / lint-1 (push) Has been cancelled
Lint / lint-2 (push) Has been cancelled
Lint / govulncheck (push) Has been cancelled
Lint / dependency-review (push) Has been cancelled
OpenSSF Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
Some checks failed
Tests / test (./cmd/caddy/caddy, ~1.26.0, macos-14, 0, 1.26, mac) (push) Has been cancelled
Tests / test (./cmd/caddy/caddy, ~1.26.0, ubuntu-latest, 0, 1.26, linux) (push) Has been cancelled
Tests / test (./cmd/caddy/caddy.exe, ~1.26.0, windows-latest, True, 1.26, windows) (push) Has been cancelled
Tests / test (s390x on IBM Z) (push) Has been cancelled
Tests / goreleaser-check (push) Has been cancelled
Cross-Build / build (~1.26.0, 1.26, aix) (push) Has been cancelled
Cross-Build / build (~1.26.0, 1.26, darwin) (push) Has been cancelled
Cross-Build / build (~1.26.0, 1.26, dragonfly) (push) Has been cancelled
Cross-Build / build (~1.26.0, 1.26, freebsd) (push) Has been cancelled
Cross-Build / build (~1.26.0, 1.26, illumos) (push) Has been cancelled
Cross-Build / build (~1.26.0, 1.26, linux) (push) Has been cancelled
Cross-Build / build (~1.26.0, 1.26, netbsd) (push) Has been cancelled
Cross-Build / build (~1.26.0, 1.26, openbsd) (push) Has been cancelled
Cross-Build / build (~1.26.0, 1.26, solaris) (push) Has been cancelled
Cross-Build / build (~1.26.0, 1.26, windows) (push) Has been cancelled
Lint / lint (push) Has been cancelled
Lint / lint-1 (push) Has been cancelled
Lint / lint-2 (push) Has been cancelled
Lint / govulncheck (push) Has been cancelled
Lint / dependency-review (push) Has been cancelled
OpenSSF Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
* reverseproxy: validate on weighted_round_robin policy
Validate that weighted_round_robin has a non-zero total weight.
This prevents configurations such as:
weighted_round_robin 0 0
from being accepted and causing a divide-by-zero panic during request handling.
* test: validation test on zero weight upstreams.
* test: provision called instead of totalweight setting
* reverseproxy: validate on negative upstream weights
* test: regression test on weighted_round_robin selection policy
This commit is contained in:
parent
d3986f824d
commit
55b3397a2d
3 changed files with 123 additions and 5 deletions
|
|
@ -199,7 +199,7 @@ func TestReverseProxyWithPlaceholderDialAddress(t *testing.T) {
|
|||
],
|
||||
"handle": [
|
||||
{
|
||||
|
||||
|
||||
"handler": "reverse_proxy",
|
||||
"upstreams": [
|
||||
{
|
||||
|
|
@ -293,7 +293,7 @@ func TestReverseProxyWithPlaceholderTCPDialAddress(t *testing.T) {
|
|||
],
|
||||
"handle": [
|
||||
{
|
||||
|
||||
|
||||
"handler": "reverse_proxy",
|
||||
"upstreams": [
|
||||
{
|
||||
|
|
@ -374,7 +374,7 @@ func TestReverseProxyHealthCheck(t *testing.T) {
|
|||
http://localhost:9080 {
|
||||
reverse_proxy {
|
||||
to localhost:2020
|
||||
|
||||
|
||||
health_uri /health
|
||||
health_port 2021
|
||||
health_interval 10ms
|
||||
|
|
@ -495,7 +495,7 @@ func TestReverseProxyHealthCheckUnixSocket(t *testing.T) {
|
|||
http://localhost:9080 {
|
||||
reverse_proxy {
|
||||
to unix/%s
|
||||
|
||||
|
||||
health_uri /health
|
||||
health_port 2021
|
||||
health_interval 2s
|
||||
|
|
@ -553,7 +553,7 @@ func TestReverseProxyHealthCheckUnixSocketWithoutPort(t *testing.T) {
|
|||
http://localhost:9080 {
|
||||
reverse_proxy {
|
||||
to unix/%s
|
||||
|
||||
|
||||
health_uri /health
|
||||
health_interval 2s
|
||||
health_timeout 5s
|
||||
|
|
@ -831,3 +831,65 @@ func TestReverseProxySNIPlaceHolder(t *testing.T) {
|
|||
tester.AssertResponse(req, 200, "example.com")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWeightedRoundRobinSelectionValidation(t *testing.T) {
|
||||
configTemplate := `
|
||||
{
|
||||
"apps": {
|
||||
"http": {
|
||||
"servers": {
|
||||
"srv0": {
|
||||
"listen": [":18080"],
|
||||
"routes": [
|
||||
{
|
||||
"handle": [
|
||||
{
|
||||
"handler": "reverse_proxy",
|
||||
"load_balancing": {
|
||||
"selection_policy": {
|
||||
"policy": "weighted_round_robin",
|
||||
"weights": %s
|
||||
}
|
||||
},
|
||||
"upstreams": [
|
||||
{"dial": "localhost:18081"},
|
||||
{"dial": "localhost:18082"}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
weights string
|
||||
errMsg string
|
||||
}{
|
||||
{
|
||||
name: "negative weight",
|
||||
weights: "[-1, 2]",
|
||||
errMsg: "weight of an upstream cannot be negative",
|
||||
},
|
||||
{
|
||||
name: "zero total weight",
|
||||
weights: "[0, 0]",
|
||||
errMsg: "requires at least one upstream with a positive weight",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
caddytest.AssertLoadError(
|
||||
t,
|
||||
fmt.Sprintf(configTemplate, tc.weights),
|
||||
"json",
|
||||
tc.errMsg,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,6 +127,19 @@ func (r *WeightedRoundRobinSelection) Provision(ctx caddy.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Validate ensures that r's configuration is valid
|
||||
func (r *WeightedRoundRobinSelection) Validate() error {
|
||||
if r.totalWeight <= 0 {
|
||||
return fmt.Errorf("weighted_round_robin requires at least one upstream with a positive weight")
|
||||
}
|
||||
for _, weight := range r.Weights {
|
||||
if weight < 0 {
|
||||
return fmt.Errorf("weight of an upstream cannot be negative")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Select returns an available host, if any.
|
||||
func (r *WeightedRoundRobinSelection) Select(pool UpstreamPool, _ *http.Request, _ http.ResponseWriter) *Upstream {
|
||||
if len(pool) == 0 {
|
||||
|
|
@ -891,6 +904,7 @@ var (
|
|||
_ Selector = (*CookieHashSelection)(nil)
|
||||
|
||||
_ caddy.Validator = (*RandomChoiceSelection)(nil)
|
||||
_ caddy.Validator = (*WeightedRoundRobinSelection)(nil)
|
||||
|
||||
_ caddy.Provisioner = (*RandomChoiceSelection)(nil)
|
||||
_ caddy.Provisioner = (*WeightedRoundRobinSelection)(nil)
|
||||
|
|
|
|||
|
|
@ -131,6 +131,48 @@ func TestWeightedRoundRobinPolicy(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestWeightedRoundRobinSelection_Validate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
weights []int
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Valid 0 2 1 case",
|
||||
weights: []int{0, 2, 1},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Invalid 0 case (single)",
|
||||
weights: []int{0},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Invalid 0 0 case (multiple)",
|
||||
weights: []int{0, 0},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Valid weights",
|
||||
weights: []int{1, 1, 1},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := &WeightedRoundRobinSelection{
|
||||
Weights: tt.weights,
|
||||
}
|
||||
_ = s.Provision(caddy.Context{})
|
||||
err := s.Validate()
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWeightedRoundRobinPolicyWithZeroWeight(t *testing.T) {
|
||||
pool := testPool()
|
||||
wrrPolicy := WeightedRoundRobinSelection{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue