Skip to content

Commit

Permalink
Support HTTPQueryParamMatch as CEL routeRuleConditions (#981)
Browse files Browse the repository at this point in the history
* Support HTTPQueryParamMatch as CEL routeRuleConditions

Signed-off-by: Alex Snaps <[email protected]>

* By default decodeQueryString will now ignore repeated params

Signed-off-by: Alex Snaps <[email protected]>

* By default queryMap will now ignore repeated params

Signed-off-by: Alex Snaps <[email protected]>

* Test for mapping `HTTPRouteMatch` to CEL Predicates

Signed-off-by: Alex Snaps <[email protected]>

---------

Signed-off-by: Alex Snaps <[email protected]>
  • Loading branch information
alexsnaps authored Nov 7, 2024
1 parent a925273 commit a46de69
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 3 deletions.
15 changes: 12 additions & 3 deletions pkg/wasm/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,14 @@ func PredicatesFromHTTPRouteMatch(match gatewayapiv1.HTTPRouteMatch) []string {
predicates = append(predicates, predicateFromHeader(headerMatch))
}

// TODO(eguzki): query params. Investigate integration with wasm regarding Envoy params
// from https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/advanced/attributes
// request.query -> string : The query portion of the URL in the format of “name1=value1&name2=value2”.
// query param, only consider the first in case of repetition, as per spec
queryParams := make(map[gatewayapiv1.HTTPHeaderName]bool)
for _, queryParamMatch := range match.QueryParams {
if !queryParams[queryParamMatch.Name] {
queryParams[queryParamMatch.Name] = true
predicates = append(predicates, predicateFromQueryParam(queryParamMatch))
}
}

return predicates
}
Expand Down Expand Up @@ -187,3 +192,7 @@ func predicateFromHeader(headerMatch gatewayapiv1.HTTPHeaderMatch) string {
// https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.HTTPHeaderMatch
return fmt.Sprintf("request.headers['%s'] == '%s'", headerMatch.Name, headerMatch.Value)
}

func predicateFromQueryParam(queryParam gatewayapiv1.HTTPQueryParamMatch) string {
return fmt.Sprintf("queryMap(request.query)['%s'] == '%s'", queryParam.Name, queryParam.Value)
}
51 changes: 51 additions & 0 deletions pkg/wasm/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import (
"errors"
"testing"

"gotest.tools/assert"

"github.com/google/go-cmp/cmp"
"google.golang.org/protobuf/types/known/structpb"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1"
"sigs.k8s.io/yaml"
)

Expand Down Expand Up @@ -248,3 +251,51 @@ func TestConfigFromStruct(t *testing.T) {
})
}
}

func TestPredicatesFromHTTPRouteMatch(t *testing.T) {
queryParams := make([]gatewayapiv1.HTTPQueryParamMatch, 0)
queryParamMatch := gatewayapiv1.QueryParamMatchExact
queryParams = append(queryParams, gatewayapiv1.HTTPQueryParamMatch{
Type: &queryParamMatch,
Name: "foo",
Value: "bar",
})
queryParams = append(queryParams, gatewayapiv1.HTTPQueryParamMatch{
Type: &queryParamMatch,
Name: "foo",
Value: "baz",
}) // this param will be ignored, as `foo` was defined above to match `bar`
queryParams = append(queryParams, gatewayapiv1.HTTPQueryParamMatch{
Type: &queryParamMatch,
Name: "kua",
Value: "drant",
})

headerMatch := gatewayapiv1.HeaderMatchExact
header := gatewayapiv1.HTTPHeaderMatch{
Type: &headerMatch,
Name: "x-auth",
Value: "kuadrant",
}

method := gatewayapiv1.HTTPMethodTrace

pathMatch := gatewayapiv1.PathMatchPathPrefix
path := "/admin"
predicates := PredicatesFromHTTPRouteMatch(gatewayapiv1.HTTPRouteMatch{
Path: &gatewayapiv1.HTTPPathMatch{
Type: &pathMatch,
Value: &path,
},
Headers: []gatewayapiv1.HTTPHeaderMatch{header},
QueryParams: queryParams,
Method: &method,
})

assert.Equal(t, predicates[0], "request.method == 'TRACE'")
assert.Equal(t, predicates[1], "request.url_path.startsWith('/admin')")
assert.Equal(t, predicates[2], "request.headers['x-auth'] == 'kuadrant'")
assert.Equal(t, predicates[3], "queryMap(request.query)['foo'] == 'bar'")
assert.Equal(t, predicates[4], "queryMap(request.query)['kua'] == 'drant'")
assert.Equal(t, len(predicates), 5)
}

0 comments on commit a46de69

Please sign in to comment.