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

grpc / grpc-java / #18908

20 Nov 2023 09:54PM CUT coverage: 88.231% (-0.02%) from 88.249%
#18908

push

github

ejona86
netty: Add option to limit RST_STREAM rate

The behavior purposefully mirrors that of Netty's
AbstractHttp2ConnectionHandlerBuilder.decoderEnforceMaxRstFramesPerWindow().
That API is not available to our code as we extend the
Http2ConnectionHandler, but we want our API to be able to delegate to
Netty's in the future if that ever becomes possible.

30311 of 34354 relevant lines covered (88.23%)

0.88 hits per line

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

57.38
/../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.ServerBuilder;
36
import io.grpc.ServerCredentials;
37
import io.grpc.ServerStreamTracer;
38
import io.grpc.internal.FixedObjectPool;
39
import io.grpc.internal.GrpcUtil;
40
import io.grpc.internal.InternalServer;
41
import io.grpc.internal.KeepAliveManager;
42
import io.grpc.internal.ObjectPool;
43
import io.grpc.internal.ServerImplBuilder;
44
import io.grpc.internal.ServerImplBuilder.ClientTransportServersBuilder;
45
import io.grpc.internal.SharedResourcePool;
46
import io.grpc.internal.TransportTracer;
47
import io.netty.channel.ChannelFactory;
48
import io.netty.channel.ChannelOption;
49
import io.netty.channel.EventLoopGroup;
50
import io.netty.channel.ReflectiveChannelFactory;
51
import io.netty.channel.ServerChannel;
52
import io.netty.channel.socket.nio.NioServerSocketChannel;
53
import io.netty.handler.ssl.SslContext;
54
import java.io.File;
55
import java.io.InputStream;
56
import java.net.InetSocketAddress;
57
import java.net.SocketAddress;
58
import java.util.ArrayList;
59
import java.util.HashMap;
60
import java.util.List;
61
import java.util.Map;
62
import java.util.concurrent.TimeUnit;
63
import javax.net.ssl.SSLException;
64

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

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

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

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

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

93
  private TransportTracer.Factory transportTracerFactory = TransportTracer.getDefaultFactory();
1✔
94
  private ChannelFactory<? extends ServerChannel> channelFactory =
1✔
95
      Utils.DEFAULT_SERVER_CHANNEL_FACTORY;
96
  private final Map<ChannelOption<?>, Object> channelOptions = new HashMap<>();
1✔
97
  private final Map<ChannelOption<?>, Object> childChannelOptions = new HashMap<>();
1✔
98
  private ObjectPool<? extends EventLoopGroup> bossEventLoopGroupPool =
1✔
99
      DEFAULT_BOSS_EVENT_LOOP_GROUP_POOL;
100
  private ObjectPool<? extends EventLoopGroup> workerEventLoopGroupPool =
1✔
101
      DEFAULT_WORKER_EVENT_LOOP_GROUP_POOL;
102
  private boolean forceHeapBuffer;
103
  private ProtocolNegotiator.ServerFactory protocolNegotiatorFactory;
104
  private final boolean freezeProtocolNegotiatorFactory;
105
  private int maxConcurrentCallsPerConnection = Integer.MAX_VALUE;
1✔
106
  private boolean autoFlowControl = true;
1✔
107
  private int flowControlWindow = DEFAULT_FLOW_CONTROL_WINDOW;
1✔
108
  private int maxMessageSize = DEFAULT_MAX_MESSAGE_SIZE;
1✔
109
  private int maxHeaderListSize = 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
      return buildTransportServers(streamTracerFactories);
1✔
170
    }
171
  }
172

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

500
  /**
501
   * Sets a custom keepalive time, the delay time for sending next keepalive ping. An unreasonably
502
   * small value might be increased, and {@code Long.MAX_VALUE} nano seconds or an unreasonably
503
   * large value will disable keepalive.
504
   *
505
   * @since 1.3.0
506
   */
507
  @CanIgnoreReturnValue
508
  @Override
509
  public NettyServerBuilder keepAliveTime(long keepAliveTime, TimeUnit timeUnit) {
510
    checkArgument(keepAliveTime > 0L, "keepalive time must be positive:%s", keepAliveTime);
1✔
511
    keepAliveTimeInNanos = timeUnit.toNanos(keepAliveTime);
×
512
    keepAliveTimeInNanos = KeepAliveManager.clampKeepAliveTimeInNanos(keepAliveTimeInNanos);
×
513
    if (keepAliveTimeInNanos >= AS_LARGE_AS_INFINITE) {
×
514
      // Bump keepalive time to infinite. This disables keep alive.
515
      keepAliveTimeInNanos = SERVER_KEEPALIVE_TIME_NANOS_DISABLED;
×
516
    }
517
    if (keepAliveTimeInNanos < MIN_KEEPALIVE_TIME_NANO) {
×
518
      // Bump keepalive time.
519
      keepAliveTimeInNanos = MIN_KEEPALIVE_TIME_NANO;
×
520
    }
521
    return this;
×
522
  }
523

524
  /**
525
   * Sets a custom keepalive timeout, the timeout for keepalive ping requests. An unreasonably small
526
   * value might be increased.
527
   *
528
   * @since 1.3.0
529
   */
530
  @CanIgnoreReturnValue
531
  @Override
532
  public NettyServerBuilder keepAliveTimeout(long keepAliveTimeout, TimeUnit timeUnit) {
533
    checkArgument(keepAliveTimeout > 0L, "keepalive timeout must be positive: %s",
1✔
534
        keepAliveTimeout);
535
    keepAliveTimeoutInNanos = timeUnit.toNanos(keepAliveTimeout);
×
536
    keepAliveTimeoutInNanos =
×
537
        KeepAliveManager.clampKeepAliveTimeoutInNanos(keepAliveTimeoutInNanos);
×
538
    if (keepAliveTimeoutInNanos < MIN_KEEPALIVE_TIMEOUT_NANO) {
×
539
      // Bump keepalive timeout.
540
      keepAliveTimeoutInNanos = MIN_KEEPALIVE_TIMEOUT_NANO;
×
541
    }
542
    return this;
×
543
  }
544

545
  /**
546
   * Sets a custom max connection idle time, connection being idle for longer than which will be
547
   * gracefully terminated. Idleness duration is defined since the most recent time the number of
548
   * outstanding RPCs became zero or the connection establishment. An unreasonably small value might
549
   * be increased. {@code Long.MAX_VALUE} nano seconds or an unreasonably large value will disable
550
   * max connection idle.
551
   *
552
   * @since 1.4.0
553
   */
554
  @CanIgnoreReturnValue
555
  @Override
556
  public NettyServerBuilder maxConnectionIdle(long maxConnectionIdle, TimeUnit timeUnit) {
557
    checkArgument(maxConnectionIdle > 0L, "max connection idle must be positive: %s",
1✔
558
        maxConnectionIdle);
559
    maxConnectionIdleInNanos = timeUnit.toNanos(maxConnectionIdle);
×
560
    if (maxConnectionIdleInNanos >= AS_LARGE_AS_INFINITE) {
×
561
      maxConnectionIdleInNanos = MAX_CONNECTION_IDLE_NANOS_DISABLED;
×
562
    }
563
    if (maxConnectionIdleInNanos < MIN_MAX_CONNECTION_IDLE_NANO) {
×
564
      maxConnectionIdleInNanos = MIN_MAX_CONNECTION_IDLE_NANO;
×
565
    }
566
    return this;
×
567
  }
568

569
  /**
570
   * Sets a custom max connection age, connection lasting longer than which will be gracefully
571
   * terminated. An unreasonably small value might be increased.  A random jitter of +/-10% will be
572
   * added to it. {@code Long.MAX_VALUE} nano seconds or an unreasonably large value will disable
573
   * max connection age.
574
   *
575
   * @since 1.3.0
576
   */
577
  @CanIgnoreReturnValue
578
  @Override
579
  public NettyServerBuilder maxConnectionAge(long maxConnectionAge, TimeUnit timeUnit) {
580
    checkArgument(maxConnectionAge > 0L, "max connection age must be positive: %s",
1✔
581
        maxConnectionAge);
582
    maxConnectionAgeInNanos = timeUnit.toNanos(maxConnectionAge);
×
583
    if (maxConnectionAgeInNanos >= AS_LARGE_AS_INFINITE) {
×
584
      maxConnectionAgeInNanos = MAX_CONNECTION_AGE_NANOS_DISABLED;
×
585
    }
586
    if (maxConnectionAgeInNanos < MIN_MAX_CONNECTION_AGE_NANO) {
×
587
      maxConnectionAgeInNanos = MIN_MAX_CONNECTION_AGE_NANO;
×
588
    }
589
    return this;
×
590
  }
591

592
  /**
593
   * Sets a custom grace time for the graceful connection termination. Once the max connection age
594
   * is reached, RPCs have the grace time to complete. RPCs that do not complete in time will be
595
   * cancelled, allowing the connection to terminate. {@code Long.MAX_VALUE} nano seconds or an
596
   * unreasonably large value are considered infinite.
597
   *
598
   * @see #maxConnectionAge(long, TimeUnit)
599
   * @since 1.3.0
600
   */
601
  @CanIgnoreReturnValue
602
  @Override
603
  public NettyServerBuilder maxConnectionAgeGrace(long maxConnectionAgeGrace, TimeUnit timeUnit) {
604
    checkArgument(maxConnectionAgeGrace >= 0L, "max connection age grace must be non-negative: %s",
1✔
605
        maxConnectionAgeGrace);
606
    maxConnectionAgeGraceInNanos = timeUnit.toNanos(maxConnectionAgeGrace);
×
607
    if (maxConnectionAgeGraceInNanos >= AS_LARGE_AS_INFINITE) {
×
608
      maxConnectionAgeGraceInNanos = MAX_CONNECTION_AGE_GRACE_NANOS_INFINITE;
×
609
    }
610
    return this;
×
611
  }
612

613
  /**
614
   * Specify the most aggressive keep-alive time clients are permitted to configure. The server will
615
   * try to detect clients exceeding this rate and when detected will forcefully close the
616
   * connection. The default is 5 minutes.
617
   *
618
   * <p>Even though a default is defined that allows some keep-alives, clients must not use
619
   * keep-alive without approval from the service owner. Otherwise, they may experience failures in
620
   * the future if the service becomes more restrictive. When unthrottled, keep-alives can cause a
621
   * significant amount of traffic and CPU usage, so clients and servers should be conservative in
622
   * what they use and accept.
623
   *
624
   * @see #permitKeepAliveWithoutCalls(boolean)
625
   * @since 1.3.0
626
   */
627
  @CanIgnoreReturnValue
628
  @Override
629
  public NettyServerBuilder permitKeepAliveTime(long keepAliveTime, TimeUnit timeUnit) {
630
    checkArgument(keepAliveTime >= 0, "permit keepalive time must be non-negative: %s",
1✔
631
        keepAliveTime);
632
    permitKeepAliveTimeInNanos = timeUnit.toNanos(keepAliveTime);
×
633
    return this;
×
634
  }
635

636
  /**
637
   * Sets whether to allow clients to send keep-alive HTTP/2 PINGs even if there are no outstanding
638
   * RPCs on the connection. Defaults to {@code false}.
639
   *
640
   * @see #permitKeepAliveTime(long, TimeUnit)
641
   * @since 1.3.0
642
   */
643
  @CanIgnoreReturnValue
644
  @Override
645
  public NettyServerBuilder permitKeepAliveWithoutCalls(boolean permit) {
646
    permitKeepAliveWithoutCalls = permit;
×
647
    return this;
×
648
  }
649

650
  /**
651
   * Limits the rate of incoming RST_STREAM frames per connection to maxRstStream per
652
   * secondsPerWindow. When exceeded on a connection, the connection is closed. This can reduce the
653
   * impact of an attacker continually resetting RPCs before they complete, when combined with TLS
654
   * and {@link #maxConcurrentCallsPerConnection(int)}.
655
   *
656
   * <p>gRPC clients send RST_STREAM when they cancel RPCs, so some RST_STREAMs are normal and
657
   * setting this too low can cause errors for legimitate clients.
658
   *
659
   * <p>By default there is no limit.
660
   *
661
   * @param maxRstStream the positive limit of RST_STREAM frames per connection per period, or
662
   *     {@code Integer.MAX_VALUE} for unlimited
663
   * @param secondsPerWindow the positive number of seconds per period
664
   */
665
  @CanIgnoreReturnValue
666
  public NettyServerBuilder maxRstFramesPerWindow(int maxRstStream, int secondsPerWindow) {
667
    checkArgument(maxRstStream > 0, "maxRstStream must be positive");
×
668
    checkArgument(secondsPerWindow > 0, "secondsPerWindow must be positive");
×
669
    if (maxRstStream == Integer.MAX_VALUE) {
×
670
      maxRstStream = MAX_RST_COUNT_DISABLED;
×
671
    }
672
    this.maxRstCount = maxRstStream;
×
673
    this.maxRstPeriodNanos = TimeUnit.SECONDS.toNanos(secondsPerWindow);
×
674
    return this;
×
675
  }
676

677
  /** Sets the EAG attributes available to protocol negotiators. Not for general use. */
678
  void eagAttributes(Attributes eagAttributes) {
679
    this.eagAttributes = checkNotNull(eagAttributes, "eagAttributes");
1✔
680
  }
1✔
681

682
  NettyServer buildTransportServers(
683
      List<? extends ServerStreamTracer.Factory> streamTracerFactories) {
684
    assertEventLoopsAndChannelType();
1✔
685

686
    ProtocolNegotiator negotiator = protocolNegotiatorFactory.newNegotiator(
1✔
687
        this.serverImplBuilder.getExecutorPool());
1✔
688

689
    return new NettyServer(
1✔
690
        listenAddresses, channelFactory, channelOptions, childChannelOptions,
691
        bossEventLoopGroupPool, workerEventLoopGroupPool, forceHeapBuffer, negotiator,
692
        streamTracerFactories, transportTracerFactory, maxConcurrentCallsPerConnection,
693
        autoFlowControl, flowControlWindow, maxMessageSize, maxHeaderListSize,
694
        keepAliveTimeInNanos, keepAliveTimeoutInNanos,
695
        maxConnectionIdleInNanos, maxConnectionAgeInNanos,
696
        maxConnectionAgeGraceInNanos, permitKeepAliveWithoutCalls, permitKeepAliveTimeInNanos,
697
        maxRstCount, maxRstPeriodNanos, eagAttributes, this.serverImplBuilder.getChannelz());
1✔
698
  }
699

700
  @VisibleForTesting
701
  void assertEventLoopsAndChannelType() {
702
    boolean allProvided = channelFactory != Utils.DEFAULT_SERVER_CHANNEL_FACTORY
1✔
703
        && bossEventLoopGroupPool != DEFAULT_BOSS_EVENT_LOOP_GROUP_POOL
704
        && workerEventLoopGroupPool != DEFAULT_WORKER_EVENT_LOOP_GROUP_POOL;
705
    boolean nonProvided = channelFactory == Utils.DEFAULT_SERVER_CHANNEL_FACTORY
1✔
706
        && bossEventLoopGroupPool == DEFAULT_BOSS_EVENT_LOOP_GROUP_POOL
707
        && workerEventLoopGroupPool == DEFAULT_WORKER_EVENT_LOOP_GROUP_POOL;
708
    checkState(
1✔
709
        allProvided || nonProvided,
710
        "All of BossEventLoopGroup, WorkerEventLoopGroup and ChannelType should be provided or "
711
            + "neither should be");
712
  }
1✔
713

714
  @CanIgnoreReturnValue
715
  NettyServerBuilder setTransportTracerFactory(TransportTracer.Factory transportTracerFactory) {
716
    this.transportTracerFactory = transportTracerFactory;
1✔
717
    return this;
1✔
718
  }
719

720
  @CanIgnoreReturnValue
721
  @Override
722
  public NettyServerBuilder useTransportSecurity(File certChain, File privateKey) {
723
    checkState(!freezeProtocolNegotiatorFactory,
×
724
               "Cannot change security when using ServerCredentials");
725
    SslContext sslContext;
726
    try {
727
      sslContext = GrpcSslContexts.forServer(certChain, privateKey).build();
×
728
    } catch (SSLException e) {
×
729
      // This should likely be some other, easier to catch exception.
730
      throw new RuntimeException(e);
×
731
    }
×
732
    protocolNegotiatorFactory = ProtocolNegotiators.serverTlsFactory(sslContext);
×
733
    return this;
×
734
  }
735

736
  @CanIgnoreReturnValue
737
  @Override
738
  public NettyServerBuilder useTransportSecurity(InputStream certChain, InputStream privateKey) {
739
    checkState(!freezeProtocolNegotiatorFactory,
×
740
               "Cannot change security when using ServerCredentials");
741
    SslContext sslContext;
742
    try {
743
      sslContext = GrpcSslContexts.forServer(certChain, privateKey).build();
×
744
    } catch (SSLException e) {
×
745
      // This should likely be some other, easier to catch exception.
746
      throw new RuntimeException(e);
×
747
    }
×
748
    protocolNegotiatorFactory = ProtocolNegotiators.serverTlsFactory(sslContext);
×
749
    return this;
×
750
  }
751
}
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