aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/grpc/impl/codegen/grpc_types.h4
-rw-r--r--src/objective-c/GRPCClient/GRPCCall.h145
-rw-r--r--src/objective-c/GRPCClient/GRPCCall.m253
-rw-r--r--src/objective-c/GRPCClient/GRPCCallOptions.h317
-rw-r--r--src/objective-c/GRPCClient/GRPCCallOptions.m431
5 files changed, 1105 insertions, 45 deletions
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index 3ce88a8264..4cf13edca9 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -347,6 +347,10 @@ typedef struct {
/** If set to non zero, surfaces the user agent string to the server. User
agent is surfaced by default. */
#define GRPC_ARG_SURFACE_USER_AGENT "grpc.surface_user_agent"
+/** gRPC Objective-C channel pooling domain string. */
+#define GRPC_ARG_CHANNEL_POOL_DOMAIN "grpc.channel_pooling_domain"
+/** gRPC Objective-C channel pooling id. */
+#define GRPC_ARG_CHANNEL_ID "grpc.channel_id"
/** \} */
/** Result of a grpc call. If the caller satisfies the prerequisites of a
diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h
index e0ef8b1391..3f6ec75c04 100644
--- a/src/objective-c/GRPCClient/GRPCCall.h
+++ b/src/objective-c/GRPCClient/GRPCCall.h
@@ -37,6 +37,10 @@
#include <AvailabilityMacros.h>
+#include "GRPCCallOptions.h"
+
+@class GRPCCallOptions;
+
#pragma mark gRPC errors
/** Domain of NSError objects produced by gRPC. */
@@ -140,42 +144,123 @@ typedef NS_ENUM(NSUInteger, GRPCErrorCode) {
};
/**
- * Safety remark of a gRPC method as defined in RFC 2616 Section 9.1
- */
-typedef NS_ENUM(NSUInteger, GRPCCallSafety) {
- /** Signal that there is no guarantees on how the call affects the server state. */
- GRPCCallSafetyDefault = 0,
- /** Signal that the call is idempotent. gRPC is free to use PUT verb. */
- GRPCCallSafetyIdempotentRequest = 1,
- /** Signal that the call is cacheable and will not affect server state. gRPC is free to use GET
- verb. */
- GRPCCallSafetyCacheableRequest = 2,
-};
-
-/**
* Keys used in |NSError|'s |userInfo| dictionary to store the response headers and trailers sent by
* the server.
*/
extern id const kGRPCHeadersKey;
extern id const kGRPCTrailersKey;
+/** An object can implement this protocol to receive responses from server from a call. */
+@protocol GRPCResponseHandler
+@optional
+/** Issued when initial metadata is received from the server. */
+- (void)receivedInitialMetadata:(NSDictionary *)initialMetadata;
+/**
+ * Issued when a message is received from the server. The message may be raw data from the server
+ * (when using \a GRPCCall2 directly) or deserialized proto object (when using \a ProtoRPC).
+ */
+- (void)receivedMessage:(id)message;
+/**
+ * Issued when a call finished. If the call finished successfully, \a error is nil and \a
+ * trainingMetadata consists any trailing metadata received from the server. Otherwise, \a error
+ * is non-nil and contains the corresponding error information, including gRPC error codes and
+ * error descriptions.
+ */
+- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error;
+
+/**
+ * All the responses must be issued to a user-provided dispatch queue. This property specifies the
+ * dispatch queue to be used for issuing the notifications.
+ */
+@property(atomic, readonly) dispatch_queue_t dispatchQueue;
+
+@end
+
+/**
+ * Call related parameters. These parameters are automatically specified by Protobuf. If directly
+ * using the \a GRPCCall2 class, users should specify these parameters manually.
+ */
+@interface GRPCRequestOptions : NSObject<NSCopying>
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/** Initialize with all properties. */
+- (instancetype)initWithHost:(NSString *)host path:(NSString *)path safety:(GRPCCallSafety)safety;
+
+/** The host serving the RPC service. */
+@property(copy, readonly) NSString *host;
+/** The path to the RPC call. */
+@property(copy, readonly) NSString *path;
+/**
+ * Specify whether the call is idempotent or cachable. gRPC may select different HTTP verbs for the
+ * call based on this information.
+ */
+@property(readonly) GRPCCallSafety safety;
+
+@end
+
#pragma mark GRPCCall
-/** Represents a single gRPC remote call. */
-@interface GRPCCall : GRXWriter
+/**
+ * A \a GRPCCall2 object represents an RPC call.
+ */
+@interface GRPCCall2 : NSObject
+
+- (instancetype)init NS_UNAVAILABLE;
/**
- * The authority for the RPC. If nil, the default authority will be used. This property must be nil
- * when Cronet transport is enabled.
+ * Designated initializer for a call.
+ * \param requestOptions Protobuf generated parameters for the call.
+ * \param handler The object to which responses should be issed.
+ * \param callOptions Options for the call.
*/
-@property(atomic, copy, readwrite) NSString *serverName;
+- (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions
+ handler:(id<GRPCResponseHandler>)handler
+ callOptions:(GRPCCallOptions *)callOptions NS_DESIGNATED_INITIALIZER;
+/**
+ * Convevience initializer for a call that uses default call options.
+ */
+- (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions
+ handler:(id<GRPCResponseHandler>)handler;
/**
- * The timeout for the RPC call in seconds. If set to 0, the call will not timeout. If set to
- * positive, the gRPC call returns with status GRPCErrorCodeDeadlineExceeded if it is not completed
- * within \a timeout seconds. A negative value is not allowed.
+ * Starts the call. Can only be called once.
*/
-@property NSTimeInterval timeout;
+- (void)start;
+
+/**
+ * Cancel the request of this call at best effort; notifies the server that the RPC should be
+ * cancelled, and issue callback to the user with an error code CANCELED if the call is not
+ * finished.
+ */
+- (void)cancel;
+
+/**
+ * Send a message to the server. Data are sent as raw bytes in gRPC message frames.
+ */
+- (void)writeWithData:(NSData *)data;
+
+/**
+ * Finish the RPC request and half-close the call. The server may still send messages and/or
+ * trailers to the client.
+ */ -(void)finish;
+
+/**
+ * Get a copy of the original call options.
+ */
+@property(readonly, copy) GRPCCallOptions *callOptions;
+
+/** Get a copy of the original request options. */
+@property(readonly, copy) GRPCRequestOptions *requestOptions;
+
+@end
+
+/**
+ * This interface is deprecated. Please use \a GRPCcall2.
+ *
+ * Represents a single gRPC remote call.
+ */
+@interface GRPCCall : GRXWriter
/**
* The container of the request headers of an RPC conforms to this protocol, which is a subset of
@@ -236,7 +321,7 @@ extern id const kGRPCTrailersKey;
*/
- (instancetype)initWithHost:(NSString *)host
path:(NSString *)path
- requestsWriter:(GRXWriter *)requestsWriter NS_DESIGNATED_INITIALIZER;
+ requestsWriter:(GRXWriter *)requestWriter;
/**
* Finishes the request side of this call, notifies the server that the RPC should be cancelled, and
@@ -245,21 +330,13 @@ extern id const kGRPCTrailersKey;
- (void)cancel;
/**
- * Set the call flag for a specific host path.
- *
- * Host parameter should not contain the scheme (http:// or https://), only the name or IP addr
- * and the port number, for example @"localhost:5050".
+ * The following methods are deprecated.
*/
+ (void)setCallSafety:(GRPCCallSafety)callSafety host:(NSString *)host path:(NSString *)path;
-
-/**
- * Set the dispatch queue to be used for callbacks.
- *
- * This configuration is only effective before the call starts.
- */
+@property(atomic, copy, readwrite) NSString *serverName;
+@property NSTimeInterval timeout;
- (void)setResponseDispatchQueue:(dispatch_queue_t)queue;
-// TODO(jcanizales): Let specify a deadline. As a category of GRXWriter?
@end
#pragma mark Backwards compatibiity
diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m
index 084fbdeb49..519f91e522 100644
--- a/src/objective-c/GRPCClient/GRPCCall.m
+++ b/src/objective-c/GRPCClient/GRPCCall.m
@@ -20,13 +20,16 @@
#import "GRPCCall+OAuth2.h"
+#import <RxLibrary/GRXBufferedPipe.h>
#import <RxLibrary/GRXConcurrentWriteable.h>
#import <RxLibrary/GRXImmediateSingleWriter.h>
+#import <RxLibrary/GRXWriter+Immediate.h>
#include <grpc/grpc.h>
#include <grpc/support/time.h>
-#import "private/GRPCConnectivityMonitor.h"
+#import "GRPCCallOptions.h"
#import "private/GRPCHost.h"
+#import "private/GRPCConnectivityMonitor.h"
#import "private/GRPCRequestHeaders.h"
#import "private/GRPCWrappedCall.h"
#import "private/NSData+GRPC.h"
@@ -52,6 +55,165 @@ const char *kCFStreamVarName = "grpc_cfstream";
@property(atomic, strong) NSDictionary *responseHeaders;
@property(atomic, strong) NSDictionary *responseTrailers;
@property(atomic) BOOL isWaitingForToken;
+
+- (instancetype)initWithHost:(NSString *)host
+ path:(NSString *)path
+ callSafety:(GRPCCallSafety)safety
+ requestsWriter:(GRXWriter *)requestsWriter
+ callOptions:(GRPCCallOptions *)callOptions;
+
+@end
+
+@implementation GRPCRequestOptions
+
+- (instancetype)initWithHost:(NSString *)host path:(NSString *)path safety:(GRPCCallSafety)safety {
+ if ((self = [super init])) {
+ _host = host;
+ _path = path;
+ _safety = safety;
+ }
+ return self;
+}
+
+- (id)copyWithZone:(NSZone *)zone {
+ GRPCRequestOptions *request =
+ [[GRPCRequestOptions alloc] initWithHost:[_host copy] path:[_path copy] safety:_safety];
+
+ return request;
+}
+
+@end
+
+@implementation GRPCCall2 {
+ GRPCCallOptions *_callOptions;
+ id<GRPCResponseHandler> _handler;
+
+ GRPCCall *_call;
+ BOOL _initialMetadataPublished;
+ GRXBufferedPipe *_pipe;
+ dispatch_queue_t _dispatchQueue;
+}
+
+- (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions
+ handler:(id<GRPCResponseHandler>)handler
+ callOptions:(GRPCCallOptions *)callOptions {
+ if (!requestOptions || !requestOptions.host || !requestOptions.path) {
+ [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil."];
+ }
+
+ if ((self = [super init])) {
+ _requestOptions = [requestOptions copy];
+ _callOptions = [callOptions copy];
+ _handler = handler;
+ _initialMetadataPublished = NO;
+ _pipe = [GRXBufferedPipe pipe];
+ _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
+ }
+
+ return self;
+}
+
+- (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions
+ handler:(id<GRPCResponseHandler>)handler {
+ return [self initWithRequestOptions:requestOptions handler:handler callOptions:nil];
+}
+
+- (void)start {
+ dispatch_async(_dispatchQueue, ^{
+ if (!self->_callOptions) {
+ self->_callOptions = [[GRPCCallOptions alloc] init];
+ }
+
+ self->_call = [[GRPCCall alloc] initWithHost:self->_requestOptions.host
+ path:self->_requestOptions.path
+ callSafety:self->_requestOptions.safety
+ requestsWriter:self->_pipe
+ callOptions:self->_callOptions];
+ if (self->_callOptions.initialMetadata) {
+ [self->_call.requestHeaders addEntriesFromDictionary:self->_callOptions.initialMetadata];
+ }
+ id<GRXWriteable> responseWriteable = [[GRXWriteable alloc] initWithValueHandler:^(id value) {
+ dispatch_async(self->_dispatchQueue, ^{
+ if (self->_handler) {
+ id<GRPCResponseHandler> handler = self->_handler;
+ NSDictionary *headers = nil;
+ if (!self->_initialMetadataPublished) {
+ headers = self->_call.responseHeaders;
+ self->_initialMetadataPublished = YES;
+ }
+ if (headers) {
+ dispatch_async(handler.dispatchQueue, ^{
+ [handler receivedInitialMetadata:headers];
+ });
+ }
+ if (value) {
+ dispatch_async(handler.dispatchQueue, ^{
+ [handler receivedMessage:value];
+ });
+ }
+ }
+ });
+ }
+ completionHandler:^(NSError *errorOrNil) {
+ dispatch_async(self->_dispatchQueue, ^{
+ if (self->_handler) {
+ id<GRPCResponseHandler> handler = self->_handler;
+ NSDictionary *headers = nil;
+ if (!self->_initialMetadataPublished) {
+ headers = self->_call.responseHeaders;
+ self->_initialMetadataPublished = YES;
+ }
+ if (headers) {
+ dispatch_async(handler.dispatchQueue, ^{
+ [handler receivedInitialMetadata:headers];
+ });
+ }
+ dispatch_async(handler.dispatchQueue, ^{
+ [handler closedWithTrailingMetadata:self->_call.responseTrailers error:errorOrNil];
+ });
+ }
+ });
+ }];
+ [self->_call startWithWriteable:responseWriteable];
+ });
+}
+
+- (void)cancel {
+ dispatch_async(_dispatchQueue, ^{
+ if (self->_call) {
+ [self->_call cancel];
+ self->_call = nil;
+ }
+ if (self->_handler) {
+ id<GRPCResponseHandler> handler = self->_handler;
+ dispatch_async(handler.dispatchQueue, ^{
+ [handler closedWithTrailingMetadata:nil
+ error:[NSError errorWithDomain:kGRPCErrorDomain
+ code:GRPCErrorCodeCancelled
+ userInfo:@{
+ NSLocalizedDescriptionKey :
+ @"Canceled by app"
+ }]];
+ });
+ self->_handler = nil;
+ }
+ });
+}
+
+- (void)writeWithData:(NSData *)data {
+ dispatch_async(_dispatchQueue, ^{
+ [self->_pipe writeValue:data];
+ });
+}
+
+- (void)finish {
+ dispatch_async(_dispatchQueue, ^{
+ if (self->_call) {
+ [self->_pipe writesFinishedWithError:nil];
+ }
+ });
+}
+
@end
// The following methods of a C gRPC call object aren't reentrant, and thus
@@ -75,6 +237,8 @@ const char *kCFStreamVarName = "grpc_cfstream";
NSString *_host;
NSString *_path;
+ GRPCCallSafety _callSafety;
+ GRPCCallOptions *_callOptions;
GRPCWrappedCall *_wrappedCall;
GRPCConnectivityMonitor *_connectivityMonitor;
@@ -113,6 +277,9 @@ const char *kCFStreamVarName = "grpc_cfstream";
// Whether the call is finished. If it is, should not call finishWithError again.
BOOL _finished;
+
+ // The OAuth2 token fetched from a token provider.
+ NSString *_fetchedOauth2AccessToken;
}
@synthesize state = _state;
@@ -156,6 +323,18 @@ const char *kCFStreamVarName = "grpc_cfstream";
- (instancetype)initWithHost:(NSString *)host
path:(NSString *)path
requestsWriter:(GRXWriter *)requestWriter {
+ return [self initWithHost:host
+ path:path
+ callSafety:GRPCCallSafetyDefault
+ requestsWriter:requestWriter
+ callOptions:nil];
+}
+
+- (instancetype)initWithHost:(NSString *)host
+ path:(NSString *)path
+ callSafety:(GRPCCallSafety)safety
+ requestsWriter:(GRXWriter *)requestWriter
+ callOptions:(GRPCCallOptions *)callOptions {
if (!host || !path) {
[NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil."];
}
@@ -166,6 +345,8 @@ const char *kCFStreamVarName = "grpc_cfstream";
if ((self = [super init])) {
_host = [host copy];
_path = [path copy];
+ _callSafety = safety;
+ _callOptions = [callOptions copy];
// Serial queue to invoke the non-reentrant methods of the grpc_call object.
_callQueue = dispatch_queue_create("io.grpc.call", NULL);
@@ -317,11 +498,36 @@ const char *kCFStreamVarName = "grpc_cfstream";
#pragma mark Send headers
-- (void)sendHeaders:(NSDictionary *)headers {
+- (void)sendHeaders {
+ // TODO (mxyan): Remove after deprecated methods are removed
+ uint32_t callSafetyFlags;
+ switch (_callSafety) {
+ case GRPCCallSafetyDefault:
+ callSafetyFlags = 0;
+ break;
+ case GRPCCallSafetyIdempotentRequest:
+ callSafetyFlags = GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST;
+ break;
+ case GRPCCallSafetyCacheableRequest:
+ callSafetyFlags = GRPC_INITIAL_METADATA_CACHEABLE_REQUEST;
+ break;
+ default:
+ [NSException raise:NSInvalidArgumentException format:@"Invalid call safety value."];
+ }
+ uint32_t callFlag = callSafetyFlags;
+
+ NSMutableDictionary *headers = _requestHeaders;
+ if (_fetchedOauth2AccessToken != nil) {
+ headers[@"authorization"] = [kBearerPrefix stringByAppendingString:_fetchedOauth2AccessToken];
+ } else if (_callOptions.oauth2AccessToken != nil) {
+ headers[@"authorization"] =
+ [kBearerPrefix stringByAppendingString:_callOptions.oauth2AccessToken];
+ }
+
// TODO(jcanizales): Add error handlers for async failures
GRPCOpSendMetadata *op = [[GRPCOpSendMetadata alloc]
initWithMetadata:headers
- flags:[GRPCCall callFlagsForHost:_host path:_path]
+ flags:callFlag
handler:nil]; // No clean-up needed after SEND_INITIAL_METADATA
if (!_unaryCall) {
[_wrappedCall startBatchWithOperations:@[ op ]];
@@ -458,13 +664,10 @@ const char *kCFStreamVarName = "grpc_cfstream";
_responseWriteable =
[[GRXConcurrentWriteable alloc] initWithWriteable:writeable dispatchQueue:_responseQueue];
- _wrappedCall = [[GRPCWrappedCall alloc] initWithHost:_host
- serverName:_serverName
- path:_path
- timeout:_timeout];
+ _wrappedCall = [[GRPCWrappedCall alloc] initWithHost:_host path:_path callOptions:_callOptions];
NSAssert(_wrappedCall, @"Error allocating RPC objects. Low memory?");
- [self sendHeaders:_requestHeaders];
+ [self sendHeaders];
[self invokeCall];
// Connectivity monitor is not required for CFStream
@@ -486,15 +689,43 @@ const char *kCFStreamVarName = "grpc_cfstream";
// that the life of the instance is determined by this retain cycle.
_retainSelf = self;
- if (self.tokenProvider != nil) {
+ if (_callOptions == nil) {
+ GRPCMutableCallOptions *callOptions;
+ if ([GRPCHost isHostConfigured:_host]) {
+ GRPCHost *hostConfig = [GRPCHost hostWithAddress:_host];
+ callOptions = hostConfig.callOptions;
+ } else {
+ callOptions = [[GRPCMutableCallOptions alloc] init];
+ }
+ if (_serverName != nil) {
+ callOptions.serverAuthority = _serverName;
+ }
+ if (_timeout != 0) {
+ callOptions.timeout = _timeout;
+ }
+ uint32_t callFlags = [GRPCCall callFlagsForHost:_host path:_path];
+ if (callFlags != 0) {
+ if (callFlags == GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) {
+ _callSafety = GRPCCallSafetyIdempotentRequest;
+ } else if (callFlags == GRPC_INITIAL_METADATA_CACHEABLE_REQUEST) {
+ _callSafety = GRPCCallSafetyCacheableRequest;
+ }
+ }
+
+ id<GRPCAuthorizationProtocol> tokenProvider = self.tokenProvider;
+ if (tokenProvider != nil) {
+ callOptions.authTokenProvider = tokenProvider;
+ }
+ _callOptions = callOptions;
+ }
+ if (_callOptions.authTokenProvider != nil) {
self.isWaitingForToken = YES;
__weak typeof(self) weakSelf = self;
[self.tokenProvider getTokenWithHandler:^(NSString *token) {
typeof(self) strongSelf = weakSelf;
if (strongSelf && strongSelf.isWaitingForToken) {
if (token) {
- NSString *t = [kBearerPrefix stringByAppendingString:token];
- strongSelf.requestHeaders[kAuthorizationHeader] = t;
+ strongSelf->_fetchedOauth2AccessToken = token;
}
[strongSelf startCallWithWriteable:writeable];
strongSelf.isWaitingForToken = NO;
diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h
new file mode 100644
index 0000000000..75b320ca6d
--- /dev/null
+++ b/src/objective-c/GRPCClient/GRPCCallOptions.h
@@ -0,0 +1,317 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+/**
+ * Safety remark of a gRPC method as defined in RFC 2616 Section 9.1
+ */
+typedef NS_ENUM(NSUInteger, GRPCCallSafety) {
+ /** Signal that there is no guarantees on how the call affects the server state. */
+ GRPCCallSafetyDefault = 0,
+ /** Signal that the call is idempotent. gRPC is free to use PUT verb. */
+ GRPCCallSafetyIdempotentRequest = 1,
+ /** Signal that the call is cacheable and will not affect server state. gRPC is free to use GET
+ verb. */
+ GRPCCallSafetyCacheableRequest = 2,
+};
+
+// Compression algorithm to be used by a gRPC call
+typedef NS_ENUM(NSInteger, GRPCCompressAlgorithm) {
+ GRPCCompressNone = 0,
+ GRPCCompressDeflate,
+ GRPCCompressGzip,
+ GRPCStreamCompressGzip,
+};
+
+// The transport to be used by a gRPC call
+typedef NS_ENUM(NSInteger, GRPCTransportType) {
+ // gRPC internal HTTP/2 stack with BoringSSL
+ GRPCTransportTypeDefault = 0,
+ // Cronet stack
+ GRPCTransportTypeCronet,
+ // Insecure channel. FOR TEST ONLY!
+ GRPCTransportTypeInsecure,
+};
+
+@protocol GRPCAuthorizationProtocol
+- (void)getTokenWithHandler:(void (^)(NSString *token))hander;
+@end
+
+@interface GRPCCallOptions : NSObject<NSCopying, NSMutableCopying>
+
+// Call parameters
+/**
+ * The authority for the RPC. If nil, the default authority will be used.
+ *
+ * Note: This property must be nil when Cronet transport is enabled.
+ * Note: This property cannot be used to validate a self-signed server certificate. It control the
+ * :authority header field of the call and performs an extra check that server's certificate
+ * matches the :authority header.
+ */
+@property(readonly) NSString *serverAuthority;
+
+/**
+ * The timeout for the RPC call in seconds. If set to 0, the call will not timeout. If set to
+ * positive, the gRPC call returns with status GRPCErrorCodeDeadlineExceeded if it is not completed
+ * within \a timeout seconds. A negative value is not allowed.
+ */
+@property(readonly) NSTimeInterval timeout;
+
+// OAuth2 parameters. Users of gRPC may specify one of the following two parameters.
+
+/**
+ * The OAuth2 access token string. The string is prefixed with "Bearer " then used as value of the
+ * request's "authorization" header field. This parameter should not be used simultaneously with
+ * \a authTokenProvider.
+ */
+@property(copy, readonly) NSString *oauth2AccessToken;
+
+/**
+ * The interface to get the OAuth2 access token string. gRPC will attempt to acquire token when
+ * initiating the call. This parameter should not be used simultaneously with \a oauth2AccessToken.
+ */
+@property(readonly) id<GRPCAuthorizationProtocol> authTokenProvider;
+
+/**
+ * Initial metadata key-value pairs that should be included in the request.
+ */
+@property(copy, readwrite) NSDictionary *initialMetadata;
+
+// Channel parameters; take into account of channel signature.
+
+/**
+ * Custom string that is prefixed to a request's user-agent header field before gRPC's internal
+ * user-agent string.
+ */
+@property(copy, readonly) NSString *userAgentPrefix;
+
+/**
+ * The size limit for the response received from server. If it is exceeded, an error with status
+ * code GRPCErrorCodeResourceExhausted is returned.
+ */
+@property(readonly) NSUInteger responseSizeLimit;
+
+/**
+ * The compression algorithm to be used by the gRPC call. For more details refer to
+ * https://github.com/grpc/grpc/blob/master/doc/compression.md
+ */
+@property(readonly) GRPCCompressAlgorithm compressAlgorithm;
+
+/**
+ * Enable/Disable gRPC call's retry feature. The default is enabled. For details of this feature
+ * refer to
+ * https://github.com/grpc/proposal/blob/master/A6-client-retries.md
+ */
+@property(readonly) BOOL enableRetry;
+
+/**
+ * HTTP/2 keep-alive feature. The parameter \a keepaliveInterval specifies the interval between two
+ * PING frames. The parameter \a keepaliveTimeout specifies the length of the period for which the
+ * call should wait for PING ACK. If PING ACK is not received after this period, the call fails.
+ */
+@property(readonly) NSTimeInterval keepaliveInterval;
+@property(readonly) NSTimeInterval keepaliveTimeout;
+
+// Parameters for connection backoff. For details of gRPC's backoff behavior, refer to
+// https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md
+@property(readonly) NSTimeInterval connectMinTimeout;
+@property(readonly) NSTimeInterval connectInitialBackoff;
+@property(readonly) NSTimeInterval connectMaxBackoff;
+
+/**
+ * Specify channel args to be used for this call. For a list of channel args available, see
+ * grpc/grpc_types.h
+ */
+@property(copy, readonly) NSDictionary *additionalChannelArgs;
+
+// Parameters for SSL authentication.
+
+/**
+ * PEM format root certifications that is trusted. If set to nil, gRPC uses a list of default
+ * root certificates.
+ */
+@property(copy, readonly) NSString *pemRootCert;
+
+/**
+ * PEM format private key for client authentication, if required by the server.
+ */
+@property(copy, readonly) NSString *pemPrivateKey;
+
+/**
+ * PEM format certificate chain for client authentication, if required by the server.
+ */
+@property(copy, readonly) NSString *pemCertChain;
+
+/**
+ * Select the transport type to be used for this call.
+ */
+@property(readonly) GRPCTransportType transportType;
+
+/**
+ * Override the hostname during the TLS hostname validation process.
+ */
+@property(copy, readonly) NSString *hostNameOverride;
+
+/**
+ * Parameter used for internal logging.
+ */
+@property(readonly) id logContext;
+
+/**
+ * A string that specify the domain where channel is being cached. Channels with different domains
+ * will not get cached to the same connection.
+ */
+@property(copy, readonly) NSString *channelPoolDomain;
+
+/**
+ * Channel id allows a call to force creating a new channel (connection) rather than using a cached
+ * channel. Calls using distinct channelId will not get cached to the same connection.
+ */
+@property(readonly) NSUInteger channelId;
+
+@end
+
+@interface GRPCMutableCallOptions : GRPCCallOptions<NSCopying, NSMutableCopying>
+
+// Call parameters
+/**
+ * The authority for the RPC. If nil, the default authority will be used.
+ *
+ * Note: This property must be nil when Cronet transport is enabled.
+ * Note: This property cannot be used to validate a self-signed server certificate. It control the
+ * :authority header field of the call and performs an extra check that server's certificate
+ * matches the :authority header.
+ */
+@property(readwrite) NSString *serverAuthority;
+
+/**
+ * The timeout for the RPC call in seconds. If set to 0, the call will not timeout. If set to
+ * positive, the gRPC call returns with status GRPCErrorCodeDeadlineExceeded if it is not completed
+ * within \a timeout seconds. A negative value is not allowed.
+ */
+@property(readwrite) NSTimeInterval timeout;
+
+// OAuth2 parameters. Users of gRPC may specify one of the following two parameters.
+
+/**
+ * The OAuth2 access token string. The string is prefixed with "Bearer " then used as value of the
+ * request's "authorization" header field. This parameter should not be used simultaneously with
+ * \a authTokenProvider.
+ */
+@property(copy, readwrite) NSString *oauth2AccessToken;
+
+/**
+ * The interface to get the OAuth2 access token string. gRPC will attempt to acquire token when
+ * initiating the call. This parameter should not be used simultaneously with \a oauth2AccessToken.
+ */
+@property(readwrite) id<GRPCAuthorizationProtocol> authTokenProvider;
+
+// Channel parameters; take into account of channel signature.
+
+/**
+ * Custom string that is prefixed to a request's user-agent header field before gRPC's internal
+ * user-agent string.
+ */
+@property(copy, readwrite) NSString *userAgentPrefix;
+
+/**
+ * The size limit for the response received from server. If it is exceeded, an error with status
+ * code GRPCErrorCodeResourceExhausted is returned.
+ */
+@property(readwrite) NSUInteger responseSizeLimit;
+
+/**
+ * The compression algorithm to be used by the gRPC call. For more details refer to
+ * https://github.com/grpc/grpc/blob/master/doc/compression.md
+ */
+@property(readwrite) GRPCCompressAlgorithm compressAlgorithm;
+
+/**
+ * Enable/Disable gRPC call's retry feature. The default is enabled. For details of this feature
+ * refer to
+ * https://github.com/grpc/proposal/blob/master/A6-client-retries.md
+ */
+@property(readwrite) BOOL enableRetry;
+
+/**
+ * HTTP/2 keep-alive feature. The parameter \a keepaliveInterval specifies the interval between two
+ * PING frames. The parameter \a keepaliveTimeout specifies the length of the period for which the
+ * call should wait for PING ACK. If PING ACK is not received after this period, the call fails.
+ */
+@property(readwrite) NSTimeInterval keepaliveInterval;
+@property(readwrite) NSTimeInterval keepaliveTimeout;
+
+// Parameters for connection backoff. For details of gRPC's backoff behavior, refer to
+// https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md
+@property(readwrite) NSTimeInterval connectMinTimeout;
+@property(readwrite) NSTimeInterval connectInitialBackoff;
+@property(readwrite) NSTimeInterval connectMaxBackoff;
+
+/**
+ * Specify channel args to be used for this call. For a list of channel args available, see
+ * grpc/grpc_types.h
+ */
+@property(copy, readwrite) NSDictionary *additionalChannelArgs;
+
+// Parameters for SSL authentication.
+
+/**
+ * PEM format root certifications that is trusted. If set to nil, gRPC uses a list of default
+ * root certificates.
+ */
+@property(copy, readwrite) NSString *pemRootCert;
+
+/**
+ * PEM format private key for client authentication, if required by the server.
+ */
+@property(copy, readwrite) NSString *pemPrivateKey;
+
+/**
+ * PEM format certificate chain for client authentication, if required by the server.
+ */
+@property(copy, readwrite) NSString *pemCertChain;
+
+/**
+ * Select the transport type to be used for this call.
+ */
+@property(readwrite) GRPCTransportType transportType;
+
+/**
+ * Override the hostname during the TLS hostname validation process.
+ */
+@property(copy, readwrite) NSString *hostNameOverride;
+
+/**
+ * Parameter used for internal logging.
+ */
+@property(copy, readwrite) id logContext;
+
+/**
+ * A string that specify the domain where channel is being cached. Channels with different domains
+ * will not get cached to the same connection.
+ */
+@property(copy, readwrite) NSString *channelPoolDomain;
+
+/**
+ * Channel id allows a call to force creating a new channel (connection) rather than using a cached
+ * channel. Calls using distinct channelId will not get cached to the same connection.
+ */
+@property(readwrite) NSUInteger channelId;
+
+@end
diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m
new file mode 100644
index 0000000000..ee76c2a642
--- /dev/null
+++ b/src/objective-c/GRPCClient/GRPCCallOptions.m
@@ -0,0 +1,431 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#import "GRPCCallOptions.h"
+
+static NSString *const kDefaultServerAuthority = nil;
+static const NSTimeInterval kDefaultTimeout = 0;
+static NSDictionary *const kDefaultInitialMetadata = nil;
+static NSString *const kDefaultUserAgentPrefix = nil;
+static const NSUInteger kDefaultResponseSizeLimit = 0;
+static const GRPCCompressAlgorithm kDefaultCompressAlgorithm = GRPCCompressNone;
+static const BOOL kDefaultEnableRetry = YES;
+static const NSTimeInterval kDefaultKeepaliveInterval = 0;
+static const NSTimeInterval kDefaultKeepaliveTimeout = 0;
+static const NSTimeInterval kDefaultConnectMinTimeout = 0;
+static const NSTimeInterval kDefaultConnectInitialBackoff = 0;
+static const NSTimeInterval kDefaultConnectMaxBackoff = 0;
+static NSDictionary *const kDefaultAdditionalChannelArgs = nil;
+static NSString *const kDefaultPemRootCert = nil;
+static NSString *const kDefaultPemPrivateKey = nil;
+static NSString *const kDefaultPemCertChain = nil;
+static NSString *const kDefaultOauth2AccessToken = nil;
+static const id<GRPCAuthorizationProtocol> kDefaultAuthTokenProvider = nil;
+static const GRPCTransportType kDefaultTransportType = GRPCTransportTypeDefault;
+static NSString *const kDefaultHostNameOverride = nil;
+static const id kDefaultLogContext = nil;
+static NSString *kDefaultChannelPoolDomain = nil;
+static NSUInteger kDefaultChannelId = 0;
+
+@implementation GRPCCallOptions {
+ @protected
+ NSString *_serverAuthority;
+ NSTimeInterval _timeout;
+ NSString *_oauth2AccessToken;
+ id<GRPCAuthorizationProtocol> _authTokenProvider;
+ NSDictionary *_initialMetadata;
+ NSString *_userAgentPrefix;
+ NSUInteger _responseSizeLimit;
+ GRPCCompressAlgorithm _compressAlgorithm;
+ BOOL _enableRetry;
+ NSTimeInterval _keepaliveInterval;
+ NSTimeInterval _keepaliveTimeout;
+ NSTimeInterval _connectMinTimeout;
+ NSTimeInterval _connectInitialBackoff;
+ NSTimeInterval _connectMaxBackoff;
+ NSDictionary *_additionalChannelArgs;
+ NSString *_pemRootCert;
+ NSString *_pemPrivateKey;
+ NSString *_pemCertChain;
+ GRPCTransportType _transportType;
+ NSString *_hostNameOverride;
+ id _logContext;
+ NSString *_channelPoolDomain;
+ NSUInteger _channelId;
+}
+
+@synthesize serverAuthority = _serverAuthority;
+@synthesize timeout = _timeout;
+@synthesize oauth2AccessToken = _oauth2AccessToken;
+@synthesize authTokenProvider = _authTokenProvider;
+@synthesize initialMetadata = _initialMetadata;
+@synthesize userAgentPrefix = _userAgentPrefix;
+@synthesize responseSizeLimit = _responseSizeLimit;
+@synthesize compressAlgorithm = _compressAlgorithm;
+@synthesize enableRetry = _enableRetry;
+@synthesize keepaliveInterval = _keepaliveInterval;
+@synthesize keepaliveTimeout = _keepaliveTimeout;
+@synthesize connectMinTimeout = _connectMinTimeout;
+@synthesize connectInitialBackoff = _connectInitialBackoff;
+@synthesize connectMaxBackoff = _connectMaxBackoff;
+@synthesize additionalChannelArgs = _additionalChannelArgs;
+@synthesize pemRootCert = _pemRootCert;
+@synthesize pemPrivateKey = _pemPrivateKey;
+@synthesize pemCertChain = _pemCertChain;
+@synthesize transportType = _transportType;
+@synthesize hostNameOverride = _hostNameOverride;
+@synthesize logContext = _logContext;
+@synthesize channelPoolDomain = _channelPoolDomain;
+@synthesize channelId = _channelId;
+
+- (instancetype)init {
+ return [self initWithServerAuthority:kDefaultServerAuthority
+ timeout:kDefaultTimeout
+ oauth2AccessToken:kDefaultOauth2AccessToken
+ authTokenProvider:kDefaultAuthTokenProvider
+ initialMetadata:kDefaultInitialMetadata
+ userAgentPrefix:kDefaultUserAgentPrefix
+ responseSizeLimit:kDefaultResponseSizeLimit
+ compressAlgorithm:kDefaultCompressAlgorithm
+ enableRetry:kDefaultEnableRetry
+ keepaliveInterval:kDefaultKeepaliveInterval
+ keepaliveTimeout:kDefaultKeepaliveTimeout
+ connectMinTimeout:kDefaultConnectMinTimeout
+ connectInitialBackoff:kDefaultConnectInitialBackoff
+ connectMaxBackoff:kDefaultConnectMaxBackoff
+ additionalChannelArgs:kDefaultAdditionalChannelArgs
+ pemRootCert:kDefaultPemRootCert
+ pemPrivateKey:kDefaultPemPrivateKey
+ pemCertChain:kDefaultPemCertChain
+ transportType:kDefaultTransportType
+ hostNameOverride:kDefaultHostNameOverride
+ logContext:kDefaultLogContext
+ channelPoolDomain:kDefaultChannelPoolDomain
+ channelId:kDefaultChannelId];
+}
+
+- (instancetype)initWithServerAuthority:(NSString *)serverAuthority
+ timeout:(NSTimeInterval)timeout
+ oauth2AccessToken:(NSString *)oauth2AccessToken
+ authTokenProvider:(id<GRPCAuthorizationProtocol>)authTokenProvider
+ initialMetadata:(NSDictionary *)initialMetadata
+ userAgentPrefix:(NSString *)userAgentPrefix
+ responseSizeLimit:(NSUInteger)responseSizeLimit
+ compressAlgorithm:(GRPCCompressAlgorithm)compressAlgorithm
+ enableRetry:(BOOL)enableRetry
+ keepaliveInterval:(NSTimeInterval)keepaliveInterval
+ keepaliveTimeout:(NSTimeInterval)keepaliveTimeout
+ connectMinTimeout:(NSTimeInterval)connectMinTimeout
+ connectInitialBackoff:(NSTimeInterval)connectInitialBackoff
+ connectMaxBackoff:(NSTimeInterval)connectMaxBackoff
+ additionalChannelArgs:(NSDictionary *)additionalChannelArgs
+ pemRootCert:(NSString *)pemRootCert
+ pemPrivateKey:(NSString *)pemPrivateKey
+ pemCertChain:(NSString *)pemCertChain
+ transportType:(GRPCTransportType)transportType
+ hostNameOverride:(NSString *)hostNameOverride
+ logContext:(id)logContext
+ channelPoolDomain:(NSString *)channelPoolDomain
+ channelId:(NSUInteger)channelId {
+ if ((self = [super init])) {
+ _serverAuthority = serverAuthority;
+ _timeout = timeout;
+ _oauth2AccessToken = oauth2AccessToken;
+ _authTokenProvider = authTokenProvider;
+ _initialMetadata = initialMetadata;
+ _userAgentPrefix = userAgentPrefix;
+ _responseSizeLimit = responseSizeLimit;
+ _compressAlgorithm = compressAlgorithm;
+ _enableRetry = enableRetry;
+ _keepaliveInterval = keepaliveInterval;
+ _keepaliveTimeout = keepaliveTimeout;
+ _connectMinTimeout = connectMinTimeout;
+ _connectInitialBackoff = connectInitialBackoff;
+ _connectMaxBackoff = connectMaxBackoff;
+ _additionalChannelArgs = additionalChannelArgs;
+ _pemRootCert = pemRootCert;
+ _pemPrivateKey = pemPrivateKey;
+ _pemCertChain = pemCertChain;
+ _transportType = transportType;
+ _hostNameOverride = hostNameOverride;
+ _logContext = logContext;
+ _channelPoolDomain = channelPoolDomain;
+ _channelId = channelId;
+ }
+ return self;
+}
+
+- (nonnull id)copyWithZone:(NSZone *)zone {
+ GRPCCallOptions *newOptions =
+ [[GRPCCallOptions allocWithZone:zone] initWithServerAuthority:_serverAuthority
+ timeout:_timeout
+ oauth2AccessToken:_oauth2AccessToken
+ authTokenProvider:_authTokenProvider
+ initialMetadata:_initialMetadata
+ userAgentPrefix:_userAgentPrefix
+ responseSizeLimit:_responseSizeLimit
+ compressAlgorithm:_compressAlgorithm
+ enableRetry:_enableRetry
+ keepaliveInterval:_keepaliveInterval
+ keepaliveTimeout:_keepaliveTimeout
+ connectMinTimeout:_connectMinTimeout
+ connectInitialBackoff:_connectInitialBackoff
+ connectMaxBackoff:_connectMaxBackoff
+ additionalChannelArgs:[_additionalChannelArgs copy]
+ pemRootCert:_pemRootCert
+ pemPrivateKey:_pemPrivateKey
+ pemCertChain:_pemCertChain
+ transportType:_transportType
+ hostNameOverride:_hostNameOverride
+ logContext:_logContext
+ channelPoolDomain:_channelPoolDomain
+ channelId:_channelId];
+ return newOptions;
+}
+
+- (nonnull id)mutableCopyWithZone:(NSZone *)zone {
+ GRPCMutableCallOptions *newOptions = [[GRPCMutableCallOptions allocWithZone:zone]
+ initWithServerAuthority:_serverAuthority
+ timeout:_timeout
+ oauth2AccessToken:_oauth2AccessToken
+ authTokenProvider:_authTokenProvider
+ initialMetadata:_initialMetadata
+ userAgentPrefix:_userAgentPrefix
+ responseSizeLimit:_responseSizeLimit
+ compressAlgorithm:_compressAlgorithm
+ enableRetry:_enableRetry
+ keepaliveInterval:_keepaliveInterval
+ keepaliveTimeout:_keepaliveTimeout
+ connectMinTimeout:_connectMinTimeout
+ connectInitialBackoff:_connectInitialBackoff
+ connectMaxBackoff:_connectMaxBackoff
+ additionalChannelArgs:[_additionalChannelArgs copy]
+ pemRootCert:_pemRootCert
+ pemPrivateKey:_pemPrivateKey
+ pemCertChain:_pemCertChain
+ transportType:_transportType
+ hostNameOverride:_hostNameOverride
+ logContext:_logContext
+ channelPoolDomain:_channelPoolDomain
+ channelId:_channelId];
+ return newOptions;
+}
+
+@end
+
+@implementation GRPCMutableCallOptions
+
+@dynamic serverAuthority;
+@dynamic timeout;
+@dynamic oauth2AccessToken;
+@dynamic authTokenProvider;
+@dynamic initialMetadata;
+@dynamic userAgentPrefix;
+@dynamic responseSizeLimit;
+@dynamic compressAlgorithm;
+@dynamic enableRetry;
+@dynamic keepaliveInterval;
+@dynamic keepaliveTimeout;
+@dynamic connectMinTimeout;
+@dynamic connectInitialBackoff;
+@dynamic connectMaxBackoff;
+@dynamic additionalChannelArgs;
+@dynamic pemRootCert;
+@dynamic pemPrivateKey;
+@dynamic pemCertChain;
+@dynamic transportType;
+@dynamic hostNameOverride;
+@dynamic logContext;
+@dynamic channelPoolDomain;
+@dynamic channelId;
+
+- (instancetype)init {
+ return [self initWithServerAuthority:kDefaultServerAuthority
+ timeout:kDefaultTimeout
+ oauth2AccessToken:kDefaultOauth2AccessToken
+ authTokenProvider:kDefaultAuthTokenProvider
+ initialMetadata:kDefaultInitialMetadata
+ userAgentPrefix:kDefaultUserAgentPrefix
+ responseSizeLimit:kDefaultResponseSizeLimit
+ compressAlgorithm:kDefaultCompressAlgorithm
+ enableRetry:kDefaultEnableRetry
+ keepaliveInterval:kDefaultKeepaliveInterval
+ keepaliveTimeout:kDefaultKeepaliveTimeout
+ connectMinTimeout:kDefaultConnectMinTimeout
+ connectInitialBackoff:kDefaultConnectInitialBackoff
+ connectMaxBackoff:kDefaultConnectMaxBackoff
+ additionalChannelArgs:kDefaultAdditionalChannelArgs
+ pemRootCert:kDefaultPemRootCert
+ pemPrivateKey:kDefaultPemPrivateKey
+ pemCertChain:kDefaultPemCertChain
+ transportType:kDefaultTransportType
+ hostNameOverride:kDefaultHostNameOverride
+ logContext:kDefaultLogContext
+ channelPoolDomain:kDefaultChannelPoolDomain
+ channelId:kDefaultChannelId];
+}
+
+- (nonnull id)copyWithZone:(NSZone *)zone {
+ GRPCCallOptions *newOptions =
+ [[GRPCCallOptions allocWithZone:zone] initWithServerAuthority:_serverAuthority
+ timeout:_timeout
+ oauth2AccessToken:_oauth2AccessToken
+ authTokenProvider:_authTokenProvider
+ initialMetadata:_initialMetadata
+ userAgentPrefix:_userAgentPrefix
+ responseSizeLimit:_responseSizeLimit
+ compressAlgorithm:_compressAlgorithm
+ enableRetry:_enableRetry
+ keepaliveInterval:_keepaliveInterval
+ keepaliveTimeout:_keepaliveTimeout
+ connectMinTimeout:_connectMinTimeout
+ connectInitialBackoff:_connectInitialBackoff
+ connectMaxBackoff:_connectMaxBackoff
+ additionalChannelArgs:[_additionalChannelArgs copy]
+ pemRootCert:_pemRootCert
+ pemPrivateKey:_pemPrivateKey
+ pemCertChain:_pemCertChain
+ transportType:_transportType
+ hostNameOverride:_hostNameOverride
+ logContext:_logContext
+ channelPoolDomain:_channelPoolDomain
+ channelId:_channelId];
+ return newOptions;
+}
+
+- (nonnull id)mutableCopyWithZone:(NSZone *)zone {
+ GRPCMutableCallOptions *newOptions = [[GRPCMutableCallOptions allocWithZone:zone]
+ initWithServerAuthority:_serverAuthority
+ timeout:_timeout
+ oauth2AccessToken:_oauth2AccessToken
+ authTokenProvider:_authTokenProvider
+ initialMetadata:_initialMetadata
+ userAgentPrefix:_userAgentPrefix
+ responseSizeLimit:_responseSizeLimit
+ compressAlgorithm:_compressAlgorithm
+ enableRetry:_enableRetry
+ keepaliveInterval:_keepaliveInterval
+ keepaliveTimeout:_keepaliveTimeout
+ connectMinTimeout:_connectMinTimeout
+ connectInitialBackoff:_connectInitialBackoff
+ connectMaxBackoff:_connectMaxBackoff
+ additionalChannelArgs:[_additionalChannelArgs copy]
+ pemRootCert:_pemRootCert
+ pemPrivateKey:_pemPrivateKey
+ pemCertChain:_pemCertChain
+ transportType:_transportType
+ hostNameOverride:_hostNameOverride
+ logContext:_logContext
+ channelPoolDomain:_channelPoolDomain
+ channelId:_channelId];
+ return newOptions;
+}
+
+- (void)setServerAuthority:(NSString *)serverAuthority {
+ _serverAuthority = serverAuthority;
+}
+
+- (void)setTimeout:(NSTimeInterval)timeout {
+ _timeout = timeout;
+}
+
+- (void)setOauth2AccessToken:(NSString *)oauth2AccessToken {
+ _oauth2AccessToken = oauth2AccessToken;
+}
+
+- (void)setAuthTokenProvider:(id<GRPCAuthorizationProtocol>)authTokenProvider {
+ _authTokenProvider = authTokenProvider;
+}
+
+- (void)setInitialMetadata:(NSDictionary *)initialMetadata {
+ _initialMetadata = initialMetadata;
+}
+
+- (void)setUserAgentPrefix:(NSString *)userAgentPrefix {
+ _userAgentPrefix = userAgentPrefix;
+}
+
+- (void)setResponseSizeLimit:(NSUInteger)responseSizeLimit {
+ _responseSizeLimit = responseSizeLimit;
+}
+
+- (void)setCompressAlgorithm:(GRPCCompressAlgorithm)compressAlgorithm {
+ _compressAlgorithm = compressAlgorithm;
+}
+
+- (void)setEnableRetry:(BOOL)enableRetry {
+ _enableRetry = enableRetry;
+}
+
+- (void)setKeepaliveInterval:(NSTimeInterval)keepaliveInterval {
+ _keepaliveInterval = keepaliveInterval;
+}
+
+- (void)setKeepaliveTimeout:(NSTimeInterval)keepaliveTimeout {
+ _keepaliveTimeout = keepaliveTimeout;
+}
+
+- (void)setConnectMinTimeout:(NSTimeInterval)connectMinTimeout {
+ _connectMinTimeout = connectMinTimeout;
+}
+
+- (void)setConnectInitialBackoff:(NSTimeInterval)connectInitialBackoff {
+ _connectInitialBackoff = connectInitialBackoff;
+}
+
+- (void)setConnectMaxBackoff:(NSTimeInterval)connectMaxBackoff {
+ _connectMaxBackoff = connectMaxBackoff;
+}
+
+- (void)setAdditionalChannelArgs:(NSDictionary *)additionalChannelArgs {
+ _additionalChannelArgs = additionalChannelArgs;
+}
+
+- (void)setPemRootCert:(NSString *)pemRootCert {
+ _pemRootCert = pemRootCert;
+}
+
+- (void)setPemPrivateKey:(NSString *)pemPrivateKey {
+ _pemPrivateKey = pemPrivateKey;
+}
+
+- (void)setPemCertChain:(NSString *)pemCertChain {
+ _pemCertChain = pemCertChain;
+}
+
+- (void)setTransportType:(GRPCTransportType)transportType {
+ _transportType = transportType;
+}
+
+- (void)setHostNameOverride:(NSString *)hostNameOverride {
+ _hostNameOverride = hostNameOverride;
+}
+
+- (void)setLogContext:(id)logContext {
+ _logContext = logContext;
+}
+
+- (void)setChannelPoolDomain:(NSString *)channelPoolDomain {
+ _channelPoolDomain = channelPoolDomain;
+}
+
+- (void)setChannelId:(NSUInteger)channelId {
+ _channelId = channelId;
+}
+
+@end