• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grpc / grpc-java / #20276

11 May 2026 08:24AM UTC coverage: 88.821% (-0.02%) from 88.838%
#20276

push

github

web-flow
Allow injecting bootstrap info into xDS Filter API for config parsing (#12724)

Extend the xDS Filter API to support injecting bootstrap information
into filters during configuration parsing. This allows filters to access
context information (e.g., allowed gRPC services) from the resource loading
layer during configuration validation and parsing.

- Update `Filter.Provider.parseFilterConfig` and
`parseFilterConfigOverride`
  to accept a `FilterContext` parameter.
- Introduce `BootstrapInfoGrpcServiceContextProvider` to encapsulate
  bootstrap info for context resolution.
- Update `XdsListenerResource` and `XdsRouteConfigureResource` to
  construct and pass `FilterContext` during configuration parsing.
- Update sub-filters (`FaultFilter`, `RbacFilter`,
`GcpAuthenticationFilter`,
  `RouterFilter`) to match the updated `FilterContext` signature.

Known Gaps & Limitations:
1. **MetricHolder**: Propagation of `MetricHolder` is not supported with
   this approach currently and is planned for support in a later phase.
2. **NameResolverRegistry**: Propagation is deferred for consistency.
While it could be passed from `XdsNameResolver` on the client side, there is
no equivalent mechanism on the server side. To ensure consistent
behavior, `DefaultRegistry` is used when validating schemes and creating channels.

36254 of 40817 relevant lines covered (88.82%)

0.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.0
/../xds/src/main/java/io/grpc/xds/Filter.java
1
/*
2
 * Copyright 2021 The gRPC Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package io.grpc.xds;
18

19

20
import com.google.auto.value.AutoValue;
21
import com.google.common.base.MoreObjects;
22
import com.google.protobuf.Message;
23
import io.grpc.ClientInterceptor;
24
import io.grpc.ServerInterceptor;
25
import io.grpc.xds.client.Bootstrapper.BootstrapInfo;
26
import io.grpc.xds.client.Bootstrapper.ServerInfo;
27
import java.io.Closeable;
28
import java.util.Objects;
29
import java.util.concurrent.ScheduledExecutorService;
30
import javax.annotation.Nullable;
31

32
/**
33
 * Defines the parsing functionality of an HTTP filter.
34
 *
35
 * <p>A Filter may optionally implement either {@link Filter#buildClientInterceptor} or
36
 * {@link Filter#buildServerInterceptor} or both, and return true from corresponding
37
 * {@link Provider#isClientFilter()}, {@link Provider#isServerFilter()} to indicate that the filter
38
 * is capable of working on the client side or server side or both, respectively.
39
 */
40
interface Filter extends Closeable {
41

42
  /** Represents an opaque data structure holding configuration for a filter. */
43
  interface FilterConfig {
44
    String typeUrl();
45
  }
46

47
  /**
48
   * Common interface for filter providers.
49
   */
50
  interface Provider {
51
    /**
52
     * The proto message types supported by this filter. A filter will be registered by each of its
53
     * supported message types.
54
     */
55
    String[] typeUrls();
56

57
    /**
58
     * Whether the filter can be installed on the client side.
59
     *
60
     * <p>Returns true if the filter implements {@link Filter#buildClientInterceptor}.
61
     */
62
    default boolean isClientFilter() {
63
      return false;
1✔
64
    }
65

66
    /**
67
     * Whether the filter can be installed into xDS-enabled servers.
68
     *
69
     * <p>Returns true if the filter implements {@link Filter#buildServerInterceptor}.
70
     */
71
    default boolean isServerFilter() {
72
      return false;
1✔
73
    }
74

75
    /**
76
     * Creates a new instance of the filter.
77
     *
78
     * <p>Returns a filter instance registered with the same typeUrls as the provider,
79
     * capable of working with the same FilterConfig type returned by provider's parse functions.
80
     *
81
     * <p>For xDS gRPC clients, new filter instances are created per combination of:
82
     * <ol>
83
     *   <li><code>XdsNameResolver</code> instance,</li>
84
     *   <li>Filter name+typeUrl in HttpConnectionManager (HCM) http_filters.</li>
85
     * </ol>
86
     *
87
     * <p>For xDS-enabled gRPC servers, new filter instances are created per combination of:
88
     * <ol>
89
     *   <li>Server instance,</li>
90
     *   <li>FilterChain name,</li>
91
     *   <li>Filter name+typeUrl in FilterChain's HCM.http_filters.</li>
92
     * </ol>
93
     */
94
    Filter newInstance(String name);
95

96
    /**
97
     * Parses the top-level filter config from raw proto message. The message may be either a {@link
98
     * com.google.protobuf.Any} or a {@link com.google.protobuf.Struct}.
99
     */
100
    ConfigOrError<? extends FilterConfig> parseFilterConfig(
101
        Message rawProtoMessage, FilterConfigParseContext context);
102

103
    /**
104
     * Parses the per-filter override filter config from raw proto message. The message may be
105
     * either a {@link com.google.protobuf.Any} or a {@link com.google.protobuf.Struct}.
106
     */
107
    ConfigOrError<? extends FilterConfig> parseFilterConfigOverride(
108
        Message rawProtoMessage, FilterConfigParseContext context);
109
  }
110

111
  /** Uses the FilterConfigs produced above to produce an HTTP filter interceptor for clients. */
112
  @Nullable
113
  default ClientInterceptor buildClientInterceptor(
114
      FilterConfig config, @Nullable FilterConfig overrideConfig,
115
      ScheduledExecutorService scheduler) {
116
    return null;
1✔
117
  }
118

119
  /** Uses the FilterConfigs produced above to produce an HTTP filter interceptor for the server. */
120
  @Nullable
121
  default ServerInterceptor buildServerInterceptor(
122
      FilterConfig config, @Nullable FilterConfig overrideConfig) {
123
    return null;
1✔
124
  }
125

126
  /**
127
   * Releases filter resources like shared resources and remote connections.
128
   *
129
   * <p>See {@link Provider#newInstance()} for details on filter instance creation.
130
   */
131
  @Override
132
  default void close() {}
1✔
133

134
  /** Context carrying dynamic metadata for a filter. */
135
  @AutoValue
136
  abstract static class FilterConfigParseContext {
1✔
137
    abstract BootstrapInfo bootstrapInfo();
138

139
    abstract ServerInfo serverInfo();
140

141
    static Builder builder() {
142
      return new AutoValue_Filter_FilterConfigParseContext.Builder();
1✔
143
    }
144

145
    @AutoValue.Builder
146
    abstract static class Builder {
1✔
147
      abstract Builder bootstrapInfo(BootstrapInfo info);
148

149
      abstract Builder serverInfo(ServerInfo info);
150

151
      abstract FilterConfigParseContext build();
152
    }
153
  }
154

155
  /** Filter config with instance name. */
156
  final class NamedFilterConfig {
157
    // filter instance name
158
    final String name;
159
    final FilterConfig filterConfig;
160

161
    NamedFilterConfig(String name, FilterConfig filterConfig) {
1✔
162
      this.name = name;
1✔
163
      this.filterConfig = filterConfig;
1✔
164
    }
1✔
165

166
    String filterStateKey() {
167
      return name + "_" + filterConfig.typeUrl();
1✔
168
    }
169

170
    @Override
171
    public boolean equals(Object o) {
172
      if (this == o) {
1✔
173
        return true;
×
174
      }
175
      if (o == null || getClass() != o.getClass()) {
1✔
176
        return false;
×
177
      }
178
      NamedFilterConfig that = (NamedFilterConfig) o;
1✔
179
      return Objects.equals(name, that.name)
1✔
180
          && Objects.equals(filterConfig, that.filterConfig);
1✔
181
    }
182

183
    @Override
184
    public int hashCode() {
185
      return Objects.hash(name, filterConfig);
1✔
186
    }
187

188
    @Override
189
    public String toString() {
190
      return MoreObjects.toStringHelper(this)
1✔
191
          .add("name", name)
1✔
192
          .add("filterConfig", filterConfig)
1✔
193
          .toString();
1✔
194
    }
195
  }
196
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc