Skip to content

Commit

Permalink
[API Gateway] Validate listener name is not empty (#16340)
Browse files Browse the repository at this point in the history
* [API Gateway] Validate listener name is not empty

* Update docstrings and test
  • Loading branch information
Andrew Stucki authored Feb 21, 2023
1 parent 8997f2b commit 7f9ec78
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 6 deletions.
11 changes: 8 additions & 3 deletions agent/structs/config_entry_gateways.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package structs

import (
"fmt"
"regexp"
"sort"
"strings"

Expand Down Expand Up @@ -778,9 +779,14 @@ func (e *APIGatewayConfigEntry) Validate() error {
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 {
listeners := make(map[string]struct{})
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 {
return fmt.Errorf("found multiple listeners with the name %q", listener.Name)
}
Expand Down Expand Up @@ -861,9 +867,8 @@ const (

// APIGatewayListener represents an individual listener for an APIGateway
type APIGatewayListener struct {
// Name is the optional name of the listener in a given gateway. This is
// optional but must be unique within a gateway; therefore, if a gateway
// has more than a single listener, all but one must specify a Name.
// Name is the name of the listener in a given gateway. This must be
// unique within a gateway.
Name string
// Hostname is the host name that a listener should be bound to. If
// unspecified, the listener accepts requests for all hostnames.
Expand Down
35 changes: 35 additions & 0 deletions agent/structs/config_entry_gateways_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1143,12 +1143,40 @@ func TestAPIGateway_Listeners(t *testing.T) {
},
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": {
entry: &APIGatewayConfigEntry{
Kind: "api-gateway",
Name: "api-gw-two",
Listeners: []APIGatewayListener{
{
Name: "listener-one",
Port: 80,
Protocol: ListenerProtocolHTTP,
},
Expand All @@ -1167,6 +1195,7 @@ func TestAPIGateway_Listeners(t *testing.T) {
Name: "api-gw-three",
Listeners: []APIGatewayListener{
{
Name: "listener",
Port: 80,
Hostname: "host.one",
},
Expand All @@ -1185,6 +1214,7 @@ func TestAPIGateway_Listeners(t *testing.T) {
Name: "api-gw-four",
Listeners: []APIGatewayListener{
{
Name: "listener",
Port: 80,
Hostname: "host.one",
Protocol: APIGatewayListenerProtocol("UDP"),
Expand All @@ -1199,6 +1229,7 @@ func TestAPIGateway_Listeners(t *testing.T) {
Name: "api-gw-five",
Listeners: []APIGatewayListener{
{
Name: "listener",
Port: 80,
Hostname: "host.one",
Protocol: APIGatewayListenerProtocol("tcp"),
Expand All @@ -1213,6 +1244,7 @@ func TestAPIGateway_Listeners(t *testing.T) {
Name: "api-gw-six",
Listeners: []APIGatewayListener{
{
Name: "listener",
Port: -1,
Protocol: APIGatewayListenerProtocol("tcp"),
},
Expand All @@ -1226,6 +1258,7 @@ func TestAPIGateway_Listeners(t *testing.T) {
Name: "api-gw-seven",
Listeners: []APIGatewayListener{
{
Name: "listener",
Port: 80,
Hostname: "*.*.host.one",
Protocol: APIGatewayListenerProtocol("http"),
Expand All @@ -1240,6 +1273,7 @@ func TestAPIGateway_Listeners(t *testing.T) {
Name: "api-gw-eight",
Listeners: []APIGatewayListener{
{
Name: "listener",
Port: 80,
Hostname: "host.one",
Protocol: APIGatewayListenerProtocol("http"),
Expand All @@ -1259,6 +1293,7 @@ func TestAPIGateway_Listeners(t *testing.T) {
Name: "api-gw-nine",
Listeners: []APIGatewayListener{
{
Name: "listener",
Port: 80,
Hostname: "host.one",
Protocol: APIGatewayListenerProtocol("http"),
Expand Down
5 changes: 2 additions & 3 deletions api/config_entry_gateways.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,9 +268,8 @@ func (g *APIGatewayConfigEntry) GetModifyIndex() uint64 { return g.ModifyInd

// APIGatewayListener represents an individual listener for an APIGateway
type APIGatewayListener struct {
// Name is the optional name of the listener in a given gateway. This is
// optional, however, it must be unique. Therefore, if a gateway has more
// than a single listener, all but one must specify a Name.
// Name is the name of the listener in a given gateway. This must be
// unique within a gateway.
Name string
// Hostname is the host name that a listener should be bound to, if
// unspecified, the listener accepts requests for all hostnames.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ listeners = [
{
port = 9999
protocol = "tcp"
name = "listener"
}
]
'
Expand Down

0 comments on commit 7f9ec78

Please sign in to comment.