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

grpc / grpc-java / #19528

28 Oct 2024 05:25PM UTC coverage: 84.59% (-0.04%) from 84.627%
#19528

push

github

web-flow
netty: add soft Metadata size limit enforcement. (#11603)

33914 of 40092 relevant lines covered (84.59%)

0.85 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.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_MAX_CONNECTION_IDLE_NANO = TimeUnit.SECONDS.toNanos(1L);
1✔
81
  private static final long MIN_MAX_CONNECTION_AGE_NANO = TimeUnit.SECONDS.toNanos(1L);
1✔
82
  private static final long AS_LARGE_AS_INFINITE = TimeUnit.DAYS.toNanos(1000L);
1✔
83
  private static final ObjectPool<? extends EventLoopGroup> DEFAULT_BOSS_EVENT_LOOP_GROUP_POOL =
1✔
84
      SharedResourcePool.forResource(Utils.DEFAULT_BOSS_EVENT_LOOP_GROUP);
1✔
85
  private static final ObjectPool<? extends EventLoopGroup> DEFAULT_WORKER_EVENT_LOOP_GROUP_POOL =
1✔
86
      SharedResourcePool.forResource(Utils.DEFAULT_WORKER_EVENT_LOOP_GROUP);
1✔
87

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

706
  NettyServer buildTransportServers(
707
      List<? extends ServerStreamTracer.Factory> streamTracerFactories) {
708
    assertEventLoopsAndChannelType();
1✔
709

710
    ProtocolNegotiator negotiator = protocolNegotiatorFactory.newNegotiator(
1✔
711
        this.serverImplBuilder.getExecutorPool());
1✔
712

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

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

757
  @CanIgnoreReturnValue
758
  NettyServerBuilder setTransportTracerFactory(TransportTracer.Factory transportTracerFactory) {
759
    this.transportTracerFactory = transportTracerFactory;
1✔
760
    return this;
1✔
761
  }
762

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

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