Skip to content

Commit

Permalink
Merge pull request grpc#2754 from jcanizales/support-test-certificates
Browse files Browse the repository at this point in the history
Support test certificates and SSL name override in Obj-C
  • Loading branch information
jcanizales committed Aug 6, 2015
2 parents 0a60126 + 4ab7cc0 commit a3428f3
Show file tree
Hide file tree
Showing 14 changed files with 410 additions and 101 deletions.
45 changes: 45 additions & 0 deletions src/objective-c/GRPCClient/GRPCCall+Tests.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
*
* 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 "GRPCCall.h"

@interface GRPCCall (Tests)

// Establish all SSL connections to the provided host using the passed SSL target name and the root
// certificates found in the file at |certsPath|.
// Must be called before any gRPC call to that host is made.
+ (void)useTestCertsPath:(NSString *)certsPath
testName:(NSString *)testName
forHost:(NSString *)host;

@end
47 changes: 47 additions & 0 deletions src/objective-c/GRPCClient/GRPCCall+Tests.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
*
* 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 "GRPCCall+Tests.h"

#import "private/GRPCHost.h"

@implementation GRPCCall (Tests)
+ (void)useTestCertsPath:(NSString *)certsPath
testName:(NSString *)testName
forHost:(NSString *)host {
GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];
hostConfig.secure = YES;
hostConfig.pathToCertificates = certsPath;
hostConfig.hostNameOverride = testName;
}
@end
12 changes: 4 additions & 8 deletions src/objective-c/GRPCClient/GRPCCall.m
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
#include <grpc/support/time.h>
#import <RxLibrary/GRXConcurrentWriteable.h>

#import "private/GRPCChannel.h"
#import "private/GRPCWrappedCall.h"
#import "private/NSData+GRPC.h"
#import "private/NSDictionary+GRPC.h"
Expand Down Expand Up @@ -70,8 +69,6 @@ @implementation GRPCCall {
GRPCWrappedCall *_wrappedCall;
dispatch_once_t _callAlreadyInvoked;

GRPCChannel *_channel;

// The C gRPC library has less guarantees on the ordering of events than we
// do. Particularly, in the face of errors, there's no ordering guarantee at
// all. This wrapper over our actual writeable ensures thread-safety and
Expand Down Expand Up @@ -105,11 +102,10 @@ - (instancetype)initWithHost:(NSString *)host
format:@"The requests writer can't be already started."];
}
if ((self = [super init])) {
_channel = [GRPCChannel channelToHost:host];

_wrappedCall = [[GRPCWrappedCall alloc] initWithChannel:_channel
path:path
host:host];
_wrappedCall = [[GRPCWrappedCall alloc] initWithHost:host path:path];
if (!_wrappedCall) {
return nil;
}

// Serial queue to invoke the non-reentrant methods of the grpc_call object.
_callQueue = dispatch_queue_create("org.grpc.call", NULL);
Expand Down
13 changes: 4 additions & 9 deletions src/objective-c/GRPCClient/private/GRPCChannel.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,12 @@

struct grpc_channel;

// Each separate instance of this class represents at least one TCP
// connection to the provided host. To create a grpc_call, pass the
// value of the unmanagedChannel property to grpc_channel_create_call.
// Release this object when the call is finished.
// 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;

// Convenience constructor to allow for reuse of connections.
+ (instancetype)channelToHost:(NSString *)host;

- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;

// 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.
- (instancetype)initWithChannel:(struct grpc_channel *)unmanagedChannel NS_DESIGNATED_INITIALIZER;
@end
56 changes: 8 additions & 48 deletions src/objective-c/GRPCClient/private/GRPCChannel.m
Original file line number Diff line number Diff line change
Expand Up @@ -35,66 +35,26 @@

#include <grpc/grpc.h>

#import "GRPCSecureChannel.h"
#import "GRPCUnsecuredChannel.h"

@implementation GRPCChannel

+ (instancetype)channelToHost:(NSString *)host {
// TODO(mlumish): Investigate whether a cache with strong links is a good idea
static NSMutableDictionary *channelCache;
static dispatch_once_t cacheInitialization;
dispatch_once(&cacheInitialization, ^{
channelCache = [NSMutableDictionary dictionary];
});
GRPCChannel *channel = channelCache[host];
if (!channel) {
channel = [[self alloc] initWithHost:host];
channelCache[host] = channel;
}
return channel;
}

- (instancetype)init {
return [self initWithHost:nil];
return [self initWithChannel:NULL];
}

- (instancetype)initWithHost:(NSString *)host {
if (![host rangeOfString:@"://"].length) {
// No scheme provided; assume https.
host = [@"https://" stringByAppendingString:host];
}
NSURL *hostURL = [NSURL URLWithString:host];
if (!hostURL) {
[NSException raise:NSInvalidArgumentException format:@"Invalid URL: %@", host];
// Designated initializer
- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel {
if (!unmanagedChannel) {
return nil;
}
if ([hostURL.scheme isEqualToString:@"https"]) {
host = [@[hostURL.host, hostURL.port ?: @443] componentsJoinedByString:@":"];
return [[GRPCSecureChannel alloc] initWithHost:host];
}
if ([hostURL.scheme isEqualToString:@"http"]) {
host = [@[hostURL.host, hostURL.port ?: @80] componentsJoinedByString:@":"];
return [[GRPCUnsecuredChannel alloc] initWithHost:host];
}
[NSException raise:NSInvalidArgumentException
format:@"URL scheme %@ isn't supported.", hostURL.scheme];
return nil; // silence warning.
}

- (instancetype)initWithChannel:(struct grpc_channel *)unmanagedChannel {
if ((self = [super init])) {
_unmanagedChannel = unmanagedChannel;
}
return self;
}

- (void)dealloc {
// _unmanagedChannel is NULL when deallocating an object of the base class (because the
// initializer returns a different object).
if (_unmanagedChannel) {
// 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);
}
// 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);
}
@end
2 changes: 0 additions & 2 deletions src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@
@implementation GRPCCompletionQueue

+ (instancetype)completionQueue {
// TODO(jcanizales): Reuse completion queues to consume only one thread,
// instead of one per call.
return [[self alloc] init];
}

Expand Down
58 changes: 58 additions & 0 deletions src/objective-c/GRPCClient/private/GRPCHost.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
*
* 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 <Foundation/Foundation.h>

@class GRPCCompletionQueue;
struct grpc_call;

@interface GRPCHost : NSObject

@property(nonatomic, readonly) NSString *address;

// The following properties should only be modified for testing:

@property(nonatomic, getter=isSecure) BOOL secure;

@property(nonatomic, copy) NSString *pathToCertificates;
@property(nonatomic, copy) NSString *hostNameOverride;

// Host objects initialized with the same address are the same.
+ (instancetype)hostWithAddress:(NSString *)address;
- (instancetype)initWithAddress:(NSString *)address NS_DESIGNATED_INITIALIZER;

// Create a grpc_call object to the provided path on this host.
- (struct grpc_call *)unmanagedCallWithPath:(NSString *)path
completionQueue:(GRPCCompletionQueue *)queue;

@end
Loading

0 comments on commit a3428f3

Please sign in to comment.