Skip to content

Commit

Permalink
sort HTTP filters
Browse files Browse the repository at this point in the history
Signed-off-by: huabing zhao <[email protected]>
  • Loading branch information
zhaohuabing committed Oct 20, 2023
1 parent 51517c5 commit e528962
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 13 deletions.
101 changes: 101 additions & 0 deletions internal/xds/translator/httpfilters.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright Envoy Gateway Authors
// SPDX-License-Identifier: Apache-2.0
// The full text of the Apache license is available in the LICENSE file at
// the root of the repo.

package translator

import (
"sort"

hcmv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
"github.com/envoyproxy/go-control-plane/pkg/wellknown"

"github.com/envoyproxy/gateway/internal/ir"
xdsfilters "github.com/envoyproxy/gateway/internal/xds/filters"
)

type OrderedHTTPFilter struct {
filter *hcmv3.HttpFilter
order int
}

type OrderedHTTPFilters []*OrderedHTTPFilter

func newOrderedHTTPFilter(filter *hcmv3.HttpFilter) *OrderedHTTPFilter {
order := 50

// Set a rational order for all the filters.
switch filter.Name {
case wellknown.CORS:
order = 1
case jwtAuthenFilter:
order = 2
case wellknown.HTTPRateLimit:
order = 3
case wellknown.Router:
order = 100
}

return &OrderedHTTPFilter{
filter: filter,
order: order,
}
}

// sort.Interface implementation.
func (o OrderedHTTPFilters) Len() int {
return len(o)
}

func (o OrderedHTTPFilters) Less(i, j int) bool {
return o[i].order < o[j].order
}

func (o OrderedHTTPFilters) Swap(i, j int) {
o[i], o[j] = o[j], o[i]
}

// sortHTTPFilters sorts the HTTP filters in the correct order.
// This is needed because the order of the filters is important.
// For example, the cors filter must be before the router filter.
// The router filter must be the last one.
func sortHTTPFilters(filters []*hcmv3.HttpFilter) []*hcmv3.HttpFilter {
orderedFilters := make(OrderedHTTPFilters, len(filters))
for i := 0; i < len(filters); i++ {
orderedFilters[i] = newOrderedHTTPFilter(filters[i])
}
sort.Sort(orderedFilters)

for i := 0; i < len(filters); i++ {
filters[i] = orderedFilters[i].filter
}
return filters
}

// patchHCMWithFilters builds and appends HTTP Filters to the HTTP connection
// manager.
func (t *Translator) patchHCMWithFilters(mgr *hcmv3.HttpConnectionManager, irListener *ir.HTTPListener) error {
// The order of filter patching is not relevant here.
// All the filters will be sorted in correct order after the patching is done.
// TODO: Make this a generic interface for all API Gateway features.
// https://github.com/envoyproxy/gateway/issues/882
t.patchHCMWithRateLimit(mgr, irListener)

// Add the jwt authn filter, if needed.
if err := patchHCMWithJwtAuthnFilter(mgr, irListener); err != nil {
return err
}

Check warning on line 88 in internal/xds/translator/httpfilters.go

View check run for this annotation

Codecov / codecov/patch

internal/xds/translator/httpfilters.go#L87-L88

Added lines #L87 - L88 were not covered by tests

// Add the cors filter, if needed
if err := patchHCMWithCorsFilter(mgr, irListener); err != nil {
return err
}

Check warning on line 93 in internal/xds/translator/httpfilters.go

View check run for this annotation

Codecov / codecov/patch

internal/xds/translator/httpfilters.go#L92-L93

Added lines #L92 - L93 were not covered by tests

// Add the router filter
mgr.HttpFilters = append(mgr.HttpFilters, xdsfilters.HTTPRouter)

// Sort the filters in the correct order.
mgr.HttpFilters = sortHTTPFilters(mgr.HttpFilters)
return nil
}
49 changes: 49 additions & 0 deletions internal/xds/translator/httpfilters_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright Envoy Gateway Authors
// SPDX-License-Identifier: Apache-2.0
// The full text of the Apache license is available in the LICENSE file at
// the root of the repo.

package translator

import (
"testing"

hcmv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
"github.com/envoyproxy/go-control-plane/pkg/wellknown"
"github.com/stretchr/testify/assert"
)

func Test_sortHTTPFilters(t *testing.T) {
tests := []struct {
name string
filters []*hcmv3.HttpFilter
want []*hcmv3.HttpFilter
}{
{
name: "sort filters",
filters: []*hcmv3.HttpFilter{
httpFilterForTest(wellknown.Router),
httpFilterForTest(wellknown.CORS),
httpFilterForTest(jwtAuthenFilter),
httpFilterForTest(wellknown.HTTPRateLimit),
},
want: []*hcmv3.HttpFilter{
httpFilterForTest(wellknown.CORS),
httpFilterForTest(jwtAuthenFilter),
httpFilterForTest(wellknown.HTTPRateLimit),
httpFilterForTest(wellknown.Router),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equalf(t, tt.want, sortHTTPFilters(tt.filters), "sortHTTPFilters(%v)", tt.filters)
})
}
}

func httpFilterForTest(name string) *hcmv3.HttpFilter {
return &hcmv3.HttpFilter{
Name: name,
}
}
16 changes: 3 additions & 13 deletions internal/xds/translator/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,22 +134,12 @@ func (t *Translator) addXdsHTTPFilterChain(xdsListener *listenerv3.Listener, irL
}
}

// TODO: Make this a generic interface for all API Gateway features.
// https://github.com/envoyproxy/gateway/issues/882
t.patchHCMWithRateLimit(mgr, irListener)

// Add the jwt authn filter, if needed.
if err := patchHCMWithJwtAuthnFilter(mgr, irListener); err != nil {
return err
}

// Add the cors filter, if needed
if err := patchHCMWithCorsFilter(mgr, irListener); err != nil {
// Add the HTTP filters to the HCM, the filters have been sorted in the
// correct order.
if err := t.patchHCMWithFilters(mgr, irListener); err != nil {
return err
}

// Make sure the router filter is the last one.
mgr.HttpFilters = append(mgr.HttpFilters, xdsfilters.HTTPRouter)
mgrAny, err := protocov.ToAnyWithError(mgr)
if err != nil {
return err
Expand Down

0 comments on commit e528962

Please sign in to comment.