| /* | |
| * | |
| * Copyright 2018 gRPC authors. | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| * | |
| */ | |
| package grpc | |
| import ( | |
| "context" | |
| "net" | |
| "net/url" | |
| "time" | |
| "google.golang.org/grpc/backoff" | |
| "google.golang.org/grpc/channelz" | |
| "google.golang.org/grpc/credentials" | |
| "google.golang.org/grpc/credentials/insecure" | |
| "google.golang.org/grpc/internal" | |
| internalbackoff "google.golang.org/grpc/internal/backoff" | |
| "google.golang.org/grpc/internal/binarylog" | |
| "google.golang.org/grpc/internal/transport" | |
| "google.golang.org/grpc/keepalive" | |
| "google.golang.org/grpc/mem" | |
| "google.golang.org/grpc/resolver" | |
| "google.golang.org/grpc/stats" | |
| ) | |
| const ( | |
| // https://github.com/grpc/proposal/blob/master/A6-client-retries.md#limits-on-retries-and-hedges | |
| defaultMaxCallAttempts = 5 | |
| ) | |
| func init() { | |
| internal.AddGlobalDialOptions = func(opt ...DialOption) { | |
| globalDialOptions = append(globalDialOptions, opt...) | |
| } | |
| internal.ClearGlobalDialOptions = func() { | |
| globalDialOptions = nil | |
| } | |
| internal.AddGlobalPerTargetDialOptions = func(opt any) { | |
| if ptdo, ok := opt.(perTargetDialOption); ok { | |
| globalPerTargetDialOptions = append(globalPerTargetDialOptions, ptdo) | |
| } | |
| } | |
| internal.ClearGlobalPerTargetDialOptions = func() { | |
| globalPerTargetDialOptions = nil | |
| } | |
| internal.WithBinaryLogger = withBinaryLogger | |
| internal.JoinDialOptions = newJoinDialOption | |
| internal.DisableGlobalDialOptions = newDisableGlobalDialOptions | |
| internal.WithBufferPool = withBufferPool | |
| } | |
| // dialOptions configure a Dial call. dialOptions are set by the DialOption | |
| // values passed to Dial. | |
| type dialOptions struct { | |
| unaryInt UnaryClientInterceptor | |
| streamInt StreamClientInterceptor | |
| chainUnaryInts []UnaryClientInterceptor | |
| chainStreamInts []StreamClientInterceptor | |
| compressorV0 Compressor | |
| dc Decompressor | |
| bs internalbackoff.Strategy | |
| block bool | |
| returnLastError bool | |
| timeout time.Duration | |
| authority string | |
| binaryLogger binarylog.Logger | |
| copts transport.ConnectOptions | |
| callOptions []CallOption | |
| channelzParent channelz.Identifier | |
| disableServiceConfig bool | |
| disableRetry bool | |
| disableHealthCheck bool | |
| minConnectTimeout func() time.Duration | |
| defaultServiceConfig *ServiceConfig // defaultServiceConfig is parsed from defaultServiceConfigRawJSON. | |
| defaultServiceConfigRawJSON *string | |
| resolvers []resolver.Builder | |
| idleTimeout time.Duration | |
| defaultScheme string | |
| maxCallAttempts int | |
| enableLocalDNSResolution bool // Specifies if target hostnames should be resolved when proxying is enabled. | |
| useProxy bool // Specifies if a server should be connected via proxy. | |
| clientConnProvider ClientConnProvider | |
| } | |
| // DialOption configures how we set up the connection. | |
| type DialOption interface { | |
| apply(*dialOptions) | |
| } | |
| var globalDialOptions []DialOption | |
| // perTargetDialOption takes a parsed target and returns a dial option to apply. | |
| // | |
| // This gets called after NewClient() parses the target, and allows per target | |
| // configuration set through a returned DialOption. The DialOption will not take | |
| // effect if specifies a resolver builder, as that Dial Option is factored in | |
| // while parsing target. | |
| type perTargetDialOption interface { | |
| // DialOption returns a Dial Option to apply. | |
| DialOptionForTarget(parsedTarget url.URL) DialOption | |
| } | |
| var globalPerTargetDialOptions []perTargetDialOption | |
| // EmptyDialOption does not alter the dial configuration. It can be embedded in | |
| // another structure to build custom dial options. | |
| // | |
| // # Experimental | |
| // | |
| // Notice: This type is EXPERIMENTAL and may be changed or removed in a | |
| // later release. | |
| type EmptyDialOption struct{} | |
| func (EmptyDialOption) apply(*dialOptions) {} | |
| type disableGlobalDialOptions struct{} | |
| func (disableGlobalDialOptions) apply(*dialOptions) {} | |
| // newDisableGlobalDialOptions returns a DialOption that prevents the ClientConn | |
| // from applying the global DialOptions (set via AddGlobalDialOptions). | |
| func newDisableGlobalDialOptions() DialOption { | |
| return &disableGlobalDialOptions{} | |
| } | |
| // funcDialOption wraps a function that modifies dialOptions into an | |
| // implementation of the DialOption interface. | |
| type funcDialOption struct { | |
| f func(*dialOptions) | |
| } | |
| func (fdo *funcDialOption) apply(do *dialOptions) { | |
| fdo.f(do) | |
| } | |
| func newFuncDialOption(f func(*dialOptions)) *funcDialOption { | |
| return &funcDialOption{ | |
| f: f, | |
| } | |
| } | |
| type joinDialOption struct { | |
| opts []DialOption | |
| } | |
| func (jdo *joinDialOption) apply(do *dialOptions) { | |
| for _, opt := range jdo.opts { | |
| opt.apply(do) | |
| } | |
| } | |
| func newJoinDialOption(opts ...DialOption) DialOption { | |
| return &joinDialOption{opts: opts} | |
| } | |
| // WithSharedWriteBuffer allows reusing per-connection transport write buffer. | |
| // If this option is set to true every connection will release the buffer after | |
| // flushing the data on the wire. | |
| // | |
| // Deprecated: shared write buffer is enabled by default. WithSharedWriteBuffer | |
| // will be removed in a future release. | |
| func WithSharedWriteBuffer(val bool) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.copts.SharedWriteBuffer = val | |
| }) | |
| } | |
| // WithWriteBufferSize determines how much data can be batched before doing a | |
| // write on the wire. The default value for this buffer is 32KB. | |
| // | |
| // Zero or negative values will disable the write buffer such that each write | |
| // will be on underlying connection. Note: A Send call may not directly | |
| // translate to a write. | |
| func WithWriteBufferSize(s int) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.copts.WriteBufferSize = s | |
| }) | |
| } | |
| // WithReadBufferSize lets you set the size of read buffer, this determines how | |
| // much data can be read at most for each read syscall. | |
| // | |
| // The default value for this buffer is 32KB. Zero or negative values will | |
| // disable read buffer for a connection so data framer can access the | |
| // underlying conn directly. | |
| func WithReadBufferSize(s int) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.copts.ReadBufferSize = s | |
| }) | |
| } | |
| // WithInitialWindowSize returns a DialOption which sets the value for initial | |
| // window size on a stream. The lower bound for window size is 64K and any value | |
| // smaller than that will be ignored. | |
| func WithInitialWindowSize(s int32) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.copts.InitialWindowSize = s | |
| o.copts.StaticWindowSize = true | |
| }) | |
| } | |
| // WithInitialConnWindowSize returns a DialOption which sets the value for | |
| // initial window size on a connection. The lower bound for window size is 64K | |
| // and any value smaller than that will be ignored. | |
| func WithInitialConnWindowSize(s int32) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.copts.InitialConnWindowSize = s | |
| o.copts.StaticWindowSize = true | |
| }) | |
| } | |
| // WithStaticStreamWindowSize returns a DialOption which sets the initial | |
| // stream window size to the value provided and disables dynamic flow control. | |
| // | |
| // Note that this also disables dynamic flow control for the connection, | |
| // falling back to a default static connection-level window of 64KB. To | |
| // use a larger connection-level window, you must also use the | |
| // [WithStaticConnWindowSize] DialOption. | |
| // | |
| // Most users should not configure static flow control windows unless | |
| // operating in a memory-constrained environment. | |
| func WithStaticStreamWindowSize(s int32) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.copts.InitialWindowSize = s | |
| o.copts.StaticWindowSize = true | |
| }) | |
| } | |
| // WithStaticConnWindowSize returns a DialOption which sets the initial | |
| // connection window size to the value provided and disables dynamic flow | |
| // control. | |
| // | |
| // Note that this also disables dynamic flow control for individual streams, | |
| // falling back to a default static connection-level window of 64KB. To | |
| // explicitly configure the stream-level window size, you must also use the | |
| // [WithStaticStreamWindowSize] DialOption. | |
| // | |
| // Most users should not configure static flow control windows unless | |
| // operating in a memory-constrained environment. | |
| func WithStaticConnWindowSize(s int32) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.copts.InitialConnWindowSize = s | |
| o.copts.StaticWindowSize = true | |
| }) | |
| } | |
| // WithMaxMsgSize returns a DialOption which sets the maximum message size the | |
| // client can receive. | |
| // | |
| // Deprecated: use WithDefaultCallOptions(MaxCallRecvMsgSize(s)) instead. Will | |
| // be supported throughout 1.x. | |
| func WithMaxMsgSize(s int) DialOption { | |
| return WithDefaultCallOptions(MaxCallRecvMsgSize(s)) | |
| } | |
| // WithDefaultCallOptions returns a DialOption which sets the default | |
| // CallOptions for calls over the connection. | |
| func WithDefaultCallOptions(cos ...CallOption) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.callOptions = append(o.callOptions, cos...) | |
| }) | |
| } | |
| // WithCodec returns a DialOption which sets a codec for message marshaling and | |
| // unmarshaling. | |
| // | |
| // Deprecated: use WithDefaultCallOptions(ForceCodec(_)) instead. Will be | |
| // supported throughout 1.x. | |
| func WithCodec(c Codec) DialOption { | |
| return WithDefaultCallOptions(CallCustomCodec(c)) | |
| } | |
| // WithCompressor returns a DialOption which sets a Compressor to use for | |
| // message compression. It has lower priority than the compressor set by the | |
| // UseCompressor CallOption. | |
| // | |
| // Deprecated: use UseCompressor instead. Will be supported throughout 1.x. | |
| func WithCompressor(cp Compressor) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.compressorV0 = cp | |
| }) | |
| } | |
| // WithDecompressor returns a DialOption which sets a Decompressor to use for | |
| // incoming message decompression. If incoming response messages are encoded | |
| // using the decompressor's Type(), it will be used. Otherwise, the message | |
| // encoding will be used to look up the compressor registered via | |
| // encoding.RegisterCompressor, which will then be used to decompress the | |
| // message. If no compressor is registered for the encoding, an Unimplemented | |
| // status error will be returned. | |
| // | |
| // Deprecated: use encoding.RegisterCompressor instead. Will be supported | |
| // throughout 1.x. | |
| func WithDecompressor(dc Decompressor) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.dc = dc | |
| }) | |
| } | |
| // WithConnectParams configures the ClientConn to use the provided ConnectParams | |
| // for creating and maintaining connections to servers. | |
| // | |
| // The backoff configuration specified as part of the ConnectParams overrides | |
| // all defaults specified in | |
| // https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md. Consider | |
| // using the backoff.DefaultConfig as a base, in cases where you want to | |
| // override only a subset of the backoff configuration. | |
| func WithConnectParams(p ConnectParams) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.bs = internalbackoff.Exponential{Config: p.Backoff} | |
| o.minConnectTimeout = func() time.Duration { | |
| return p.MinConnectTimeout | |
| } | |
| }) | |
| } | |
| // WithBackoffMaxDelay configures the dialer to use the provided maximum delay | |
| // when backing off after failed connection attempts. | |
| // | |
| // Deprecated: use WithConnectParams instead. Will be supported throughout 1.x. | |
| func WithBackoffMaxDelay(md time.Duration) DialOption { | |
| return WithBackoffConfig(BackoffConfig{MaxDelay: md}) | |
| } | |
| // WithBackoffConfig configures the dialer to use the provided backoff | |
| // parameters after connection failures. | |
| // | |
| // Deprecated: use WithConnectParams instead. Will be supported throughout 1.x. | |
| func WithBackoffConfig(b BackoffConfig) DialOption { | |
| bc := backoff.DefaultConfig | |
| bc.MaxDelay = b.MaxDelay | |
| return withBackoff(internalbackoff.Exponential{Config: bc}) | |
| } | |
| // withBackoff sets the backoff strategy used for connectRetryNum after a failed | |
| // connection attempt. | |
| // | |
| // This can be exported if arbitrary backoff strategies are allowed by gRPC. | |
| func withBackoff(bs internalbackoff.Strategy) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.bs = bs | |
| }) | |
| } | |
| // WithBlock returns a DialOption which makes callers of Dial block until the | |
| // underlying connection is up. Without this, Dial returns immediately and | |
| // connecting the server happens in background. | |
| // | |
| // Use of this feature is not recommended. For more information, please see: | |
| // https://github.com/grpc/grpc-go/blob/master/Documentation/anti-patterns.md | |
| // | |
| // Deprecated: this DialOption is not supported by NewClient. | |
| // Will be supported throughout 1.x. | |
| func WithBlock() DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.block = true | |
| }) | |
| } | |
| // WithReturnConnectionError returns a DialOption which makes the client connection | |
| // return a string containing both the last connection error that occurred and | |
| // the context.DeadlineExceeded error. | |
| // Implies WithBlock() | |
| // | |
| // Use of this feature is not recommended. For more information, please see: | |
| // https://github.com/grpc/grpc-go/blob/master/Documentation/anti-patterns.md | |
| // | |
| // Deprecated: this DialOption is not supported by NewClient. | |
| // Will be supported throughout 1.x. | |
| func WithReturnConnectionError() DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.block = true | |
| o.returnLastError = true | |
| }) | |
| } | |
| // WithInsecure returns a DialOption which disables transport security for this | |
| // ClientConn. Under the hood, it uses insecure.NewCredentials(). | |
| // | |
| // Note that using this DialOption with per-RPC credentials (through | |
| // WithCredentialsBundle or WithPerRPCCredentials) which require transport | |
| // security is incompatible and will cause RPCs to fail. | |
| // | |
| // Deprecated: use WithTransportCredentials and insecure.NewCredentials() | |
| // instead. Will be supported throughout 1.x. | |
| func WithInsecure() DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.copts.TransportCredentials = insecure.NewCredentials() | |
| }) | |
| } | |
| // WithNoProxy returns a DialOption which disables the use of proxies for this | |
| // ClientConn. This is ignored if WithDialer or WithContextDialer are used. | |
| // | |
| // # Experimental | |
| // | |
| // Notice: This API is EXPERIMENTAL and may be changed or removed in a | |
| // later release. | |
| func WithNoProxy() DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.useProxy = false | |
| }) | |
| } | |
| // WithLocalDNSResolution forces local DNS name resolution even when a proxy is | |
| // specified in the environment. By default, the server name is provided | |
| // directly to the proxy as part of the CONNECT handshake. This is ignored if | |
| // WithNoProxy is used. | |
| // | |
| // # Experimental | |
| // | |
| // Notice: This API is EXPERIMENTAL and may be changed or removed in a | |
| // later release. | |
| func WithLocalDNSResolution() DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.enableLocalDNSResolution = true | |
| }) | |
| } | |
| // WithTransportCredentials returns a DialOption which configures a connection | |
| // level security credentials (e.g., TLS/SSL). This should not be used together | |
| // with WithCredentialsBundle. | |
| func WithTransportCredentials(creds credentials.TransportCredentials) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.copts.TransportCredentials = creds | |
| }) | |
| } | |
| // WithPerRPCCredentials returns a DialOption which sets credentials and places | |
| // auth state on each outbound RPC. | |
| func WithPerRPCCredentials(creds credentials.PerRPCCredentials) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.copts.PerRPCCredentials = append(o.copts.PerRPCCredentials, creds) | |
| }) | |
| } | |
| // WithCredentialsBundle returns a DialOption to set a credentials bundle for | |
| // the ClientConn.WithCreds. This should not be used together with | |
| // WithTransportCredentials. | |
| // | |
| // # Experimental | |
| // | |
| // Notice: This API is EXPERIMENTAL and may be changed or removed in a | |
| // later release. | |
| func WithCredentialsBundle(b credentials.Bundle) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.copts.CredsBundle = b | |
| }) | |
| } | |
| // WithTimeout returns a DialOption that configures a timeout for dialing a | |
| // ClientConn initially. This is valid if and only if WithBlock() is present. | |
| // | |
| // Deprecated: this DialOption is not supported by NewClient. | |
| // Will be supported throughout 1.x. | |
| func WithTimeout(d time.Duration) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.timeout = d | |
| }) | |
| } | |
| // WithContextDialer returns a DialOption that sets a dialer to create | |
| // connections. If FailOnNonTempDialError() is set to true, and an error is | |
| // returned by f, gRPC checks the error's Temporary() method to decide if it | |
| // should try to reconnect to the network address. | |
| // | |
| // Note that gRPC by default performs name resolution on the target passed to | |
| // NewClient. To bypass name resolution and cause the target string to be | |
| // passed directly to the dialer here instead, use the "passthrough" resolver | |
| // by specifying it in the target string, e.g. "passthrough:target". | |
| // | |
| // Note: All supported releases of Go (as of December 2023) override the OS | |
| // defaults for TCP keepalive time and interval to 15s. To enable TCP keepalive | |
| // with OS defaults for keepalive time and interval, use a net.Dialer that sets | |
| // the KeepAlive field to a negative value, and sets the SO_KEEPALIVE socket | |
| // option to true from the Control field. For a concrete example of how to do | |
| // this, see internal.NetDialerWithTCPKeepalive(). | |
| // | |
| // For more information, please see [issue 23459] in the Go GitHub repo. | |
| // | |
| // [issue 23459]: https://github.com/golang/go/issues/23459 | |
| func WithContextDialer(f func(context.Context, string) (net.Conn, error)) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.copts.Dialer = f | |
| }) | |
| } | |
| // WithDialer returns a DialOption that specifies a function to use for dialing | |
| // network addresses. If FailOnNonTempDialError() is set to true, and an error | |
| // is returned by f, gRPC checks the error's Temporary() method to decide if it | |
| // should try to reconnect to the network address. | |
| // | |
| // Deprecated: use WithContextDialer instead. Will be supported throughout | |
| // 1.x. | |
| func WithDialer(f func(string, time.Duration) (net.Conn, error)) DialOption { | |
| return WithContextDialer( | |
| func(ctx context.Context, addr string) (net.Conn, error) { | |
| if deadline, ok := ctx.Deadline(); ok { | |
| return f(addr, time.Until(deadline)) | |
| } | |
| return f(addr, 0) | |
| }) | |
| } | |
| // WithStatsHandler returns a DialOption that specifies the stats handler for | |
| // all the RPCs and underlying network connections in this ClientConn. | |
| func WithStatsHandler(h stats.Handler) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| if h == nil { | |
| logger.Error("ignoring nil parameter in grpc.WithStatsHandler ClientOption") | |
| // Do not allow a nil stats handler, which would otherwise cause | |
| // panics. | |
| return | |
| } | |
| o.copts.StatsHandlers = append(o.copts.StatsHandlers, h) | |
| }) | |
| } | |
| // withBinaryLogger returns a DialOption that specifies the binary logger for | |
| // this ClientConn. | |
| func withBinaryLogger(bl binarylog.Logger) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.binaryLogger = bl | |
| }) | |
| } | |
| // FailOnNonTempDialError returns a DialOption that specifies if gRPC fails on | |
| // non-temporary dial errors. If f is true, and dialer returns a non-temporary | |
| // error, gRPC will fail the connection to the network address and won't try to | |
| // reconnect. The default value of FailOnNonTempDialError is false. | |
| // | |
| // FailOnNonTempDialError only affects the initial dial, and does not do | |
| // anything useful unless you are also using WithBlock(). | |
| // | |
| // Use of this feature is not recommended. For more information, please see: | |
| // https://github.com/grpc/grpc-go/blob/master/Documentation/anti-patterns.md | |
| // | |
| // Deprecated: this DialOption is not supported by NewClient. | |
| // This API may be changed or removed in a | |
| // later release. | |
| func FailOnNonTempDialError(f bool) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.copts.FailOnNonTempDialError = f | |
| }) | |
| } | |
| // WithUserAgent returns a DialOption that specifies a user agent string for all | |
| // the RPCs. | |
| func WithUserAgent(s string) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.copts.UserAgent = s + " " + grpcUA | |
| }) | |
| } | |
| // WithKeepaliveParams returns a DialOption that specifies keepalive parameters | |
| // for the client transport. | |
| // | |
| // Keepalive is disabled by default. | |
| func WithKeepaliveParams(kp keepalive.ClientParameters) DialOption { | |
| if kp.Time < internal.KeepaliveMinPingTime { | |
| logger.Warningf("Adjusting keepalive ping interval to minimum period of %v", internal.KeepaliveMinPingTime) | |
| kp.Time = internal.KeepaliveMinPingTime | |
| } | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.copts.KeepaliveParams = kp | |
| }) | |
| } | |
| // WithUnaryInterceptor returns a DialOption that specifies the interceptor for | |
| // unary RPCs. | |
| func WithUnaryInterceptor(f UnaryClientInterceptor) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.unaryInt = f | |
| }) | |
| } | |
| // WithChainUnaryInterceptor returns a DialOption that specifies the chained | |
| // interceptor for unary RPCs. The first interceptor will be the outer most, | |
| // while the last interceptor will be the inner most wrapper around the real call. | |
| // All interceptors added by this method will be chained, and the interceptor | |
| // defined by WithUnaryInterceptor will always be prepended to the chain. | |
| func WithChainUnaryInterceptor(interceptors ...UnaryClientInterceptor) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.chainUnaryInts = append(o.chainUnaryInts, interceptors...) | |
| }) | |
| } | |
| // WithStreamInterceptor returns a DialOption that specifies the interceptor for | |
| // streaming RPCs. | |
| func WithStreamInterceptor(f StreamClientInterceptor) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.streamInt = f | |
| }) | |
| } | |
| // WithChainStreamInterceptor returns a DialOption that specifies the chained | |
| // interceptor for streaming RPCs. The first interceptor will be the outer most, | |
| // while the last interceptor will be the inner most wrapper around the real call. | |
| // All interceptors added by this method will be chained, and the interceptor | |
| // defined by WithStreamInterceptor will always be prepended to the chain. | |
| func WithChainStreamInterceptor(interceptors ...StreamClientInterceptor) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.chainStreamInts = append(o.chainStreamInts, interceptors...) | |
| }) | |
| } | |
| // WithAuthority returns a DialOption that specifies the value to be used as the | |
| // :authority pseudo-header and as the server name in authentication handshake. | |
| // This overrides all other ways of setting authority on the channel, but can be | |
| // overridden per-call by using grpc.CallAuthority. | |
| func WithAuthority(a string) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.authority = a | |
| }) | |
| } | |
| // WithChannelzParentID returns a DialOption that specifies the channelz ID of | |
| // current ClientConn's parent. This function is used in nested channel creation | |
| // (e.g. grpclb dial). | |
| // | |
| // # Experimental | |
| // | |
| // Notice: This API is EXPERIMENTAL and may be changed or removed in a | |
| // later release. | |
| func WithChannelzParentID(c channelz.Identifier) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.channelzParent = c | |
| }) | |
| } | |
| // WithDisableServiceConfig returns a DialOption that causes gRPC to ignore any | |
| // service config provided by the resolver and provides a hint to the resolver | |
| // to not fetch service configs. | |
| // | |
| // Note that this dial option only disables service config from resolver. If | |
| // default service config is provided, gRPC will use the default service config. | |
| func WithDisableServiceConfig() DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.disableServiceConfig = true | |
| }) | |
| } | |
| // WithDefaultServiceConfig returns a DialOption that configures the default | |
| // service config, which will be used in cases where: | |
| // | |
| // 1. WithDisableServiceConfig is also used, or | |
| // | |
| // 2. The name resolver does not provide a service config or provides an | |
| // invalid service config. | |
| // | |
| // The parameter s is the JSON representation of the default service config. | |
| // For more information about service configs, see: | |
| // https://github.com/grpc/grpc/blob/master/doc/service_config.md | |
| // For a simple example of usage, see: | |
| // examples/features/load_balancing/client/main.go | |
| func WithDefaultServiceConfig(s string) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.defaultServiceConfigRawJSON = &s | |
| }) | |
| } | |
| // WithDisableRetry returns a DialOption that disables retries, even if the | |
| // service config enables them. This does not impact transparent retries, which | |
| // will happen automatically if no data is written to the wire or if the RPC is | |
| // unprocessed by the remote server. | |
| func WithDisableRetry() DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.disableRetry = true | |
| }) | |
| } | |
| // MaxHeaderListSizeDialOption is a DialOption that specifies the maximum | |
| // (uncompressed) size of header list that the client is prepared to accept. | |
| type MaxHeaderListSizeDialOption struct { | |
| MaxHeaderListSize uint32 | |
| } | |
| func (o MaxHeaderListSizeDialOption) apply(do *dialOptions) { | |
| do.copts.MaxHeaderListSize = &o.MaxHeaderListSize | |
| } | |
| // WithMaxHeaderListSize returns a DialOption that specifies the maximum | |
| // (uncompressed) size of header list that the client is prepared to accept. | |
| func WithMaxHeaderListSize(s uint32) DialOption { | |
| return MaxHeaderListSizeDialOption{ | |
| MaxHeaderListSize: s, | |
| } | |
| } | |
| // WithDisableHealthCheck disables the LB channel health checking for all | |
| // SubConns of this ClientConn. | |
| // | |
| // # Experimental | |
| // | |
| // Notice: This API is EXPERIMENTAL and may be changed or removed in a | |
| // later release. | |
| func WithDisableHealthCheck() DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.disableHealthCheck = true | |
| }) | |
| } | |
| func defaultDialOptions() dialOptions { | |
| return dialOptions{ | |
| copts: transport.ConnectOptions{ | |
| ReadBufferSize: defaultReadBufSize, | |
| WriteBufferSize: defaultWriteBufSize, | |
| SharedWriteBuffer: true, | |
| UserAgent: grpcUA, | |
| BufferPool: mem.DefaultBufferPool(), | |
| }, | |
| bs: internalbackoff.DefaultExponential, | |
| idleTimeout: 30 * time.Minute, | |
| defaultScheme: "dns", | |
| maxCallAttempts: defaultMaxCallAttempts, | |
| useProxy: true, | |
| enableLocalDNSResolution: false, | |
| } | |
| } | |
| // withMinConnectDeadline specifies the function that clientconn uses to | |
| // get minConnectDeadline. This can be used to make connection attempts happen | |
| // faster/slower. | |
| // | |
| // For testing purpose only. | |
| func withMinConnectDeadline(f func() time.Duration) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.minConnectTimeout = f | |
| }) | |
| } | |
| // withDefaultScheme is used to allow Dial to use "passthrough" as the default | |
| // name resolver, while NewClient uses "dns" otherwise. | |
| func withDefaultScheme(s string) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.defaultScheme = s | |
| }) | |
| } | |
| // WithResolvers allows a list of resolver implementations to be registered | |
| // locally with the ClientConn without needing to be globally registered via | |
| // resolver.Register. They will be matched against the scheme used for the | |
| // current Dial only, and will take precedence over the global registry. | |
| // | |
| // # Experimental | |
| // | |
| // Notice: This API is EXPERIMENTAL and may be changed or removed in a | |
| // later release. | |
| func WithResolvers(rs ...resolver.Builder) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.resolvers = append(o.resolvers, rs...) | |
| }) | |
| } | |
| // WithIdleTimeout returns a DialOption that configures an idle timeout for the | |
| // channel. If the channel is idle for the configured timeout, i.e there are no | |
| // ongoing RPCs and no new RPCs are initiated, the channel will enter idle mode | |
| // and as a result the name resolver and load balancer will be shut down. The | |
| // channel will exit idle mode when the Connect() method is called or when an | |
| // RPC is initiated. | |
| // | |
| // A default timeout of 30 minutes will be used if this dial option is not set | |
| // at dial time and idleness can be disabled by passing a timeout of zero. | |
| // | |
| // # Experimental | |
| // | |
| // Notice: This API is EXPERIMENTAL and may be changed or removed in a | |
| // later release. | |
| func WithIdleTimeout(d time.Duration) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.idleTimeout = d | |
| }) | |
| } | |
| // WithMaxCallAttempts returns a DialOption that configures the maximum number | |
| // of attempts per call (including retries and hedging) using the channel. | |
| // Service owners may specify a higher value for these parameters, but higher | |
| // values will be treated as equal to the maximum value by the client | |
| // implementation. This mitigates security concerns related to the service | |
| // config being transferred to the client via DNS. | |
| // | |
| // A value of 5 will be used if this dial option is not set or n < 2. | |
| func WithMaxCallAttempts(n int) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| if n < 2 { | |
| n = defaultMaxCallAttempts | |
| } | |
| o.maxCallAttempts = n | |
| }) | |
| } | |
| func withBufferPool(bufferPool mem.BufferPool) DialOption { | |
| return newFuncDialOption(func(o *dialOptions) { | |
| o.copts.BufferPool = bufferPool | |
| }) | |
| } |