@@ -68,6 +68,7 @@ public final class InstantiatingGrpcChannelProvider implements TransportChannelP
6868 private final String endpoint ;
6969 @ Nullable private final GrpcInterceptorProvider interceptorProvider ;
7070 @ Nullable private final Integer maxInboundMessageSize ;
71+ @ Nullable private final Integer maxInboundMetadataSize ;
7172 @ Nullable private final Duration keepAliveTime ;
7273 @ Nullable private final Duration keepAliveTimeout ;
7374 @ Nullable private final Boolean keepAliveWithoutCalls ;
@@ -80,6 +81,7 @@ private InstantiatingGrpcChannelProvider(Builder builder) {
8081 this .endpoint = builder .endpoint ;
8182 this .interceptorProvider = builder .interceptorProvider ;
8283 this .maxInboundMessageSize = builder .maxInboundMessageSize ;
84+ this .maxInboundMetadataSize = builder .maxInboundMetadataSize ;
8385 this .keepAliveTime = builder .keepAliveTime ;
8486 this .keepAliveTimeout = builder .keepAliveTimeout ;
8587 this .keepAliveWithoutCalls = builder .keepAliveWithoutCalls ;
@@ -181,12 +183,38 @@ private ManagedChannel createSingleChannel() throws IOException {
181183 int port = Integer .parseInt (endpoint .substring (colon + 1 ));
182184 String serviceAddress = endpoint .substring (0 , colon );
183185
184- ManagedChannelBuilder builder =
185- ManagedChannelBuilder .forAddress (serviceAddress , port )
186- .intercept (headerInterceptor )
187- .intercept (metadataHandlerInterceptor )
188- .userAgent (headerInterceptor .getUserAgentHeader ())
189- .executor (executor );
186+ // TODO(hzyi): Use NettyChannelBuilder when maxInboundMetadataSize is specified to unblock Spanner.
187+ // Change to ManagedChannelBuilder when https://github.com/grpc/grpc-java/issues/4050 is
188+ // resolved.
189+ ManagedChannelBuilder builder ;
190+ if (maxInboundMetadataSize != null ) {
191+ try {
192+ Class .forName ("io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder" );
193+ builder =
194+ io .grpc .netty .shaded .io .grpc .netty .NettyChannelBuilder .forAddress (serviceAddress , port )
195+ .maxHeaderListSize (maxInboundMetadataSize );
196+ } catch (ClassNotFoundException e ) {
197+ try {
198+ Class .forName ("io.grpc.netty.NettyChannelBuilder" );
199+ builder =
200+ io .grpc .netty .NettyChannelBuilder .forAddress (serviceAddress , port )
201+ .maxHeaderListSize (maxInboundMetadataSize );
202+ } catch (ClassNotFoundException ex ) {
203+ throw new RuntimeException (
204+ "Unable to create the channel because neither"
205+ + " \" io.grpc.netty.NettyChannelBuilder\" nor"
206+ + " \" io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder\" is found." );
207+ }
208+ }
209+ } else {
210+ builder = ManagedChannelBuilder .forAddress (serviceAddress , port );
211+ }
212+
213+ builder
214+ .intercept (headerInterceptor )
215+ .intercept (metadataHandlerInterceptor )
216+ .userAgent (headerInterceptor .getUserAgentHeader ())
217+ .executor (executor );
190218 if (maxInboundMessageSize != null ) {
191219 builder .maxInboundMessageSize (maxInboundMessageSize );
192220 }
@@ -226,6 +254,12 @@ public Boolean getKeepAliveWithoutCalls() {
226254 return keepAliveWithoutCalls ;
227255 }
228256
257+ /** The maximum metadata size allowed to be received on the channel. */
258+ @ BetaApi ("The surface for maximum metadata size is not stable yet and may change in the future." )
259+ public Integer getMaxInboundMetadataSize () {
260+ return maxInboundMetadataSize ;
261+ }
262+
229263 @ Override
230264 public boolean shouldAutoClose () {
231265 return true ;
@@ -246,6 +280,7 @@ public static final class Builder {
246280 private String endpoint ;
247281 @ Nullable private GrpcInterceptorProvider interceptorProvider ;
248282 @ Nullable private Integer maxInboundMessageSize ;
283+ @ Nullable private Integer maxInboundMetadataSize ;
249284 @ Nullable private Duration keepAliveTime ;
250285 @ Nullable private Duration keepAliveTimeout ;
251286 @ Nullable private Boolean keepAliveWithoutCalls ;
@@ -262,6 +297,7 @@ private Builder(InstantiatingGrpcChannelProvider provider) {
262297 this .endpoint = provider .endpoint ;
263298 this .interceptorProvider = provider .interceptorProvider ;
264299 this .maxInboundMessageSize = provider .maxInboundMessageSize ;
300+ this .maxInboundMetadataSize = provider .maxInboundMetadataSize ;
265301 this .keepAliveTime = provider .keepAliveTime ;
266302 this .keepAliveTimeout = provider .keepAliveTimeout ;
267303 this .keepAliveWithoutCalls = provider .keepAliveWithoutCalls ;
@@ -333,6 +369,21 @@ public Integer getMaxInboundMessageSize() {
333369 return maxInboundMessageSize ;
334370 }
335371
372+ /** The maximum metadata size allowed to be received on the channel. */
373+ @ BetaApi (
374+ "The surface for maximum metadata size is not stable yet and may change in the future." )
375+ public Builder setMaxInboundMetadataSize (Integer max ) {
376+ this .maxInboundMetadataSize = max ;
377+ return this ;
378+ }
379+
380+ /** The maximum metadata size allowed to be received on the channel. */
381+ @ BetaApi (
382+ "The surface for maximum metadata size is not stable yet and may change in the future." )
383+ public Integer getMaxInboundMetadataSize () {
384+ return maxInboundMetadataSize ;
385+ }
386+
336387 /** The time without read activity before sending a keepalive ping. */
337388 public Builder setKeepAliveTime (Duration duration ) {
338389 this .keepAliveTime = duration ;
0 commit comments