aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Jorge Canizales <jcanizales@google.com>2016-02-05 18:00:45 -0800
committerGravatar Jorge Canizales <jcanizales@google.com>2016-02-05 18:00:45 -0800
commit83f76a8b017f2073d1468be2a01ef8309729e87b (patch)
treefecd6f884352bb7498443d576aedf97245283436 /src
parentbeb55c3b46debedcacdaab48bdae5b9c80ddf13f (diff)
parent58d98910add14197aec78aad6be15f5911e21fe4 (diff)
Merge pull request #4985 from kriswuollett/kriswuollett-objc-useragent
Add channel args to enable user agent string for Objective-C
Diffstat (limited to 'src')
-rw-r--r--src/objective-c/GRPCClient/GRPCCall+ChannelArg.h (renamed from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h)16
-rw-r--r--src/objective-c/GRPCClient/GRPCCall+ChannelArg.m (renamed from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m)23
-rw-r--r--src/objective-c/GRPCClient/private/GRPCChannel.h45
-rw-r--r--src/objective-c/GRPCClient/private/GRPCChannel.m166
-rw-r--r--src/objective-c/GRPCClient/private/GRPCHost.h1
-rw-r--r--src/objective-c/GRPCClient/private/GRPCHost.m31
-rw-r--r--src/objective-c/GRPCClient/private/GRPCSecureChannel.h55
-rw-r--r--src/objective-c/GRPCClient/private/GRPCSecureChannel.m118
8 files changed, 245 insertions, 210 deletions
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h
index 8528be44c0..bd6b064f16 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,9 +30,17 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
+#import "GRPCCall.h"
-#import "GRPCChannel.h"
+/**
+ * Methods to configure GRPC channel options.
+ */
+@interface GRPCCall (ChannelArg)
+
+/**
+ * Use the provided @c userAgentPrefix at the beginning of the HTTP User Agent string for all calls
+ * to the specified @c host.
+ */
++ (void)setUserAgentPrefix:(NSString *)userAgentPrefix forHost:(NSString *)host;
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
@end
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m
index 15b6ffc75c..5f9932d86d 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
+++ b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,20 +31,19 @@
*
*/
-#import "GRPCUnsecuredChannel.h"
+#import "GRPCCall+ChannelArg.h"
-#include <grpc/grpc.h>
+#import "private/GRPCHost.h"
-@implementation GRPCUnsecuredChannel
+@implementation GRPCCall (ChannelArg)
-- (instancetype)initWithHost:(NSString *)host {
- return (self = [super initWithChannel:grpc_insecure_channel_create(host.UTF8String, NULL, NULL)]);
++ (void)setUserAgentPrefix:(NSString *)userAgentPrefix forHost:(NSString *)host {
+ if (!host) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"host and userAgentPrefix must be provided."];
+ }
+ GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];
+ hostConfig.userAgentPrefix = userAgentPrefix;
}
-// TODO(jcanizales): GRPCSecureChannel and GRPCUnsecuredChannel are just convenience initializers
-// for GRPCChannel. Move them into GRPCChannel, which will make the following unnecessary.
-- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel {
- [NSException raise:NSInternalInconsistencyException format:@"use the other initializer"];
- return [self initWithHost:nil]; // silence warnings
-}
@end
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h
index e2d19d506a..1888dea1b4 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.h
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.h
@@ -33,18 +33,51 @@
#import <Foundation/Foundation.h>
-struct grpc_channel;
+#include <grpc/grpc.h>
+
+struct grpc_channel_credentials;
+
/**
* Each separate instance of this class represents at least one TCP connection to the provided host.
- * Create them using one of the subclasses |GRPCSecureChannel| and |GRPCUnsecuredChannel|.
*/
@interface GRPCChannel : NSObject
-@property(nonatomic, readonly) struct grpc_channel *unmanagedChannel;
+
+@property(nonatomic, readonly, nonnull) struct grpc_channel *unmanagedChannel;
+
+- (nullable instancetype)init NS_UNAVAILABLE;
/**
- * This initializer takes ownership of the passed channel, and will destroy it when this object is
- * deallocated. It's illegal to pass the same grpc_channel to two different GRPCChannel objects.
+ * Creates a secure channel to the specified @c host using default credentials and channel
+ * arguments. If certificates could not be found to create a secure channel, then @c nil is
+ * returned.
*/
-- (instancetype)initWithChannel:(struct grpc_channel *)unmanagedChannel NS_DESIGNATED_INITIALIZER;
++ (nullable GRPCChannel *)secureChannelWithHost:(nonnull NSString *)host;
+
+/**
+ * Creates a secure channel to the specified @c host using the specified @c pathToCertificates and
+ * @c channelArgs. Only in tests should @c pathToCertificates be nil or
+ * @c GRPC_SSL_TARGET_NAME_OVERRIDE_ARG channel arg be set. Passing nil for @c pathToCertificates
+ * results in using the default root certificates distributed with the library. If certificates
+ * could not be found in any case, then @c nil is returned.
+ */
++ (nullable GRPCChannel *)secureChannelWithHost:(nonnull NSString *)host
+ pathToCertificates:(nullable NSString *)pathToCertificates
+ channelArgs:(nullable NSDictionary *)channelArgs;
+
+
+/**
+ * Creates a secure channel to the specified @c host using the specified @c credentials and
+ * @c channelArgs. Only in tests should @c GRPC_SSL_TARGET_NAME_OVERRIDE_ARG channel arg be set.
+ */
++ (nonnull GRPCChannel *)secureChannelWithHost:(nonnull NSString *)host
+ credentials:(nonnull struct grpc_channel_credentials *)credentials
+ channelArgs:(nullable NSDictionary *)channelArgs;
+
+/**
+ * Creates an insecure channel to the specified @c host using the specified @c channelArgs.
+ */
++ (nonnull GRPCChannel *)insecureChannelWithHost:(nonnull NSString *)host
+ channelArgs:(nullable NSDictionary *)channelArgs;
+
@end
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m
index 4366e63320..7a676060c1 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.m
@@ -33,22 +33,114 @@
#import "GRPCChannel.h"
-#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
-@implementation GRPCChannel
+/**
+ * Returns @c grpc_channel_credentials from the specified @c path. If the file at the path could not
+ * be read then NULL is returned. If NULL is returned, @c errorPtr may not be NULL if there are
+ * details available describing what went wrong.
+ */
+static grpc_channel_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) {
+ // Files in PEM format can have non-ASCII characters in their comments (e.g. for the name of the
+ // issuer). Load them as UTF8 and produce an ASCII equivalent.
+ NSString *contentInUTF8 = [NSString stringWithContentsOfFile:path
+ encoding:NSUTF8StringEncoding
+ error:errorPtr];
+ NSData *contentInASCII = [contentInUTF8 dataUsingEncoding:NSASCIIStringEncoding
+ allowLossyConversion:YES];
+ if (!contentInASCII.bytes) {
+ // Passing NULL to grpc_ssl_credentials_create produces behavior we don't want, so return.
+ return NULL;
+ }
+ return grpc_ssl_credentials_create(contentInASCII.bytes, NULL, NULL);
+}
+
+void freeChannelArgs(grpc_channel_args *channel_args) {
+ for (size_t i = 0; i < channel_args->num_args; ++i) {
+ grpc_arg *arg = &channel_args->args[i];
+ gpr_free(arg->key);
+ if (arg->type == GRPC_ARG_STRING) {
+ gpr_free(arg->value.string);
+ }
+ }
+ gpr_free(channel_args);
+}
+
+/**
+ * Allocates a @c grpc_channel_args and populates it with the options specified in the
+ * @c dictionary. Keys must be @c NSString. If the value responds to @c @selector(UTF8String) then
+ * it will be mapped to @c GRPC_ARG_STRING. If not, it will be mapped to @c GRPC_ARG_INTEGER if the
+ * value responds to @c @selector(intValue). Otherwise, an exception will be raised. The caller of
+ * this function is responsible for calling @c freeChannelArgs on a non-NULL returned value.
+ */
+grpc_channel_args * buildChannelArgs(NSDictionary *dictionary) {
+ if (!dictionary) {
+ return NULL;
+ }
-- (instancetype)init {
- return [self initWithChannel:NULL];
+ NSArray *keys = [dictionary allKeys];
+ NSUInteger argCount = [keys count];
+
+ grpc_channel_args *channelArgs = gpr_malloc(sizeof(grpc_channel_args));
+ channelArgs->num_args = argCount;
+ channelArgs->args = gpr_malloc(argCount * sizeof(grpc_arg));
+
+ // TODO(kriswuollett) Check that keys adhere to GRPC core library requirements
+
+ for (NSUInteger i = 0; i < argCount; ++i) {
+ grpc_arg *arg = &channelArgs->args[i];
+ arg->key = gpr_strdup([keys[i] UTF8String]);
+
+ id value = dictionary[keys[i]];
+ if ([value respondsToSelector:@selector(UTF8String)]) {
+ arg->type = GRPC_ARG_STRING;
+ arg->value.string = gpr_strdup([value UTF8String]);
+ } else if ([value respondsToSelector:@selector(intValue)]) {
+ arg->type = GRPC_ARG_INTEGER;
+ arg->value.integer = [value intValue];
+ } else {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Invalid value type: %@", [value class]];
+ }
+ }
+
+ return channelArgs;
+}
+
+@implementation GRPCChannel {
+ // Retain arguments to channel_create because they may not be used on the thread that invoked
+ // the channel_create function.
+ NSString *_host;
+ grpc_channel_args *_channelArgs;
}
-// Designated initializer
-- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel {
- if (!unmanagedChannel) {
+
+- (instancetype)initWithHost:(NSString *)host
+ secure:(BOOL)secure
+ credentials:(struct grpc_channel_credentials *)credentials
+ channelArgs:(NSDictionary *)channelArgs {
+ if (!host) {
+ [NSException raise:NSInvalidArgumentException format:@"host argument missing"];
+ }
+
+ if (secure && !credentials) {
return nil;
}
- if ((self = [super init])) {
- _unmanagedChannel = unmanagedChannel;
+
+ if (self = [super init]) {
+ _channelArgs = buildChannelArgs(channelArgs);
+ _host = [host copy];
+ if (secure) {
+ _unmanagedChannel = grpc_secure_channel_create(credentials, _host.UTF8String, _channelArgs,
+ NULL);
+ } else {
+ _unmanagedChannel = grpc_insecure_channel_create(_host.UTF8String, _channelArgs, NULL);
+ }
}
+
return self;
}
@@ -56,5 +148,61 @@
// TODO(jcanizales): Be sure to add a test with a server that closes the connection prematurely,
// as in the past that made this call to crash.
grpc_channel_destroy(_unmanagedChannel);
+ freeChannelArgs(_channelArgs);
}
+
++ (GRPCChannel *)secureChannelWithHost:(NSString *)host {
+ return [[GRPCChannel alloc] initWithHost:host secure:YES credentials:NULL channelArgs:NULL];
+}
+
++ (GRPCChannel *)secureChannelWithHost:(NSString *)host
+ pathToCertificates:(NSString *)path
+ channelArgs:(NSDictionary *)channelArgs {
+ // Load default SSL certificates once.
+ static grpc_channel_credentials *kDefaultCertificates;
+ static dispatch_once_t loading;
+ dispatch_once(&loading, ^{
+ NSString *defaultPath = @"gRPCCertificates.bundle/roots"; // .pem
+ // Do not use NSBundle.mainBundle, as it's nil for tests of library projects.
+ NSBundle *bundle = [NSBundle bundleForClass:self.class];
+ NSString *path = [bundle pathForResource:defaultPath ofType:@"pem"];
+ NSError *error;
+ kDefaultCertificates = CertificatesAtPath(path, &error);
+ NSAssert(kDefaultCertificates, @"Could not read %@/%@.pem. This file, with the root "
+ "certificates, is needed to establish secure (TLS) connections. Because the file is "
+ "distributed with the gRPC library, this error is usually a sign that the library "
+ "wasn't configured correctly for your project. Error: %@",
+ bundle.bundlePath, defaultPath, error);
+ });
+
+ //TODO(jcanizales): Add NSError** parameter to the initializer.
+ grpc_channel_credentials *certificates = path
+ ? CertificatesAtPath(path, NULL)
+ : kDefaultCertificates;
+
+ return [[GRPCChannel alloc] initWithHost:host
+ secure:YES
+ credentials:certificates
+ channelArgs:channelArgs];
+}
+
+
++ (GRPCChannel *)secureChannelWithHost:(NSString *)host
+ credentials:(struct grpc_channel_credentials *)credentials
+ channelArgs:(NSDictionary *)channelArgs {
+ return [[GRPCChannel alloc] initWithHost:host
+ secure:YES
+ credentials:credentials
+ channelArgs:channelArgs];
+
+}
+
++ (GRPCChannel *)insecureChannelWithHost:(NSString *)host
+ channelArgs:(NSDictionary *)channelArgs {
+ return [[GRPCChannel alloc] initWithHost:host
+ secure:NO
+ credentials:NULL
+ channelArgs:channelArgs];
+}
+
@end
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.h b/src/objective-c/GRPCClient/private/GRPCHost.h
index 6b4f98746d..69a115e88c 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.h
+++ b/src/objective-c/GRPCClient/private/GRPCHost.h
@@ -39,6 +39,7 @@ struct grpc_call;
@interface GRPCHost : NSObject
@property(nonatomic, readonly) NSString *address;
+@property(nonatomic, copy) NSString *userAgentPrefix;
/** The following properties should only be modified for testing: */
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index a8cd3a0e74..f750841a44 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -34,11 +34,15 @@
#import "GRPCHost.h"
#include <grpc/grpc.h>
+#import <GRPCClient/GRPCCall+ChannelArg.h>
#import "GRPCChannel.h"
#import "GRPCCompletionQueue.h"
-#import "GRPCSecureChannel.h"
-#import "GRPCUnsecuredChannel.h"
+#import "NSDictionary+GRPC.h"
+
+// TODO(jcanizales): Generate the version in a standalone header, from templates. Like
+// templates/src/core/surface/version.c.template .
+#define GRPC_OBJC_VERSION_STRING @"0.13.0"
@interface GRPCHost ()
// TODO(mlumish): Investigate whether caching channels with strong links is a good idea.
@@ -106,13 +110,28 @@
- (GRPCChannel *)channel {
// Create it lazily, because we don't want to open a connection just because someone is
// configuring a host.
+
if (!_channel) {
+ NSMutableDictionary *args = [NSMutableDictionary dictionary];
+
+ // TODO(jcanizales): Add OS and device information (see
+ // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#user-agents ).
+ NSString *userAgent = @"grpc-objc/" GRPC_OBJC_VERSION_STRING;
+ if (_userAgentPrefix) {
+ userAgent = [@[_userAgentPrefix, userAgent] componentsJoinedByString:@" "];
+ }
+ args[@GRPC_ARG_PRIMARY_USER_AGENT_STRING] = userAgent;
+
if (_secure) {
- _channel = [[GRPCSecureChannel alloc] initWithHost:_address
- pathToCertificates:_pathToCertificates
- hostNameOverride:_hostNameOverride];
+ if (_hostNameOverride) {
+ args[@GRPC_SSL_TARGET_NAME_OVERRIDE_ARG] = _hostNameOverride;
+ }
+
+ _channel = [GRPCChannel secureChannelWithHost:_address
+ pathToCertificates:_pathToCertificates
+ channelArgs:args];
} else {
- _channel = [[GRPCUnsecuredChannel alloc] initWithHost:_address];
+ _channel = [GRPCChannel insecureChannelWithHost:_address channelArgs:args];
}
}
return _channel;
diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannel.h b/src/objective-c/GRPCClient/private/GRPCSecureChannel.h
deleted file mode 100644
index b82b9fe35a..0000000000
--- a/src/objective-c/GRPCClient/private/GRPCSecureChannel.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/grpc.h>
-
-#import "GRPCChannel.h"
-
-struct grpc_channel_credentials;
-
-@interface GRPCSecureChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host;
-
-/**
- * Only in tests shouldn't pathToCertificates or hostNameOverride be nil. Passing nil for
- * pathToCertificates results in using the default root certificates distributed with the library.
- */
-- (instancetype)initWithHost:(NSString *)host
- pathToCertificates:(NSString *)path
- hostNameOverride:(NSString *)hostNameOverride;
-
-/** The passed arguments aren't required to be valid beyond the invocation of this initializer. */
-- (instancetype)initWithHost:(NSString *)host
- credentials:(struct grpc_channel_credentials *)credentials
- args:(grpc_channel_args *)args NS_DESIGNATED_INITIALIZER;
-@end
diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m b/src/objective-c/GRPCClient/private/GRPCSecureChannel.m
deleted file mode 100644
index a573c171e9..0000000000
--- a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#import "GRPCSecureChannel.h"
-
-#include <grpc/grpc_security.h>
-
-// Returns NULL if the file at path couldn't be read. In that case, if errorPtr isn't NULL,
-// *errorPtr will be an object describing what went wrong.
-static grpc_channel_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) {
- // Files in PEM format can have non-ASCII characters in their comments (e.g. for the name of the
- // issuer). Load them as UTF8 and produce an ASCII equivalent.
- NSString *contentInUTF8 = [NSString stringWithContentsOfFile:path
- encoding:NSUTF8StringEncoding
- error:errorPtr];
- NSData *contentInASCII = [contentInUTF8 dataUsingEncoding:NSASCIIStringEncoding
- allowLossyConversion:YES];
- if (!contentInASCII.bytes) {
- // Passing NULL to grpc_ssl_credentials_create produces behavior we don't want, so return.
- return NULL;
- }
- return grpc_ssl_credentials_create(contentInASCII.bytes, NULL, NULL);
-}
-
-@implementation GRPCSecureChannel
-
-- (instancetype)initWithHost:(NSString *)host {
- return [self initWithHost:host pathToCertificates:nil hostNameOverride:nil];
-}
-
-- (instancetype)initWithHost:(NSString *)host
- pathToCertificates:(NSString *)path
- hostNameOverride:(NSString *)hostNameOverride {
- // Load default SSL certificates once.
- static grpc_channel_credentials *kDefaultCertificates;
- static dispatch_once_t loading;
- dispatch_once(&loading, ^{
- NSString *defaultPath = @"gRPCCertificates.bundle/roots"; // .pem
- // Do not use NSBundle.mainBundle, as it's nil for tests of library projects.
- NSBundle *bundle = [NSBundle bundleForClass:self.class];
- NSString *path = [bundle pathForResource:defaultPath ofType:@"pem"];
- NSError *error;
- kDefaultCertificates = CertificatesAtPath(path, &error);
- NSAssert(kDefaultCertificates, @"Could not read %@/%@.pem. This file, with the root "
- "certificates, is needed to establish secure (TLS) connections. Because the file is "
- "distributed with the gRPC library, this error is usually a sign that the library "
- "wasn't configured correctly for your project. Error: %@",
- bundle.bundlePath, defaultPath, error);
- });
-
- //TODO(jcanizales): Add NSError** parameter to the initializer.
- grpc_channel_credentials *certificates = path
- ? CertificatesAtPath(path, NULL)
- : kDefaultCertificates;
- if (!certificates) {
- return nil;
- }
-
- // Ritual to pass the SSL host name override to the C library.
- grpc_channel_args channelArgs;
- grpc_arg nameOverrideArg;
- channelArgs.num_args = 1;
- channelArgs.args = &nameOverrideArg;
- nameOverrideArg.type = GRPC_ARG_STRING;
- nameOverrideArg.key = GRPC_SSL_TARGET_NAME_OVERRIDE_ARG;
- // Cast const away. Hope C gRPC doesn't modify it!
- nameOverrideArg.value.string = (char *) hostNameOverride.UTF8String;
- grpc_channel_args *args = hostNameOverride ? &channelArgs : NULL;
-
- return [self initWithHost:host credentials:certificates args:args];
-}
-
-- (instancetype)initWithHost:(NSString *)host
- credentials:(grpc_channel_credentials *)credentials
- args:(grpc_channel_args *)args {
- return (self = [super
- initWithChannel:grpc_secure_channel_create(
- credentials, host.UTF8String, args, NULL)]);
-}
-
-// TODO(jcanizales): GRPCSecureChannel and GRPCUnsecuredChannel are just convenience initializers
-// for GRPCChannel. Move them into GRPCChannel, which will make the following unnecessary.
-- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel {
- [NSException raise:NSInternalInconsistencyException format:@"use another initializer"];
- return [self initWithHost:nil]; // silence warnings
-}
-
-@end