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

grpc / grpc-java / #20230

31 Mar 2026 09:55AM UTC coverage: 88.734% (+0.01%) from 88.72%
#20230

push

github

web-flow
openTelemetry: add tcp metrics (#12652)

Implements [A80](https://github.com/grpc/proposal/pull/519)

35697 of 40229 relevant lines covered (88.73%)

0.89 hits per line

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

57.61
/../netty/src/main/java/io/grpc/netty/NettyServerBuilder.java
1
/*
2
 * Copyright 2014 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.netty;
18

19
import static com.google.common.base.Preconditions.checkArgument;
20
import static com.google.common.base.Preconditions.checkNotNull;
21
import static com.google.common.base.Preconditions.checkState;
22
import static io.grpc.internal.GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE;
23
import static io.grpc.internal.GrpcUtil.DEFAULT_SERVER_KEEPALIVE_TIMEOUT_NANOS;
24
import static io.grpc.internal.GrpcUtil.DEFAULT_SERVER_KEEPALIVE_TIME_NANOS;
25
import static io.grpc.internal.GrpcUtil.SERVER_KEEPALIVE_TIME_NANOS_DISABLED;
26

27
import com.google.common.annotations.VisibleForTesting;
28
import com.google.errorprone.annotations.CanIgnoreReturnValue;
29
import com.google.errorprone.annotations.CheckReturnValue;
30
import com.google.errorprone.annotations.InlineMe;
31
import io.grpc.Attributes;
32
import io.grpc.ExperimentalApi;
33
import io.grpc.ForwardingServerBuilder;
34
import io.grpc.Internal;
35
import io.grpc.MetricRecorder;
36
import io.grpc.ServerBuilder;
37
import io.grpc.ServerCredentials;
38
import io.grpc.ServerStreamTracer;
39
import io.grpc.internal.FixedObjectPool;
40
import io.grpc.internal.GrpcUtil;
41
import io.grpc.internal.InternalServer;
42
import io.grpc.internal.KeepAliveManager;
43
import io.grpc.internal.ObjectPool;
44
import io.grpc.internal.ServerImplBuilder;
45
import io.grpc.internal.ServerImplBuilder.ClientTransportServersBuilder;
46
import io.grpc.internal.SharedResourcePool;
47
import io.grpc.internal.TransportTracer;
48
import io.netty.channel.ChannelFactory;
49
import io.netty.channel.ChannelOption;
50
import io.netty.channel.EventLoopGroup;
51
import io.netty.channel.ReflectiveChannelFactory;
52
import io.netty.channel.ServerChannel;
53
import io.netty.channel.socket.nio.NioServerSocketChannel;
54
import io.netty.handler.ssl.SslContext;
55
import java.io.File;
56
import java.io.InputStream;
57
import java.net.InetSocketAddress;
58
import java.net.SocketAddress;
59
import java.util.ArrayList;
60
import java.util.HashMap;
61
import java.util.List;
62
import java.util.Map;
63
import java.util.concurrent.TimeUnit;
64
import javax.net.ssl.SSLException;
65

66
/**
67
 * A builder to help simplify the construction of a Netty-based GRPC server.
68
 */
69
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1784")
70
@CheckReturnValue
71
public final class NettyServerBuilder extends ForwardingServerBuilder<NettyServerBuilder> {
72

73
  // 1MiB
74
  public static final int DEFAULT_FLOW_CONTROL_WINDOW = 1024 * 1024;
75

76
  static final long MAX_CONNECTION_IDLE_NANOS_DISABLED = Long.MAX_VALUE;
77
  static final long MAX_CONNECTION_AGE_NANOS_DISABLED = Long.MAX_VALUE;
78
  static final long MAX_CONNECTION_AGE_GRACE_NANOS_INFINITE = Long.MAX_VALUE;
79
  static final int MAX_RST_COUNT_DISABLED = 0;
80

81
  private static final long MIN_MAX_CONNECTION_IDLE_NANO = TimeUnit.SECONDS.toNanos(1L);
1✔
82
  private static final long MIN_MAX_CONNECTION_AGE_NANO = TimeUnit.SECONDS.toNanos(1L);
1✔
83
  private static final long AS_LARGE_AS_INFINITE = TimeUnit.DAYS.toNanos(1000L);
1✔
84
  private static final ObjectPool<? extends EventLoopGroup> DEFAULT_BOSS_EVENT_LOOP_GROUP_POOL =
1✔
85
      SharedResourcePool.forResource(Utils.DEFAULT_BOSS_EVENT_LOOP_GROUP);
1✔
86
  private static final ObjectPool<? extends EventLoopGroup> DEFAULT_WORKER_EVENT_LOOP_GROUP_POOL =
1✔
87
      SharedResourcePool.forResource(Utils.DEFAULT_WORKER_EVENT_LOOP_GROUP);
1✔
88

89
  private final ServerImplBuilder serverImplBuilder;
90
  private final List<SocketAddress> listenAddresses = new ArrayList<>();
1✔
91

92
  private TransportTracer.Factory transportTracerFactory = TransportTracer.getDefaultFactory();
1✔
93
  private ChannelFactory<? extends ServerChannel> channelFactory =
1✔
94
      Utils.DEFAULT_SERVER_CHANNEL_FACTORY;
95
  private final Map<ChannelOption<?>, Object> channelOptions = new HashMap<>();
1✔
96
  private final Map<ChannelOption<?>, Object> childChannelOptions = new HashMap<>();
1✔
97
  private ObjectPool<? extends EventLoopGroup> bossEventLoopGroupPool =
1✔
98
      DEFAULT_BOSS_EVENT_LOOP_GROUP_POOL;
99
  private ObjectPool<? extends EventLoopGroup> workerEventLoopGroupPool =
1✔
100
      DEFAULT_WORKER_EVENT_LOOP_GROUP_POOL;
101
  private boolean forceHeapBuffer;
102
  private ProtocolNegotiator.ServerFactory protocolNegotiatorFactory;
103
  private final boolean freezeProtocolNegotiatorFactory;
104
  private int maxConcurrentCallsPerConnection = Integer.MAX_VALUE;
1✔
105
  private boolean autoFlowControl = true;
1✔
106
  private int flowControlWindow = DEFAULT_FLOW_CONTROL_WINDOW;
1✔
107
  private int maxMessageSize = DEFAULT_MAX_MESSAGE_SIZE;
1✔
108
  private int maxHeaderListSize = GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE;
1✔
109
  private int softLimitHeaderListSize = GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE;
1✔
110
  private long keepAliveTimeInNanos = DEFAULT_SERVER_KEEPALIVE_TIME_NANOS;
1✔
111
  private long keepAliveTimeoutInNanos = DEFAULT_SERVER_KEEPALIVE_TIMEOUT_NANOS;
1✔
112
  private long maxConnectionIdleInNanos = MAX_CONNECTION_IDLE_NANOS_DISABLED;
1✔
113
  private long maxConnectionAgeInNanos = MAX_CONNECTION_AGE_NANOS_DISABLED;
1✔
114
  private long maxConnectionAgeGraceInNanos = MAX_CONNECTION_AGE_GRACE_NANOS_INFINITE;
1✔
115
  private boolean permitKeepAliveWithoutCalls;
116
  private long permitKeepAliveTimeInNanos = TimeUnit.MINUTES.toNanos(5);
1✔
117
  private int maxRstCount;
118
  private long maxRstPeriodNanos;
119
  private Attributes eagAttributes = Attributes.EMPTY;
1✔
120

121
  /**
122
   * Creates a server builder that will bind to the given port.
123
   *
124
   * @param port the port on which the server is to be bound.
125
   * @return the server builder.
126
   */
127
  public static NettyServerBuilder forPort(int port) {
128
    return forAddress(new InetSocketAddress(port));
1✔
129
  }
130

131
  /**
132
   * Creates a server builder that will bind to the given port.
133
   *
134
   * @param port the port on which the server is to be bound.
135
   * @return the server builder.
136
   */
137
  public static NettyServerBuilder forPort(int port, ServerCredentials creds) {
138
    return forAddress(new InetSocketAddress(port), creds);
1✔
139
  }
140

141
  /**
142
   * Creates a server builder configured with the given {@link SocketAddress}.
143
   *
144
   * @param address the socket address on which the server is to be bound.
145
   * @return the server builder
146
   */
147
  public static NettyServerBuilder forAddress(SocketAddress address) {
148
    return new NettyServerBuilder(address);
1✔
149
  }
150

151
  /**
152
   * Creates a server builder configured with the given {@link SocketAddress}.
153
   *
154
   * @param address the socket address on which the server is to be bound.
155
   * @return the server builder
156
   */
157
  public static NettyServerBuilder forAddress(SocketAddress address, ServerCredentials creds) {
158
    ProtocolNegotiators.FromServerCredentialsResult result = ProtocolNegotiators.from(creds);
1✔
159
    if (result.error != null) {
1✔
160
      throw new IllegalArgumentException(result.error);
×
161
    }
162
    return new NettyServerBuilder(address, result.negotiator);
1✔
163
  }
164

165
  private final class NettyClientTransportServersBuilder implements ClientTransportServersBuilder {
1✔
166
    @Override
167
    public InternalServer buildClientTransportServers(
168
        List<? extends ServerStreamTracer.Factory> streamTracerFactories,
169
        MetricRecorder metricRecorder) {
170
      return buildTransportServers(streamTracerFactories, metricRecorder);
1✔
171
    }
172
  }
173

174
  private NettyServerBuilder(SocketAddress address) {
1✔
175
    serverImplBuilder = new ServerImplBuilder(new NettyClientTransportServersBuilder());
1✔
176
    this.listenAddresses.add(address);
1✔
177
    this.protocolNegotiatorFactory = ProtocolNegotiators.serverPlaintextFactory();
1✔
178
    this.freezeProtocolNegotiatorFactory = false;
1✔
179
  }
1✔
180

181
  NettyServerBuilder(SocketAddress address, ProtocolNegotiator.ServerFactory negotiatorFactory) {
1✔
182
    serverImplBuilder = new ServerImplBuilder(new NettyClientTransportServersBuilder());
1✔
183
    this.listenAddresses.add(address);
1✔
184
    this.protocolNegotiatorFactory = checkNotNull(negotiatorFactory, "negotiatorFactory");
1✔
185
    this.freezeProtocolNegotiatorFactory = true;
1✔
186
  }
1✔
187

188
  @Internal
189
  @Override
190
  protected ServerBuilder<?> delegate() {
191
    return serverImplBuilder;
1✔
192
  }
193

194
  /**
195
   * Adds an additional address for this server to listen on.  Callers must ensure that all socket
196
   * addresses are compatible with the Netty channel type, and that they don't conflict with each
197
   * other.
198
   */
199
  @CanIgnoreReturnValue
200
  public NettyServerBuilder addListenAddress(SocketAddress listenAddress) {
201
    this.listenAddresses.add(checkNotNull(listenAddress, "listenAddress"));
1✔
202
    return this;
1✔
203
  }
204

205
  /**
206
   * Specifies the channel type to use, by default we use {@code EpollServerSocketChannel} if
207
   * available, otherwise using {@link NioServerSocketChannel}.
208
   *
209
   * <p>You either use this or {@link #channelFactory(io.netty.channel.ChannelFactory)} if your
210
   * {@link ServerChannel} implementation has no no-args constructor.
211
   *
212
   * <p>It's an optional parameter. If the user has not provided an Channel type or ChannelFactory
213
   * when the channel is built, the builder will use the default one which is static.
214
   *
215
   * <p>You must also provide corresponding {@link EventLoopGroup} using {@link
216
   * #workerEventLoopGroup(EventLoopGroup)} and {@link #bossEventLoopGroup(EventLoopGroup)}. For
217
   * example, {@link NioServerSocketChannel} must use {@link
218
   * io.netty.channel.nio.NioEventLoopGroup}, otherwise your server won't start.
219
   */
220
  @CanIgnoreReturnValue
221
  public NettyServerBuilder channelType(Class<? extends ServerChannel> channelType) {
222
    checkNotNull(channelType, "channelType");
1✔
223
    return channelFactory(new ReflectiveChannelFactory<>(channelType));
1✔
224
  }
225

226
  /**
227
   * Specifies the {@link ChannelFactory} to create {@link ServerChannel} instances. This method is
228
   * usually only used if the specific {@code ServerChannel} requires complex logic which requires
229
   * additional information to create the {@code ServerChannel}. Otherwise, recommend to use {@link
230
   * #channelType(Class)}.
231
   *
232
   * <p>It's an optional parameter. If the user has not provided an Channel type or ChannelFactory
233
   * when the channel is built, the builder will use the default one which is static.
234
   *
235
   * <p>You must also provide corresponding {@link EventLoopGroup} using {@link
236
   * #workerEventLoopGroup(EventLoopGroup)} and {@link #bossEventLoopGroup(EventLoopGroup)}. For
237
   * example, if the factory creates {@link NioServerSocketChannel} you must use {@link
238
   * io.netty.channel.nio.NioEventLoopGroup}, otherwise your server won't start.
239
   */
240
  @CanIgnoreReturnValue
241
  public NettyServerBuilder channelFactory(ChannelFactory<? extends ServerChannel> channelFactory) {
242
    this.channelFactory = checkNotNull(channelFactory, "channelFactory");
1✔
243
    return this;
1✔
244
  }
245

246
  /**
247
   * Specifies a channel option. As the underlying channel as well as network implementation may
248
   * ignore this value applications should consider it a hint.
249
   *
250
   * @since 1.30.0
251
   */
252
  @CanIgnoreReturnValue
253
  public <T> NettyServerBuilder withOption(ChannelOption<T> option, T value) {
254
    this.channelOptions.put(option, value);
×
255
    return this;
×
256
  }
257

258
  /**
259
   * Specifies a child channel option. As the underlying channel as well as network implementation
260
   * may ignore this value applications should consider it a hint.
261
   *
262
   * @since 1.9.0
263
   */
264
  @CanIgnoreReturnValue
265
  public <T> NettyServerBuilder withChildOption(ChannelOption<T> option, T value) {
266
    this.childChannelOptions.put(option, value);
×
267
    return this;
×
268
  }
269

270
  /**
271
   * Provides the boss EventGroupLoop to the server.
272
   *
273
   * <p>It's an optional parameter. If the user has not provided one when the server is built, the
274
   * builder will use the default one which is static.
275
   *
276
   * <p>You must also provide corresponding {@link io.netty.channel.Channel} type using {@link
277
   * #channelType(Class)} and {@link #workerEventLoopGroup(EventLoopGroup)}. For example, {@link
278
   * NioServerSocketChannel} must use {@link io.netty.channel.nio.NioEventLoopGroup} for both boss
279
   * and worker {@link EventLoopGroup}, otherwise your server won't start.
280
   *
281
   * <p>The server won't take ownership of the given EventLoopGroup. It's caller's responsibility
282
   * to shut it down when it's desired.
283
   *
284
   * <p>Grpc uses non-daemon {@link Thread}s by default and thus a {@link io.grpc.Server} will
285
   * continue to run even after the main thread has terminated. However, users have to be cautious
286
   * when providing their own {@link EventLoopGroup}s.
287
   * For example, Netty's {@link EventLoopGroup}s use daemon threads by default
288
   * and thus an application with only daemon threads running besides the main thread will exit as
289
   * soon as the main thread completes.
290
   * A simple solution to this problem is to call {@link io.grpc.Server#awaitTermination()} to
291
   * keep the main thread alive until the server has terminated.
292
   */
293
  @CanIgnoreReturnValue
294
  public NettyServerBuilder bossEventLoopGroup(EventLoopGroup group) {
295
    if (group != null) {
1✔
296
      return bossEventLoopGroupPool(new FixedObjectPool<>(group));
1✔
297
    }
298
    return bossEventLoopGroupPool(DEFAULT_BOSS_EVENT_LOOP_GROUP_POOL);
×
299
  }
300

301
  @CanIgnoreReturnValue
302
  NettyServerBuilder bossEventLoopGroupPool(
303
      ObjectPool<? extends EventLoopGroup> bossEventLoopGroupPool) {
304
    this.bossEventLoopGroupPool = checkNotNull(bossEventLoopGroupPool, "bossEventLoopGroupPool");
1✔
305
    return this;
1✔
306
  }
307

308
  /**
309
   * Provides the worker EventGroupLoop to the server.
310
   *
311
   * <p>It's an optional parameter. If the user has not provided one when the server is built, the
312
   * builder will create one.
313
   *
314
   * <p>You must also provide corresponding {@link io.netty.channel.Channel} type using {@link
315
   * #channelType(Class)} and {@link #bossEventLoopGroup(EventLoopGroup)}. For example, {@link
316
   * NioServerSocketChannel} must use {@link io.netty.channel.nio.NioEventLoopGroup} for both boss
317
   * and worker {@link EventLoopGroup}, otherwise your server won't start.
318
   *
319
   * <p>The server won't take ownership of the given EventLoopGroup. It's caller's responsibility
320
   * to shut it down when it's desired.
321
   *
322
   * <p>Grpc uses non-daemon {@link Thread}s by default and thus a {@link io.grpc.Server} will
323
   * continue to run even after the main thread has terminated. However, users have to be cautious
324
   * when providing their own {@link EventLoopGroup}s.
325
   * For example, Netty's {@link EventLoopGroup}s use daemon threads by default
326
   * and thus an application with only daemon threads running besides the main thread will exit as
327
   * soon as the main thread completes.
328
   * A simple solution to this problem is to call {@link io.grpc.Server#awaitTermination()} to
329
   * keep the main thread alive until the server has terminated.
330
   */
331
  @CanIgnoreReturnValue
332
  public NettyServerBuilder workerEventLoopGroup(EventLoopGroup group) {
333
    if (group != null) {
1✔
334
      return workerEventLoopGroupPool(new FixedObjectPool<>(group));
1✔
335
    }
336
    return workerEventLoopGroupPool(DEFAULT_WORKER_EVENT_LOOP_GROUP_POOL);
×
337
  }
338

339
  @CanIgnoreReturnValue
340
  NettyServerBuilder workerEventLoopGroupPool(
341
      ObjectPool<? extends EventLoopGroup> workerEventLoopGroupPool) {
342
    this.workerEventLoopGroupPool =
1✔
343
        checkNotNull(workerEventLoopGroupPool, "workerEventLoopGroupPool");
1✔
344
    return this;
1✔
345
  }
346

347
  /**
348
   * Force using heap buffer when custom allocator is enabled.
349
   */
350
  void setForceHeapBuffer(boolean value) {
351
    forceHeapBuffer = value;
×
352
  }
×
353

354
  /**
355
   * Sets the TLS context to use for encryption. Providing a context enables encryption. It must
356
   * have been configured with {@link GrpcSslContexts}, but options could have been overridden.
357
   */
358
  @CanIgnoreReturnValue
359
  public NettyServerBuilder sslContext(SslContext sslContext) {
360
    checkState(!freezeProtocolNegotiatorFactory,
1✔
361
               "Cannot change security when using ServerCredentials");
362
    if (sslContext != null) {
1✔
363
      checkArgument(sslContext.isServer(),
1✔
364
          "Client SSL context can not be used for server");
365
      GrpcSslContexts.ensureAlpnAndH2Enabled(sslContext.applicationProtocolNegotiator());
1✔
366
      protocolNegotiatorFactory = ProtocolNegotiators.serverTlsFactory(sslContext);
1✔
367
    } else {
368
      protocolNegotiatorFactory = ProtocolNegotiators.serverPlaintextFactory();
1✔
369
    }
370
    return this;
1✔
371
  }
372

373
  /**
374
   * Sets the {@link ProtocolNegotiator} to be used. Overrides the value specified in {@link
375
   * #sslContext(SslContext)}.
376
   */
377
  @CanIgnoreReturnValue
378
  @Internal
379
  public final NettyServerBuilder protocolNegotiator(ProtocolNegotiator protocolNegotiator) {
380
    checkState(!freezeProtocolNegotiatorFactory,
×
381
               "Cannot change security when using ServerCredentials");
382
    this.protocolNegotiatorFactory = ProtocolNegotiators.fixedServerFactory(protocolNegotiator);
×
383
    return this;
×
384
  }
385

386
  void setTracingEnabled(boolean value) {
387
    this.serverImplBuilder.setTracingEnabled(value);
×
388
  }
×
389

390
  void setStatsEnabled(boolean value) {
391
    this.serverImplBuilder.setStatsEnabled(value);
1✔
392
  }
1✔
393

394
  void setStatsRecordStartedRpcs(boolean value) {
395
    this.serverImplBuilder.setStatsRecordStartedRpcs(value);
×
396
  }
×
397

398
  void setStatsRecordRealTimeMetrics(boolean value) {
399
    this.serverImplBuilder.setStatsRecordRealTimeMetrics(value);
×
400
  }
×
401

402
  /**
403
   * The maximum number of concurrent calls permitted for each incoming connection. Defaults to no
404
   * limit.
405
   */
406
  @CanIgnoreReturnValue
407
  public NettyServerBuilder maxConcurrentCallsPerConnection(int maxCalls) {
408
    checkArgument(maxCalls > 0, "max must be positive: %s", maxCalls);
1✔
409
    this.maxConcurrentCallsPerConnection = maxCalls;
×
410
    return this;
×
411
  }
412

413
  /**
414
   * Sets the initial flow control window in bytes. Setting initial flow control window enables auto
415
   * flow control tuning using bandwidth-delay product algorithm. To disable auto flow control
416
   * tuning, use {@link #flowControlWindow(int)}. By default, auto flow control is enabled with
417
   * initial flow control window size of {@link #DEFAULT_FLOW_CONTROL_WINDOW}.
418
   */
419
  @CanIgnoreReturnValue
420
  public NettyServerBuilder initialFlowControlWindow(int initialFlowControlWindow) {
421
    checkArgument(initialFlowControlWindow > 0, "initialFlowControlWindow must be positive");
1✔
422
    this.flowControlWindow = initialFlowControlWindow;
1✔
423
    this.autoFlowControl = true;
1✔
424
    return this;
1✔
425
  }
426

427
  /**
428
   * Sets the flow control window in bytes. Setting flowControlWindow disables auto flow control
429
   * tuning; use {@link #initialFlowControlWindow(int)} to enable auto flow control tuning. If not
430
   * called, the default value is {@link #DEFAULT_FLOW_CONTROL_WINDOW}) with auto flow control
431
   * tuning.
432
   */
433
  @CanIgnoreReturnValue
434
  public NettyServerBuilder flowControlWindow(int flowControlWindow) {
435
    checkArgument(flowControlWindow > 0, "flowControlWindow must be positive: %s",
1✔
436
        flowControlWindow);
437
    this.flowControlWindow = flowControlWindow;
1✔
438
    this.autoFlowControl = false;
1✔
439
    return this;
1✔
440
  }
441

442
  /**
443
   * Sets the maximum message size allowed to be received on the server. If not called,
444
   * defaults to 4 MiB. The default provides protection to services who haven't considered the
445
   * possibility of receiving large messages while trying to be large enough to not be hit in normal
446
   * usage.
447
   *
448
   * @deprecated Call {@link #maxInboundMessageSize} instead. This method will be removed in a
449
   *     future release.
450
   */
451
  @CanIgnoreReturnValue
452
  @Deprecated
453
  @InlineMe(replacement = "this.maxInboundMessageSize(maxMessageSize)")
454
  public NettyServerBuilder maxMessageSize(int maxMessageSize) {
455
    return maxInboundMessageSize(maxMessageSize);
×
456
  }
457

458
  /** {@inheritDoc} */
459
  @CanIgnoreReturnValue
460
  @Override
461
  public NettyServerBuilder maxInboundMessageSize(int bytes) {
462
    checkArgument(bytes >= 0, "bytes must be non-negative: %s", bytes);
1✔
463
    this.maxMessageSize = bytes;
1✔
464
    return this;
1✔
465
  }
466

467
  /**
468
   * Sets the maximum size of header list allowed to be received. This is cumulative size of the
469
   * headers with some overhead, as defined for
470
   * <a href="http://httpwg.org/specs/rfc7540.html#rfc.section.6.5.2">
471
   * HTTP/2's SETTINGS_MAX_HEADER_LIST_SIZE</a>. The default is 8 KiB.
472
   *
473
   * @deprecated Use {@link #maxInboundMetadataSize} instead
474
   */
475
  @CanIgnoreReturnValue
476
  @Deprecated
477
  @InlineMe(replacement = "this.maxInboundMetadataSize(maxHeaderListSize)")
478
  public NettyServerBuilder maxHeaderListSize(int maxHeaderListSize) {
479
    return maxInboundMetadataSize(maxHeaderListSize);
×
480
  }
481

482
  /**
483
   * Sets the maximum size of metadata allowed to be received. This is cumulative size of the
484
   * entries with some overhead, as defined for
485
   * <a href="http://httpwg.org/specs/rfc7540.html#rfc.section.6.5.2">
486
   * HTTP/2's SETTINGS_MAX_HEADER_LIST_SIZE</a>. The default is 8 KiB.
487
   *
488
   * @param bytes the maximum size of received metadata
489
   * @return this
490
   * @throws IllegalArgumentException if bytes is non-positive
491
   * @since 1.17.0
492
   */
493
  @CanIgnoreReturnValue
494
  @Override
495
  public NettyServerBuilder maxInboundMetadataSize(int bytes) {
496
    checkArgument(bytes > 0, "maxInboundMetadataSize must be positive: %s", bytes);
1✔
497
    this.maxHeaderListSize = bytes;
×
498
    // Clear the soft limit setting, by setting soft limit to maxInboundMetadataSize. The
499
    // maxInboundMetadataSize will take precedence over soft limit check.
500
    this.softLimitHeaderListSize = bytes;
×
501
    return this;
×
502
  }
503

504
  /**
505
   * Sets the size of metadata that clients are advised to not exceed. When a metadata with size
506
   * larger than the soft limit is encountered there will be a probability the RPC will fail. The
507
   * chance of failing increases as the metadata size approaches the hard limit.
508
   * {@code Integer.MAX_VALUE} disables the enforcement. The default is implementation-dependent,
509
   * but is not generally less than 8 KiB and may be unlimited.
510
   *
511
   * <p>This is cumulative size of the metadata. The precise calculation is
512
   * implementation-dependent, but implementations are encouraged to follow the calculation used
513
   * for
514
   * <a href="http://httpwg.org/specs/rfc7540.html#rfc.section.6.5.2">HTTP/2's
515
   * SETTINGS_MAX_HEADER_LIST_SIZE</a>. It sums the bytes from each entry's key and value, plus 32
516
   * bytes of overhead per entry.
517
   *
518
   * @param soft the soft size limit of received metadata
519
   * @param max the hard size limit of received metadata
520
   * @return this
521
   * @throws IllegalArgumentException if soft and/or max is non-positive, or max smaller than soft
522
   * @since 1.68.0
523
   */
524
  @CanIgnoreReturnValue
525
  public NettyServerBuilder maxInboundMetadataSize(int soft, int max) {
526
    checkArgument(soft > 0, "softLimitHeaderListSize must be positive: %s", soft);
1✔
527
    checkArgument(max > soft,
1✔
528
        "maxInboundMetadataSize: %s must be greater than softLimitHeaderListSize: %s", max, soft);
529
    this.softLimitHeaderListSize = soft;
×
530
    this.maxHeaderListSize = max;
×
531
    return this;
×
532
  }
533

534
  /**
535
   * Sets a custom keepalive time, the delay time for sending next keepalive ping. An unreasonably
536
   * small value might be increased, and {@code Long.MAX_VALUE} nano seconds or an unreasonably
537
   * large value will disable keepalive.
538
   *
539
   * @since 1.3.0
540
   */
541
  @CanIgnoreReturnValue
542
  @Override
543
  public NettyServerBuilder keepAliveTime(long keepAliveTime, TimeUnit timeUnit) {
544
    checkArgument(keepAliveTime > 0L, "keepalive time must be positive:%s", keepAliveTime);
1✔
545
    keepAliveTimeInNanos = timeUnit.toNanos(keepAliveTime);
×
546
    keepAliveTimeInNanos = KeepAliveManager.clampKeepAliveTimeInNanos(keepAliveTimeInNanos);
×
547
    if (keepAliveTimeInNanos >= AS_LARGE_AS_INFINITE) {
×
548
      // Bump keepalive time to infinite. This disables keep alive.
549
      keepAliveTimeInNanos = SERVER_KEEPALIVE_TIME_NANOS_DISABLED;
×
550
    }
551
    return this;
×
552
  }
553

554
  /**
555
   * Sets a custom keepalive timeout, the timeout for keepalive ping requests. An unreasonably small
556
   * value might be increased.
557
   *
558
   * @since 1.3.0
559
   */
560
  @CanIgnoreReturnValue
561
  @Override
562
  public NettyServerBuilder keepAliveTimeout(long keepAliveTimeout, TimeUnit timeUnit) {
563
    checkArgument(keepAliveTimeout > 0L, "keepalive timeout must be positive: %s",
1✔
564
        keepAliveTimeout);
565
    keepAliveTimeoutInNanos = timeUnit.toNanos(keepAliveTimeout);
×
566
    keepAliveTimeoutInNanos =
×
567
        KeepAliveManager.clampKeepAliveTimeoutInNanos(keepAliveTimeoutInNanos);
×
568
    return this;
×
569
  }
570

571
  /**
572
   * Sets a custom max connection idle time, connection being idle for longer than which will be
573
   * gracefully terminated. Idleness duration is defined since the most recent time the number of
574
   * outstanding RPCs became zero or the connection establishment. An unreasonably small value might
575
   * be increased. {@code Long.MAX_VALUE} nano seconds or an unreasonably large value will disable
576
   * max connection idle.
577
   *
578
   * @since 1.4.0
579
   */
580
  @CanIgnoreReturnValue
581
  @Override
582
  public NettyServerBuilder maxConnectionIdle(long maxConnectionIdle, TimeUnit timeUnit) {
583
    checkArgument(maxConnectionIdle > 0L, "max connection idle must be positive: %s",
1✔
584
        maxConnectionIdle);
585
    maxConnectionIdleInNanos = timeUnit.toNanos(maxConnectionIdle);
×
586
    if (maxConnectionIdleInNanos >= AS_LARGE_AS_INFINITE) {
×
587
      maxConnectionIdleInNanos = MAX_CONNECTION_IDLE_NANOS_DISABLED;
×
588
    }
589
    if (maxConnectionIdleInNanos < MIN_MAX_CONNECTION_IDLE_NANO) {
×
590
      maxConnectionIdleInNanos = MIN_MAX_CONNECTION_IDLE_NANO;
×
591
    }
592
    return this;
×
593
  }
594

595
  /**
596
   * Sets a custom max connection age, connection lasting longer than which will be gracefully
597
   * terminated. An unreasonably small value might be increased.  A random jitter of +/-10% will be
598
   * added to it. {@code Long.MAX_VALUE} nano seconds or an unreasonably large value will disable
599
   * max connection age.
600
   *
601
   * @since 1.3.0
602
   */
603
  @CanIgnoreReturnValue
604
  @Override
605
  public NettyServerBuilder maxConnectionAge(long maxConnectionAge, TimeUnit timeUnit) {
606
    checkArgument(maxConnectionAge > 0L, "max connection age must be positive: %s",
1✔
607
        maxConnectionAge);
608
    maxConnectionAgeInNanos = timeUnit.toNanos(maxConnectionAge);
×
609
    if (maxConnectionAgeInNanos >= AS_LARGE_AS_INFINITE) {
×
610
      maxConnectionAgeInNanos = MAX_CONNECTION_AGE_NANOS_DISABLED;
×
611
    }
612
    if (maxConnectionAgeInNanos < MIN_MAX_CONNECTION_AGE_NANO) {
×
613
      maxConnectionAgeInNanos = MIN_MAX_CONNECTION_AGE_NANO;
×
614
    }
615
    return this;
×
616
  }
617

618
  /**
619
   * Sets a custom grace time for the graceful connection termination. Once the max connection age
620
   * is reached, RPCs have the grace time to complete. RPCs that do not complete in time will be
621
   * cancelled, allowing the connection to terminate. {@code Long.MAX_VALUE} nano seconds or an
622
   * unreasonably large value are considered infinite.
623
   *
624
   * @see #maxConnectionAge(long, TimeUnit)
625
   * @since 1.3.0
626
   */
627
  @CanIgnoreReturnValue
628
  @Override
629
  public NettyServerBuilder maxConnectionAgeGrace(long maxConnectionAgeGrace, TimeUnit timeUnit) {
630
    checkArgument(maxConnectionAgeGrace >= 0L, "max connection age grace must be non-negative: %s",
1✔
631
        maxConnectionAgeGrace);
632
    maxConnectionAgeGraceInNanos = timeUnit.toNanos(maxConnectionAgeGrace);
×
633
    if (maxConnectionAgeGraceInNanos >= AS_LARGE_AS_INFINITE) {
×
634
      maxConnectionAgeGraceInNanos = MAX_CONNECTION_AGE_GRACE_NANOS_INFINITE;
×
635
    }
636
    return this;
×
637
  }
638

639
  /**
640
   * Specify the most aggressive keep-alive time clients are permitted to configure. The server will
641
   * try to detect clients exceeding this rate and when detected will forcefully close the
642
   * connection. The default is 5 minutes.
643
   *
644
   * <p>Even though a default is defined that allows some keep-alives, clients must not use
645
   * keep-alive without approval from the service owner. Otherwise, they may experience failures in
646
   * the future if the service becomes more restrictive. When unthrottled, keep-alives can cause a
647
   * significant amount of traffic and CPU usage, so clients and servers should be conservative in
648
   * what they use and accept.
649
   *
650
   * @see #permitKeepAliveWithoutCalls(boolean)
651
   * @since 1.3.0
652
   */
653
  @CanIgnoreReturnValue
654
  @Override
655
  public NettyServerBuilder permitKeepAliveTime(long keepAliveTime, TimeUnit timeUnit) {
656
    checkArgument(keepAliveTime >= 0, "permit keepalive time must be non-negative: %s",
1✔
657
        keepAliveTime);
658
    permitKeepAliveTimeInNanos = timeUnit.toNanos(keepAliveTime);
×
659
    return this;
×
660
  }
661

662
  /**
663
   * Sets whether to allow clients to send keep-alive HTTP/2 PINGs even if there are no outstanding
664
   * RPCs on the connection. Defaults to {@code false}.
665
   *
666
   * @see #permitKeepAliveTime(long, TimeUnit)
667
   * @since 1.3.0
668
   */
669
  @CanIgnoreReturnValue
670
  @Override
671
  public NettyServerBuilder permitKeepAliveWithoutCalls(boolean permit) {
672
    permitKeepAliveWithoutCalls = permit;
×
673
    return this;
×
674
  }
675

676
  /**
677
   * Limits the rate of incoming RST_STREAM frames per connection to maxRstStream per
678
   * secondsPerWindow. When exceeded on a connection, the connection is closed. This can reduce the
679
   * impact of an attacker continually resetting RPCs before they complete, when combined with TLS
680
   * and {@link #maxConcurrentCallsPerConnection(int)}.
681
   *
682
   * <p>gRPC clients send RST_STREAM when they cancel RPCs, so some RST_STREAMs are normal and
683
   * setting this too low can cause errors for legimitate clients.
684
   *
685
   * <p>By default there is no limit.
686
   *
687
   * @param maxRstStream the positive limit of RST_STREAM frames per connection per period, or
688
   *     {@code Integer.MAX_VALUE} for unlimited
689
   * @param secondsPerWindow the positive number of seconds per period
690
   */
691
  @CanIgnoreReturnValue
692
  public NettyServerBuilder maxRstFramesPerWindow(int maxRstStream, int secondsPerWindow) {
693
    checkArgument(maxRstStream > 0, "maxRstStream must be positive");
×
694
    checkArgument(secondsPerWindow > 0, "secondsPerWindow must be positive");
×
695
    if (maxRstStream == Integer.MAX_VALUE) {
×
696
      maxRstStream = MAX_RST_COUNT_DISABLED;
×
697
    }
698
    this.maxRstCount = maxRstStream;
×
699
    this.maxRstPeriodNanos = TimeUnit.SECONDS.toNanos(secondsPerWindow);
×
700
    return this;
×
701
  }
702

703
  /** Sets the EAG attributes available to protocol negotiators. Not for general use. */
704
  void eagAttributes(Attributes eagAttributes) {
705
    this.eagAttributes = checkNotNull(eagAttributes, "eagAttributes");
1✔
706
  }
1✔
707

708
  @VisibleForTesting
709
  NettyServer buildTransportServers(
710
      List<? extends ServerStreamTracer.Factory> streamTracerFactories,
711
      MetricRecorder metricRecorder) {
712
    assertEventLoopsAndChannelType();
1✔
713

714
    ProtocolNegotiator negotiator = protocolNegotiatorFactory.newNegotiator(
1✔
715
        this.serverImplBuilder.getExecutorPool());
1✔
716

717
    return new NettyServer(
1✔
718
        listenAddresses,
719
        channelFactory,
720
        channelOptions,
721
        childChannelOptions,
722
        bossEventLoopGroupPool,
723
        workerEventLoopGroupPool,
724
        forceHeapBuffer,
725
        negotiator,
726
        streamTracerFactories,
727
        transportTracerFactory,
728
        maxConcurrentCallsPerConnection,
729
        autoFlowControl,
730
        flowControlWindow,
731
        maxMessageSize,
732
        maxHeaderListSize,
733
        softLimitHeaderListSize,
734
        keepAliveTimeInNanos,
735
        keepAliveTimeoutInNanos,
736
        maxConnectionIdleInNanos,
737
        maxConnectionAgeInNanos,
738
        maxConnectionAgeGraceInNanos,
739
        permitKeepAliveWithoutCalls,
740
        permitKeepAliveTimeInNanos,
741
        maxRstCount,
742
        maxRstPeriodNanos,
743
        eagAttributes,
744
        this.serverImplBuilder.getChannelz(),
1✔
745
        metricRecorder);
746
  }
747

748
  @VisibleForTesting
749
  void assertEventLoopsAndChannelType() {
750
    boolean allProvided = channelFactory != Utils.DEFAULT_SERVER_CHANNEL_FACTORY
1✔
751
        && bossEventLoopGroupPool != DEFAULT_BOSS_EVENT_LOOP_GROUP_POOL
752
        && workerEventLoopGroupPool != DEFAULT_WORKER_EVENT_LOOP_GROUP_POOL;
753
    boolean nonProvided = channelFactory == Utils.DEFAULT_SERVER_CHANNEL_FACTORY
1✔
754
        && bossEventLoopGroupPool == DEFAULT_BOSS_EVENT_LOOP_GROUP_POOL
755
        && workerEventLoopGroupPool == DEFAULT_WORKER_EVENT_LOOP_GROUP_POOL;
756
    checkState(
1✔
757
        allProvided || nonProvided,
758
        "All of BossEventLoopGroup, WorkerEventLoopGroup and ChannelType should be provided or "
759
            + "neither should be");
760
  }
1✔
761

762
  @CanIgnoreReturnValue
763
  NettyServerBuilder setTransportTracerFactory(TransportTracer.Factory transportTracerFactory) {
764
    this.transportTracerFactory = transportTracerFactory;
1✔
765
    return this;
1✔
766
  }
767

768
  @CanIgnoreReturnValue
769
  @Override
770
  public NettyServerBuilder useTransportSecurity(File certChain, File privateKey) {
771
    checkState(!freezeProtocolNegotiatorFactory,
×
772
               "Cannot change security when using ServerCredentials");
773
    SslContext sslContext;
774
    try {
775
      sslContext = GrpcSslContexts.forServer(certChain, privateKey).build();
×
776
    } catch (SSLException e) {
×
777
      // This should likely be some other, easier to catch exception.
778
      throw new RuntimeException(e);
×
779
    }
×
780
    protocolNegotiatorFactory = ProtocolNegotiators.serverTlsFactory(sslContext);
×
781
    return this;
×
782
  }
783

784
  @CanIgnoreReturnValue
785
  @Override
786
  public NettyServerBuilder useTransportSecurity(InputStream certChain, InputStream privateKey) {
787
    checkState(!freezeProtocolNegotiatorFactory,
×
788
               "Cannot change security when using ServerCredentials");
789
    SslContext sslContext;
790
    try {
791
      sslContext = GrpcSslContexts.forServer(certChain, privateKey).build();
×
792
    } catch (SSLException e) {
×
793
      // This should likely be some other, easier to catch exception.
794
      throw new RuntimeException(e);
×
795
    }
×
796
    protocolNegotiatorFactory = ProtocolNegotiators.serverTlsFactory(sslContext);
×
797
    return this;
×
798
  }
799
}
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