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

grpc / grpc-java / #19762

03 Apr 2025 05:52AM UTC coverage: 88.598% (-0.005%) from 88.603%
#19762

push

github

web-flow
xds: listener type validation (#11933)

34732 of 39202 relevant lines covered (88.6%)

0.89 hits per line

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

92.86
/../xds/src/main/java/io/grpc/xds/EnvoyServerProtoData.java
1
/*
2
 * Copyright 2020 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
import static com.google.common.base.Preconditions.checkNotNull;
20

21
import com.google.auto.value.AutoValue;
22
import com.google.common.annotations.VisibleForTesting;
23
import com.google.common.collect.ImmutableList;
24
import com.google.protobuf.util.Durations;
25
import io.envoyproxy.envoy.config.core.v3.SocketAddress.Protocol;
26
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext;
27
import io.grpc.Internal;
28
import io.grpc.xds.client.EnvoyProtoData;
29
import io.grpc.xds.internal.security.SslContextProviderSupplier;
30
import java.net.InetAddress;
31
import java.util.Objects;
32
import javax.annotation.Nullable;
33

34
/**
35
 * Defines gRPC data types for Envoy protobuf messages used in xDS protocol on the server side,
36
 * similar to how {@link EnvoyProtoData} defines it for the client side.
37
 */
38
@Internal
39
public final class EnvoyServerProtoData {
40

41
  // Prevent instantiation.
42
  private EnvoyServerProtoData() {
43
  }
44

45
  public abstract static class BaseTlsContext {
46
    protected final CommonTlsContext commonTlsContext;
47

48
    protected BaseTlsContext(CommonTlsContext commonTlsContext) {
1✔
49
      this.commonTlsContext = checkNotNull(commonTlsContext, "commonTlsContext cannot be null.");
1✔
50
    }
1✔
51

52
    public CommonTlsContext getCommonTlsContext() {
53
      return commonTlsContext;
1✔
54
    }
55

56
    @Override
57
    public boolean equals(Object o) {
58
      if (this == o) {
1✔
59
        return true;
×
60
      }
61
      if (!(o instanceof BaseTlsContext)) {
1✔
62
        return false;
1✔
63
      }
64
      BaseTlsContext that = (BaseTlsContext) o;
1✔
65
      return Objects.equals(commonTlsContext, that.commonTlsContext);
1✔
66
    }
67

68
    @Override
69
    public int hashCode() {
70
      return Objects.hashCode(commonTlsContext);
1✔
71
    }
72
  }
73

74
  public static final class UpstreamTlsContext extends BaseTlsContext {
75

76
    @VisibleForTesting
77
    public UpstreamTlsContext(CommonTlsContext commonTlsContext) {
78
      super(commonTlsContext);
1✔
79
    }
1✔
80

81
    public static UpstreamTlsContext fromEnvoyProtoUpstreamTlsContext(
82
        io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
83
            upstreamTlsContext) {
84
      return new UpstreamTlsContext(upstreamTlsContext.getCommonTlsContext());
1✔
85
    }
86

87
    @Override
88
    public String toString() {
89
      return "UpstreamTlsContext{" + "commonTlsContext=" + commonTlsContext + '}';
1✔
90
    }
91
  }
92

93
  public static final class DownstreamTlsContext extends BaseTlsContext {
94

95
    private final boolean requireClientCertificate;
96

97
    @VisibleForTesting
98
    public DownstreamTlsContext(
99
        CommonTlsContext commonTlsContext, boolean requireClientCertificate) {
100
      super(commonTlsContext);
1✔
101
      this.requireClientCertificate = requireClientCertificate;
1✔
102
    }
1✔
103

104
    public static DownstreamTlsContext fromEnvoyProtoDownstreamTlsContext(
105
        io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
106
            downstreamTlsContext) {
107
      return new DownstreamTlsContext(downstreamTlsContext.getCommonTlsContext(),
1✔
108
        downstreamTlsContext.hasRequireClientCertificate());
1✔
109
    }
110

111
    public boolean isRequireClientCertificate() {
112
      return requireClientCertificate;
1✔
113
    }
114

115
    @Override
116
    public String toString() {
117
      return "DownstreamTlsContext{"
×
118
          + "commonTlsContext="
119
          + commonTlsContext
120
          + ", requireClientCertificate="
121
          + requireClientCertificate
122
          + '}';
123
    }
124

125
    @Override
126
    public boolean equals(Object o) {
127
      if (this == o) {
1✔
128
        return true;
×
129
      }
130
      if (o == null || getClass() != o.getClass()) {
1✔
131
        return false;
×
132
      }
133
      if (!super.equals(o)) {
1✔
134
        return false;
1✔
135
      }
136
      DownstreamTlsContext that = (DownstreamTlsContext) o;
1✔
137
      return requireClientCertificate == that.requireClientCertificate;
1✔
138
    }
139

140
    @Override
141
    public int hashCode() {
142
      return Objects.hash(super.hashCode(), requireClientCertificate);
1✔
143
    }
144
  }
145

146
  @AutoValue
147
  abstract static class CidrRange {
1✔
148

149
    abstract InetAddress addressPrefix();
150

151
    abstract int prefixLen();
152

153
    static CidrRange create(InetAddress addressPrefix, int prefixLen) {
154
      return new AutoValue_EnvoyServerProtoData_CidrRange(
1✔
155
          addressPrefix, prefixLen);
156
    }
157
  }
158

159
  enum ConnectionSourceType {
1✔
160
    // Any connection source matches.
161
    ANY,
1✔
162

163
    // Match a connection originating from the same host.
164
    SAME_IP_OR_LOOPBACK,
1✔
165

166
    // Match a connection originating from a different host.
167
    EXTERNAL
1✔
168
  }
169

170
  /**
171
   * Corresponds to Envoy proto message
172
   * {@link io.envoyproxy.envoy.config.listener.v3.FilterChainMatch}.
173
   */
174
  @AutoValue
175
  abstract static class FilterChainMatch {
1✔
176

177
    abstract int destinationPort();
178

179
    abstract ImmutableList<CidrRange> prefixRanges();
180

181
    abstract ImmutableList<String> applicationProtocols();
182

183
    abstract ImmutableList<CidrRange> sourcePrefixRanges();
184

185
    abstract ConnectionSourceType connectionSourceType();
186

187
    abstract ImmutableList<Integer> sourcePorts();
188

189
    abstract ImmutableList<String> serverNames();
190

191
    abstract String transportProtocol();
192

193
    public static FilterChainMatch create(int destinationPort,
194
        ImmutableList<CidrRange> prefixRanges,
195
        ImmutableList<String> applicationProtocols, ImmutableList<CidrRange> sourcePrefixRanges,
196
        ConnectionSourceType connectionSourceType, ImmutableList<Integer> sourcePorts,
197
        ImmutableList<String> serverNames, String transportProtocol) {
198
      return new AutoValue_EnvoyServerProtoData_FilterChainMatch(
1✔
199
          destinationPort, prefixRanges, applicationProtocols, sourcePrefixRanges,
200
          connectionSourceType, sourcePorts, serverNames, transportProtocol);
201
    }
202
  }
203

204
  /**
205
   * Corresponds to Envoy proto message {@link io.envoyproxy.envoy.config.listener.v3.FilterChain}.
206
   */
207
  @AutoValue
208
  abstract static class FilterChain {
1✔
209

210
    // Must be unique per server instance (except the default chain).
211
    abstract String name();
212

213
    // TODO(sanjaypujare): flatten structure by moving FilterChainMatch class members here.
214
    abstract FilterChainMatch filterChainMatch();
215

216
    abstract HttpConnectionManager httpConnectionManager();
217

218
    @Nullable
219
    abstract SslContextProviderSupplier sslContextProviderSupplier();
220

221
    static FilterChain create(
222
        String name,
223
        FilterChainMatch filterChainMatch,
224
        HttpConnectionManager httpConnectionManager,
225
        @Nullable DownstreamTlsContext downstreamTlsContext,
226
        TlsContextManager tlsContextManager) {
227
      SslContextProviderSupplier sslContextProviderSupplier =
228
          downstreamTlsContext == null
1✔
229
              ? null : new SslContextProviderSupplier(downstreamTlsContext, tlsContextManager);
1✔
230
      return new AutoValue_EnvoyServerProtoData_FilterChain(
1✔
231
          name, filterChainMatch, httpConnectionManager, sslContextProviderSupplier);
232
    }
233
  }
234

235
  /**
236
   * Corresponds to Envoy proto message {@link io.envoyproxy.envoy.config.listener.v3.Listener} and
237
   * related classes.
238
   */
239
  @AutoValue
240
  abstract static class Listener {
1✔
241

242
    abstract String name();
243

244
    @Nullable
245
    abstract String address();
246

247
    abstract ImmutableList<FilterChain> filterChains();
248

249
    @Nullable
250
    abstract FilterChain defaultFilterChain();
251

252
    @Nullable
253
    abstract Protocol protocol();
254

255
    static Listener create(
256
        String name,
257
        @Nullable String address,
258
        ImmutableList<FilterChain> filterChains,
259
        @Nullable FilterChain defaultFilterChain,
260
        @Nullable Protocol protocol) {
261
      return new AutoValue_EnvoyServerProtoData_Listener(name, address, filterChains,
1✔
262
          defaultFilterChain, protocol);
263
    }
264
  }
265

266
  /**
267
   * Corresponds to Envoy proto message {@link
268
   * io.envoyproxy.envoy.config.cluster.v3.OutlierDetection}. Only the fields supported by gRPC are
269
   * included.
270
   *
271
   * <p>Protobuf Duration fields are represented in their string format (e.g. "10s").
272
   */
273
  @AutoValue
274
  abstract static class OutlierDetection {
1✔
275

276
    @Nullable
277
    abstract Long intervalNanos();
278

279
    @Nullable
280
    abstract Long baseEjectionTimeNanos();
281

282
    @Nullable
283
    abstract Long maxEjectionTimeNanos();
284

285
    @Nullable
286
    abstract Integer maxEjectionPercent();
287

288
    @Nullable
289
    abstract SuccessRateEjection successRateEjection();
290

291
    @Nullable
292
    abstract FailurePercentageEjection failurePercentageEjection();
293

294
    static OutlierDetection create(
295
        @Nullable Long intervalNanos,
296
        @Nullable Long baseEjectionTimeNanos,
297
        @Nullable Long maxEjectionTimeNanos,
298
        @Nullable Integer maxEjectionPercentage,
299
        @Nullable SuccessRateEjection successRateEjection,
300
        @Nullable FailurePercentageEjection failurePercentageEjection) {
301
      return new AutoValue_EnvoyServerProtoData_OutlierDetection(intervalNanos,
1✔
302
          baseEjectionTimeNanos, maxEjectionTimeNanos, maxEjectionPercentage, successRateEjection,
303
          failurePercentageEjection);
304
    }
305

306
    static OutlierDetection fromEnvoyOutlierDetection(
307
        io.envoyproxy.envoy.config.cluster.v3.OutlierDetection envoyOutlierDetection) {
308

309
      Long intervalNanos = envoyOutlierDetection.hasInterval()
1✔
310
          ? Durations.toNanos(envoyOutlierDetection.getInterval()) : null;
1✔
311
      Long baseEjectionTimeNanos = envoyOutlierDetection.hasBaseEjectionTime()
1✔
312
          ? Durations.toNanos(envoyOutlierDetection.getBaseEjectionTime()) : null;
1✔
313
      Long maxEjectionTimeNanos = envoyOutlierDetection.hasMaxEjectionTime()
1✔
314
          ? Durations.toNanos(envoyOutlierDetection.getMaxEjectionTime()) : null;
1✔
315
      Integer maxEjectionPercentage = envoyOutlierDetection.hasMaxEjectionPercent()
1✔
316
          ? envoyOutlierDetection.getMaxEjectionPercent().getValue() : null;
1✔
317

318
      SuccessRateEjection successRateEjection;
319
      // If success rate enforcement has been turned completely off, don't configure this ejection.
320
      if (envoyOutlierDetection.hasEnforcingSuccessRate()
1✔
321
          && envoyOutlierDetection.getEnforcingSuccessRate().getValue() == 0) {
1✔
322
        successRateEjection = null;
×
323
      } else {
324
        Integer stdevFactor = envoyOutlierDetection.hasSuccessRateStdevFactor()
1✔
325
            ? envoyOutlierDetection.getSuccessRateStdevFactor().getValue() : null;
1✔
326
        Integer enforcementPercentage = envoyOutlierDetection.hasEnforcingSuccessRate()
1✔
327
            ? envoyOutlierDetection.getEnforcingSuccessRate().getValue() : null;
1✔
328
        Integer minimumHosts = envoyOutlierDetection.hasSuccessRateMinimumHosts()
1✔
329
            ? envoyOutlierDetection.getSuccessRateMinimumHosts().getValue() : null;
1✔
330
        Integer requestVolume = envoyOutlierDetection.hasSuccessRateRequestVolume()
1✔
331
            ? envoyOutlierDetection.getSuccessRateMinimumHosts().getValue() : null;
1✔
332

333
        successRateEjection = SuccessRateEjection.create(stdevFactor, enforcementPercentage,
1✔
334
            minimumHosts, requestVolume);
335
      }
336

337
      FailurePercentageEjection failurePercentageEjection;
338
      if (envoyOutlierDetection.hasEnforcingFailurePercentage()
1✔
339
          && envoyOutlierDetection.getEnforcingFailurePercentage().getValue() == 0) {
1✔
340
        failurePercentageEjection = null;
×
341
      } else {
342
        Integer threshold = envoyOutlierDetection.hasFailurePercentageThreshold()
1✔
343
            ? envoyOutlierDetection.getFailurePercentageThreshold().getValue() : null;
1✔
344
        Integer enforcementPercentage = envoyOutlierDetection.hasEnforcingFailurePercentage()
1✔
345
            ? envoyOutlierDetection.getEnforcingFailurePercentage().getValue() : null;
1✔
346
        Integer minimumHosts = envoyOutlierDetection.hasFailurePercentageMinimumHosts()
1✔
347
            ? envoyOutlierDetection.getFailurePercentageMinimumHosts().getValue() : null;
1✔
348
        Integer requestVolume = envoyOutlierDetection.hasFailurePercentageRequestVolume()
1✔
349
            ? envoyOutlierDetection.getFailurePercentageRequestVolume().getValue() : null;
1✔
350

351
        failurePercentageEjection = FailurePercentageEjection.create(threshold,
1✔
352
            enforcementPercentage, minimumHosts, requestVolume);
353
      }
354

355
      return create(intervalNanos, baseEjectionTimeNanos, maxEjectionTimeNanos,
1✔
356
          maxEjectionPercentage, successRateEjection, failurePercentageEjection);
357
    }
358
  }
359

360
  @AutoValue
361
  abstract static class SuccessRateEjection {
1✔
362

363
    @Nullable
364
    abstract Integer stdevFactor();
365

366
    @Nullable
367
    abstract Integer enforcementPercentage();
368

369
    @Nullable
370
    abstract Integer minimumHosts();
371

372
    @Nullable
373
    abstract Integer requestVolume();
374

375
    static SuccessRateEjection create(
376
        @Nullable Integer stdevFactor,
377
        @Nullable Integer enforcementPercentage,
378
        @Nullable Integer minimumHosts,
379
        @Nullable Integer requestVolume) {
380
      return new AutoValue_EnvoyServerProtoData_SuccessRateEjection(stdevFactor,
1✔
381
          enforcementPercentage, minimumHosts, requestVolume);
382
    }
383
  }
384

385
  @AutoValue
386
  abstract static class FailurePercentageEjection {
1✔
387

388
    @Nullable
389
    abstract Integer threshold();
390

391
    @Nullable
392
    abstract Integer enforcementPercentage();
393

394
    @Nullable
395
    abstract Integer minimumHosts();
396

397
    @Nullable
398
    abstract Integer requestVolume();
399

400
    static FailurePercentageEjection create(
401
        @Nullable Integer threshold,
402
        @Nullable Integer enforcementPercentage,
403
        @Nullable Integer minimumHosts,
404
        @Nullable Integer requestVolume) {
405
      return new AutoValue_EnvoyServerProtoData_FailurePercentageEjection(threshold,
1✔
406
          enforcementPercentage, minimumHosts, requestVolume);
407
    }
408
  }
409
}
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

© 2025 Coveralls, Inc