Repository: envoyproxy/gateway

Issue:
Should `grpc_web` filter be in front of the `grpc_stats` ?
Should `grpc_web` filter be in front of the `grpc_stats` ?

_Originally posted by @zhaohuabing in https://github.com/envoyproxy/gateway/pull/6600#discussion_r2234433129_
            

Discussion:

Solution patch:
diff --git a/api/v1alpha1/envoyproxy_types.go b/api/v1alpha1/envoyproxy_types.go
index 20baa32df..af0c73702 100644
--- a/api/v1alpha1/envoyproxy_types.go
+++ b/api/v1alpha1/envoyproxy_types.go
@@ -272,6 +272,12 @@ const (
 	// EnvoyFilterRateLimit defines the Envoy HTTP rate limit filter.
 	EnvoyFilterRateLimit EnvoyFilter = "envoy.filters.http.ratelimit"
 
+	// EnvoyFilterGRPCWeb defines the Envoy HTTP gRPC-web filter.
+	EnvoyFilterGRPCWeb EnvoyFilter = "envoy.filters.http.grpc_web"
+
+	// EnvoyFilterGRPCStats defines the Envoy HTTP gRPC stats filter.
+	EnvoyFilterGRPCStats EnvoyFilter = "envoy.filters.http.grpc_stats"
+
 	// EnvoyFilterCustomResponse defines the Envoy HTTP custom response filter.
 	EnvoyFilterCustomResponse EnvoyFilter = "envoy.filters.http.custom_response"
 
diff --git a/internal/xds/translator/httpfilters.go b/internal/xds/translator/httpfilters.go
index a5e0a25c1..ff68e89d2 100644
--- a/internal/xds/translator/httpfilters.go
+++ b/internal/xds/translator/httpfilters.go
@@ -130,14 +130,18 @@ func newOrderedHTTPFilter(filter *hcmv3.HttpFilter) *OrderedHTTPFilter {
 		order = 302
 	case isFilterType(filter, egv1a1.EnvoyFilterRateLimit):
 		order = 303
-	case isFilterType(filter, egv1a1.EnvoyFilterCustomResponse):
+	case isFilterType(filter, egv1a1.EnvoyFilterGRPCWeb):
 		order = 304
-	case isFilterType(filter, egv1a1.EnvoyFilterCredentialInjector):
+	case isFilterType(filter, egv1a1.EnvoyFilterGRPCStats):
 		order = 305
-	case isFilterType(filter, egv1a1.EnvoyFilterCompressor):
+	case isFilterType(filter, egv1a1.EnvoyFilterCustomResponse):
 		order = 306
-	case isFilterType(filter, egv1a1.EnvoyFilterRouter):
+	case isFilterType(filter, egv1a1.EnvoyFilterCredentialInjector):
 		order = 307
+	case isFilterType(filter, egv1a1.EnvoyFilterCompressor):
+		order = 308
+	case isFilterType(filter, egv1a1.EnvoyFilterRouter):
+		order = 309
 	}
 
 	return &OrderedHTTPFilter{



Test patch:
diff --git a/internal/cmd/egctl/testdata/translate/out/default-resources.all.yaml b/internal/cmd/egctl/testdata/translate/out/default-resources.all.yaml
index 997bb75a1..cec182525 100644
--- a/internal/cmd/egctl/testdata/translate/out/default-resources.all.yaml
+++ b/internal/cmd/egctl/testdata/translate/out/default-resources.all.yaml
@@ -1214,14 +1214,14 @@ xds:
                     initialStreamWindowSize: 65536
                     maxConcurrentStreams: 100
                   httpFilters:
+                  - name: envoy.filters.http.grpc_web
+                    typedConfig:
+                      '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
                   - name: envoy.filters.http.grpc_stats
                     typedConfig:
                       '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_stats.v3.FilterConfig
                       emitFilterState: true
                       statsForAllMethods: true
-                  - name: envoy.filters.http.grpc_web
-                    typedConfig:
-                      '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
                   - name: envoy.filters.http.router
                     typedConfig:
                       '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
diff --git a/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.all.json b/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.all.json
index b31e8aed5..84d717494 100644
--- a/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.all.json
+++ b/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.all.json
@@ -1090,17 +1090,17 @@
                           },
                           "httpFilters": [
                             {
-                              "name": "envoy.filters.http.grpc_stats",
+                              "name": "envoy.filters.http.grpc_web",
                               "typedConfig": {
-                                "@type": "type.googleapis.com/envoy.extensions.filters.http.grpc_stats.v3.FilterConfig",
-                                "emitFilterState": true,
-                                "statsForAllMethods": true
+                                "@type": "type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb"
                               }
                             },
                             {
-                              "name": "envoy.filters.http.grpc_web",
+                              "name": "envoy.filters.http.grpc_stats",
                               "typedConfig": {
-                                "@type": "type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb"
+                                "@type": "type.googleapis.com/envoy.extensions.filters.http.grpc_stats.v3.FilterConfig",
+                                "emitFilterState": true,
+                                "statsForAllMethods": true
                               }
                             },
                             {
diff --git a/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.all.yaml b/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.all.yaml
index b6467311e..2bf22747e 100644
--- a/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.all.yaml
+++ b/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.all.yaml
@@ -667,14 +667,14 @@ xds:
                     initialStreamWindowSize: 65536
                     maxConcurrentStreams: 100
                   httpFilters:
+                  - name: envoy.filters.http.grpc_web
+                    typedConfig:
+                      '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
                   - name: envoy.filters.http.grpc_stats
                     typedConfig:
                       '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_stats.v3.FilterConfig
                       emitFilterState: true
                       statsForAllMethods: true
-                  - name: envoy.filters.http.grpc_web
-                    typedConfig:
-                      '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
                   - name: envoy.filters.http.router
                     typedConfig:
                       '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
diff --git a/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.listener.yaml b/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.listener.yaml
index 1c8fba4d1..c0fa7da7c 100644
--- a/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.listener.yaml
+++ b/internal/cmd/egctl/testdata/translate/out/from-gateway-api-to-xds.listener.yaml
@@ -230,14 +230,14 @@ xds:
                   initialStreamWindowSize: 65536
                   maxConcurrentStreams: 100
                 httpFilters:
+                - name: envoy.filters.http.grpc_web
+                  typedConfig:
+                    '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
                 - name: envoy.filters.http.grpc_stats
                   typedConfig:
                     '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_stats.v3.FilterConfig
                     emitFilterState: true
                     statsForAllMethods: true
-                - name: envoy.filters.http.grpc_web
-                  typedConfig:
-                    '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
                 - name: envoy.filters.http.router
                   typedConfig:
                     '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
diff --git a/internal/xds/translator/testdata/out/xds-ir/dns-lookup-family.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/dns-lookup-family.listeners.yaml
index c5fb9a58f..584a9f8d6 100644
--- a/internal/xds/translator/testdata/out/xds-ir/dns-lookup-family.listeners.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/dns-lookup-family.listeners.yaml
@@ -138,14 +138,6 @@
             transportApiVersion: V3
             withRequestBody:
               maxRequestBytes: 8192
-        - name: envoy.filters.http.grpc_stats
-          typedConfig:
-            '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_stats.v3.FilterConfig
-            emitFilterState: true
-            statsForAllMethods: true
-        - name: envoy.filters.http.grpc_web
-          typedConfig:
-            '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
         - disabled: true
           name: envoy.filters.http.ext_proc/envoyextensionpolicy/default/policy-for-httproute/extproc/0
           typedConfig:
@@ -160,6 +152,14 @@
               requestTrailerMode: SKIP
               responseHeaderMode: SKIP
               responseTrailerMode: SKIP
+        - name: envoy.filters.http.grpc_web
+          typedConfig:
+            '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
+        - name: envoy.filters.http.grpc_stats
+          typedConfig:
+            '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_stats.v3.FilterConfig
+            emitFilterState: true
+            statsForAllMethods: true
         - name: envoy.filters.http.router
           typedConfig:
             '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
diff --git a/internal/xds/translator/testdata/out/xds-ir/http2-route.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/http2-route.listeners.yaml
index 2a7c6641a..b2e4d2fb2 100644
--- a/internal/xds/translator/testdata/out/xds-ir/http2-route.listeners.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/http2-route.listeners.yaml
@@ -14,14 +14,14 @@
           initialStreamWindowSize: 65536
           maxConcurrentStreams: 100
         httpFilters:
+        - name: envoy.filters.http.grpc_web
+          typedConfig:
+            '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
         - name: envoy.filters.http.grpc_stats
           typedConfig:
             '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_stats.v3.FilterConfig
             emitFilterState: true
             statsForAllMethods: true
-        - name: envoy.filters.http.grpc_web
-          typedConfig:
-            '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
         - name: envoy.filters.http.router
           typedConfig:
             '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md
index 0aa4d2f41..768198ef9 100644
--- a/site/content/en/latest/api/extension_types.md
+++ b/site/content/en/latest/api/extension_types.md
@@ -1224,6 +1224,8 @@ _Appears in:_
 | `envoy.filters.http.rbac` | EnvoyFilterRBAC defines the Envoy RBAC filter.<br /> | 
 | `envoy.filters.http.local_ratelimit` | EnvoyFilterLocalRateLimit defines the Envoy HTTP local rate limit filter.<br /> | 
 | `envoy.filters.http.ratelimit` | EnvoyFilterRateLimit defines the Envoy HTTP rate limit filter.<br /> | 
+| `envoy.filters.http.grpc_web` | EnvoyFilterGRPCWeb defines the Envoy HTTP gRPC-web filter.<br /> | 
+| `envoy.filters.http.grpc_stats` | EnvoyFilterGRPCStats defines the Envoy HTTP gRPC stats filter.<br /> | 
 | `envoy.filters.http.custom_response` | EnvoyFilterCustomResponse defines the Envoy HTTP custom response filter.<br /> | 
 | `envoy.filters.http.credential_injector` | EnvoyFilterCredentialInjector defines the Envoy HTTP credential injector filter.<br /> | 
 | `envoy.filters.http.compressor` | EnvoyFilterCompressor defines the Envoy HTTP compressor filter.<br /> |