[API Gateway] Validate listener name is not empty (#16340)

* [API Gateway] Validate listener name is not empty

* Update docstrings and test
This commit is contained in:
Andrew Stucki 2023-02-21 14:12:19 -05:00 committed by GitHub
parent 8997f2bff1
commit 7f9ec78932
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 46 additions and 6 deletions

View File

@ -2,6 +2,7 @@ package structs
import ( import (
"fmt" "fmt"
"regexp"
"sort" "sort"
"strings" "strings"
@ -778,9 +779,14 @@ func (e *APIGatewayConfigEntry) Validate() error {
return e.validateListeners() return e.validateListeners()
} }
var listenerNameRegex = regexp.MustCompile(`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`)
func (e *APIGatewayConfigEntry) validateListenerNames() error { func (e *APIGatewayConfigEntry) validateListenerNames() error {
listeners := make(map[string]struct{}) listeners := make(map[string]struct{})
for _, listener := range e.Listeners { for _, listener := range e.Listeners {
if len(listener.Name) < 1 || !listenerNameRegex.MatchString(listener.Name) {
return fmt.Errorf("listener name %q is invalid, must be at least 1 character and contain only letters, numbers, or dashes", listener.Name)
}
if _, found := listeners[listener.Name]; found { if _, found := listeners[listener.Name]; found {
return fmt.Errorf("found multiple listeners with the name %q", listener.Name) return fmt.Errorf("found multiple listeners with the name %q", listener.Name)
} }
@ -861,9 +867,8 @@ const (
// APIGatewayListener represents an individual listener for an APIGateway // APIGatewayListener represents an individual listener for an APIGateway
type APIGatewayListener struct { type APIGatewayListener struct {
// Name is the optional name of the listener in a given gateway. This is // Name is the name of the listener in a given gateway. This must be
// optional but must be unique within a gateway; therefore, if a gateway // unique within a gateway.
// has more than a single listener, all but one must specify a Name.
Name string Name string
// Hostname is the host name that a listener should be bound to. If // Hostname is the host name that a listener should be bound to. If
// unspecified, the listener accepts requests for all hostnames. // unspecified, the listener accepts requests for all hostnames.

View File

@ -1143,12 +1143,40 @@ func TestAPIGateway_Listeners(t *testing.T) {
}, },
validateErr: "multiple listeners with the name", validateErr: "multiple listeners with the name",
}, },
"empty listener name": {
entry: &APIGatewayConfigEntry{
Kind: "api-gateway",
Name: "api-gw-one",
Listeners: []APIGatewayListener{
{
Port: 80,
Protocol: "tcp",
},
},
},
validateErr: "listener name \"\" is invalid, must be at least 1 character and contain only letters, numbers, or dashes",
},
"invalid listener name": {
entry: &APIGatewayConfigEntry{
Kind: "api-gateway",
Name: "api-gw-one",
Listeners: []APIGatewayListener{
{
Port: 80,
Protocol: "tcp",
Name: "/",
},
},
},
validateErr: "listener name \"/\" is invalid, must be at least 1 character and contain only letters, numbers, or dashes",
},
"merged listener protocol conflict": { "merged listener protocol conflict": {
entry: &APIGatewayConfigEntry{ entry: &APIGatewayConfigEntry{
Kind: "api-gateway", Kind: "api-gateway",
Name: "api-gw-two", Name: "api-gw-two",
Listeners: []APIGatewayListener{ Listeners: []APIGatewayListener{
{ {
Name: "listener-one",
Port: 80, Port: 80,
Protocol: ListenerProtocolHTTP, Protocol: ListenerProtocolHTTP,
}, },
@ -1167,6 +1195,7 @@ func TestAPIGateway_Listeners(t *testing.T) {
Name: "api-gw-three", Name: "api-gw-three",
Listeners: []APIGatewayListener{ Listeners: []APIGatewayListener{
{ {
Name: "listener",
Port: 80, Port: 80,
Hostname: "host.one", Hostname: "host.one",
}, },
@ -1185,6 +1214,7 @@ func TestAPIGateway_Listeners(t *testing.T) {
Name: "api-gw-four", Name: "api-gw-four",
Listeners: []APIGatewayListener{ Listeners: []APIGatewayListener{
{ {
Name: "listener",
Port: 80, Port: 80,
Hostname: "host.one", Hostname: "host.one",
Protocol: APIGatewayListenerProtocol("UDP"), Protocol: APIGatewayListenerProtocol("UDP"),
@ -1199,6 +1229,7 @@ func TestAPIGateway_Listeners(t *testing.T) {
Name: "api-gw-five", Name: "api-gw-five",
Listeners: []APIGatewayListener{ Listeners: []APIGatewayListener{
{ {
Name: "listener",
Port: 80, Port: 80,
Hostname: "host.one", Hostname: "host.one",
Protocol: APIGatewayListenerProtocol("tcp"), Protocol: APIGatewayListenerProtocol("tcp"),
@ -1213,6 +1244,7 @@ func TestAPIGateway_Listeners(t *testing.T) {
Name: "api-gw-six", Name: "api-gw-six",
Listeners: []APIGatewayListener{ Listeners: []APIGatewayListener{
{ {
Name: "listener",
Port: -1, Port: -1,
Protocol: APIGatewayListenerProtocol("tcp"), Protocol: APIGatewayListenerProtocol("tcp"),
}, },
@ -1226,6 +1258,7 @@ func TestAPIGateway_Listeners(t *testing.T) {
Name: "api-gw-seven", Name: "api-gw-seven",
Listeners: []APIGatewayListener{ Listeners: []APIGatewayListener{
{ {
Name: "listener",
Port: 80, Port: 80,
Hostname: "*.*.host.one", Hostname: "*.*.host.one",
Protocol: APIGatewayListenerProtocol("http"), Protocol: APIGatewayListenerProtocol("http"),
@ -1240,6 +1273,7 @@ func TestAPIGateway_Listeners(t *testing.T) {
Name: "api-gw-eight", Name: "api-gw-eight",
Listeners: []APIGatewayListener{ Listeners: []APIGatewayListener{
{ {
Name: "listener",
Port: 80, Port: 80,
Hostname: "host.one", Hostname: "host.one",
Protocol: APIGatewayListenerProtocol("http"), Protocol: APIGatewayListenerProtocol("http"),
@ -1259,6 +1293,7 @@ func TestAPIGateway_Listeners(t *testing.T) {
Name: "api-gw-nine", Name: "api-gw-nine",
Listeners: []APIGatewayListener{ Listeners: []APIGatewayListener{
{ {
Name: "listener",
Port: 80, Port: 80,
Hostname: "host.one", Hostname: "host.one",
Protocol: APIGatewayListenerProtocol("http"), Protocol: APIGatewayListenerProtocol("http"),

View File

@ -268,9 +268,8 @@ func (g *APIGatewayConfigEntry) GetModifyIndex() uint64 { return g.ModifyInd
// APIGatewayListener represents an individual listener for an APIGateway // APIGatewayListener represents an individual listener for an APIGateway
type APIGatewayListener struct { type APIGatewayListener struct {
// Name is the optional name of the listener in a given gateway. This is // Name is the name of the listener in a given gateway. This must be
// optional, however, it must be unique. Therefore, if a gateway has more // unique within a gateway.
// than a single listener, all but one must specify a Name.
Name string Name string
// Hostname is the host name that a listener should be bound to, if // Hostname is the host name that a listener should be bound to, if
// unspecified, the listener accepts requests for all hostnames. // unspecified, the listener accepts requests for all hostnames.

View File

@ -9,6 +9,7 @@ listeners = [
{ {
port = 9999 port = 9999
protocol = "tcp" protocol = "tcp"
name = "listener"
} }
] ]
' '