Merge pull request #7572 from jcanizales/p0-4MB-should-be-more-than-enough-for-everybody

Let override default response size limit
pull/7379/head
Jorge Canizales 9 years ago committed by GitHub
commit 86ea627270
  1. 5
      src/objective-c/GRPCClient/GRPCCall+ChannelArg.h
  2. 11
      src/objective-c/GRPCClient/GRPCCall+ChannelArg.m
  3. 6
      src/objective-c/GRPCClient/GRPCCall+Tests.h
  4. 3
      src/objective-c/GRPCClient/GRPCCall+Tests.m
  5. 16
      src/objective-c/GRPCClient/private/GRPCChannel.m
  6. 5
      src/objective-c/GRPCClient/private/GRPCHost.h
  7. 12
      src/objective-c/GRPCClient/private/GRPCHost.m
  8. 9
      src/objective-c/tests/GRPCClientTests.m
  9. 7
      src/objective-c/tests/InteropTests.h
  10. 73
      src/objective-c/tests/InteropTests.m
  11. 8
      src/objective-c/tests/InteropTestsLocalCleartext.m
  12. 8
      src/objective-c/tests/InteropTestsLocalSSL.m
  13. 4
      src/objective-c/tests/InteropTestsRemote.m
  14. 6
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme

@ -43,7 +43,10 @@
* 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;
+ (void)setUserAgentPrefix:(nonnull NSString *)userAgentPrefix forHost:(nonnull NSString *)host;
/** The default response size limit is 4MB. Set this to override that default. */
+ (void)setResponseSizeLimit:(NSUInteger)limit forHost:(nonnull NSString *)host;
+ (void)closeOpenConnections DEPRECATED_MSG_ATTRIBUTE("The API for this feature is experimental, "
"and might be removed or modified at any "

@ -37,15 +37,16 @@
@implementation GRPCCall (ChannelArg)
+ (void)setUserAgentPrefix:(NSString *)userAgentPrefix forHost:(NSString *)host {
if (!host) {
[NSException raise:NSInvalidArgumentException
format:@"host and userAgentPrefix must be provided."];
}
+ (void)setUserAgentPrefix:(nonnull NSString *)userAgentPrefix forHost:(nonnull NSString *)host {
GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];
hostConfig.userAgentPrefix = userAgentPrefix;
}
+ (void)setResponseSizeLimit:(NSUInteger)limit forHost:(nonnull NSString *)host {
GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];
hostConfig.responseSizeLimitOverride = @(limit);
}
+ (void)closeOpenConnections {
[GRPCHost flushChannelCache];
}

@ -57,4 +57,10 @@
* more than one invocation of the methods of this category.
*/
+ (void)useInsecureConnectionsForHost:(NSString *)host;
/**
* Resets all host configurations to their default values, and flushes all connections from the
* cache.
*/
+ (void)resetHostSettings;
@end

@ -61,4 +61,7 @@
hostConfig.secure = NO;
}
+ (void)resetHostSettings {
[GRPCHost resetAllHostSettings];
}
@end

@ -47,7 +47,7 @@
#endif
#import "GRPCCompletionQueue.h"
void freeChannelArgs(grpc_channel_args *channel_args) {
static 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);
@ -65,7 +65,7 @@ void freeChannelArgs(grpc_channel_args *channel_args) {
* 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) {
static grpc_channel_args *BuildChannelArgs(NSDictionary *dictionary) {
if (!dictionary) {
return NULL;
}
@ -115,10 +115,12 @@ grpc_channel_args * buildChannelArgs(NSDictionary *dictionary) {
}
if (self = [super init]) {
_channelArgs = buildChannelArgs(channelArgs);
_channelArgs = BuildChannelArgs(channelArgs);
_host = [host copy];
_unmanagedChannel = grpc_cronet_secure_channel_create(cronetEngine, _host.UTF8String, _channelArgs,
NULL);
_unmanagedChannel = grpc_cronet_secure_channel_create(cronetEngine,
_host.UTF8String,
_channelArgs,
NULL);
}
return self;
@ -138,7 +140,7 @@ grpc_channel_args * buildChannelArgs(NSDictionary *dictionary) {
}
if (self = [super init]) {
_channelArgs = buildChannelArgs(channelArgs);
_channelArgs = BuildChannelArgs(channelArgs);
_host = [host copy];
if (secure) {
_unmanagedChannel = grpc_secure_channel_create(credentials, _host.UTF8String, _channelArgs,
@ -155,7 +157,7 @@ grpc_channel_args * buildChannelArgs(NSDictionary *dictionary) {
// 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);
FreeChannelArgs(_channelArgs);
}
#ifdef GRPC_COMPILE_WITH_CRONET

@ -42,6 +42,7 @@ struct grpc_channel_credentials;
@interface GRPCHost : NSObject
+ (void)flushChannelCache;
+ (void)resetAllHostSettings;
@property(nonatomic, readonly) NSString *address;
@property(nonatomic, copy, nullable) NSString *userAgentPrefix;
@ -53,6 +54,10 @@ struct grpc_channel_credentials;
@property(nonatomic, copy, nullable) NSString *hostNameOverride;
/** The default response size limit is 4MB. Set this to override that default. */
@property(nonatomic, strong, nullable) NSNumber *responseSizeLimitOverride;
- (nullable instancetype)init NS_UNAVAILABLE;
/** Host objects initialized with the same address are the same. */
+ (nullable instancetype)hostWithAddress:(NSString *)address;

@ -49,7 +49,7 @@ NS_ASSUME_NONNULL_BEGIN
// 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"
#define GRPC_OBJC_VERSION_STRING @"1.0.0-pre1"
static NSMutableDictionary *kHostCache;
@ -113,6 +113,12 @@ static NSMutableDictionary *kHostCache;
}
}
+ (void)resetAllHostSettings {
@synchronized (kHostCache) {
kHostCache = [NSMutableDictionary dictionary];
}
}
- (nullable grpc_call *)unmanagedCallWithPath:(NSString *)path
completionQueue:(GRPCCompletionQueue *)queue {
GRPCChannel *channel;
@ -209,6 +215,10 @@ static NSMutableDictionary *kHostCache;
if (_secure && _hostNameOverride) {
args[@GRPC_SSL_TARGET_NAME_OVERRIDE_ARG] = _hostNameOverride;
}
if (_responseSizeLimitOverride) {
args[@GRPC_ARG_MAX_MESSAGE_LENGTH] = _responseSizeLimitOverride;
}
return args;
}

@ -292,15 +292,6 @@ static GRPCProtoMethod *kUnaryCallMethod;
// TODO(makarandd): Move to a different file that contains only unit tests
- (void)testExceptions {
// Try to set userAgentPrefix for host that is nil. This should cause
// an exception.
@try {
[GRPCCall setUserAgentPrefix:@"Foo" forHost:nil];
XCTFail(@"Did not receive an exception when host is nil");
} @catch(NSException *theException) {
NSLog(@"Received exception as expected: %@", theException.name);
}
// Try to set parameters to nil for GRPCCall. This should cause an exception
@try {
(void)[[GRPCCall alloc] initWithHost:nil

@ -46,4 +46,11 @@
* Override in a subclass to perform these tests against a specific address.
*/
+ (NSString *)host;
/**
* Bytes of overhead of test proto responses due to encoding. This is used to excercise the behavior
* when responses are just above or below the max response size. For some reason, the local and
* remote servers enconde responses with different overhead (?), so this is defined per-subclass.
*/
- (int32_t)encodingOverhead;
@end

@ -80,10 +80,6 @@
#pragma mark Tests
#ifdef GRPC_COMPILE_WITH_CRONET
static cronet_engine *cronetEngine = NULL;
#endif
@implementation InteropTests {
RMTTestService *_service;
}
@ -92,15 +88,22 @@ static cronet_engine *cronetEngine = NULL;
return nil;
}
- (int32_t)encodingOverhead {
return 0;
}
- (void)setUp {
self.continueAfterFailure = NO;
[GRPCCall resetHostSettings];
_service = self.class.host ? [RMTTestService serviceWithHost:self.class.host] : nil;
#ifdef GRPC_COMPILE_WITH_CRONET
if (cronetEngine == NULL) {
// Cronet setup
[Cronet setHttp2Enabled:YES];
[Cronet start];
cronetEngine = [Cronet getGlobalEngine];
[GRPCCall useCronetWithEngine:cronetEngine];
[GRPCCall useCronetWithEngine:[Cronet getGlobalEngine]];
}
#endif
}
@ -146,6 +149,64 @@ static cronet_engine *cronetEngine = NULL;
[self waitForExpectationsWithTimeout:16 handler:nil];
}
- (void)test4MBResponsesAreAccepted {
XCTAssertNotNil(self.class.host);
__weak XCTestExpectation *expectation = [self expectationWithDescription:@"MaxResponseSize"];
RMTSimpleRequest *request = [RMTSimpleRequest message];
const int32_t kPayloadSize = 4 * 1024 * 1024 - self.encodingOverhead; // 4MB - encoding overhead
request.responseSize = kPayloadSize;
[_service unaryCallWithRequest:request handler:^(RMTSimpleResponse *response, NSError *error) {
XCTAssertNil(error, @"Finished with unexpected error: %@", error);
XCTAssertEqual(response.payload.body.length, kPayloadSize);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:16 handler:nil];
}
- (void)testResponsesOverMaxSizeFailWithActionableMessage {
XCTAssertNotNil(self.class.host);
__weak XCTestExpectation *expectation = [self expectationWithDescription:@"ResponseOverMaxSize"];
RMTSimpleRequest *request = [RMTSimpleRequest message];
const int32_t kPayloadSize = 4 * 1024 * 1024 - self.encodingOverhead + 1; // 1B over max size
request.responseSize = kPayloadSize;
[_service unaryCallWithRequest:request handler:^(RMTSimpleResponse *response, NSError *error) {
// TODO(jcanizales): Catch the error and rethrow it with an actionable message:
// - Use +[GRPCCall setResponseSizeLimit:forHost:] to set a higher limit.
// - If you're developing the server, consider using response streaming, or let clients filter
// responses by setting a google.protobuf.FieldMask in the request:
// https://github.com/google/protobuf/blob/master/src/google/protobuf/field_mask.proto
XCTAssertEqualObjects(error.localizedDescription, @"Max message size exceeded");
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:16 handler:nil];
}
- (void)testResponsesOver4MBAreAcceptedIfOptedIn {
XCTAssertNotNil(self.class.host);
__weak XCTestExpectation *expectation =
[self expectationWithDescription:@"HigherResponseSizeLimit"];
RMTSimpleRequest *request = [RMTSimpleRequest message];
const size_t kPayloadSize = 5 * 1024 * 1024; // 5MB
request.responseSize = kPayloadSize;
[GRPCCall setResponseSizeLimit:6 * 1024 * 1024 forHost:self.class.host];
[_service unaryCallWithRequest:request handler:^(RMTSimpleResponse *response, NSError *error) {
XCTAssertNil(error, @"Finished with unexpected error: %@", error);
XCTAssertEqual(response.payload.body.length, kPayloadSize);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:16 handler:nil];
}
- (void)testClientStreamingRPC {
XCTAssertNotNil(self.class.host);
__weak XCTestExpectation *expectation = [self expectationWithDescription:@"ClientStreaming"];

@ -47,11 +47,15 @@ static NSString * const kLocalCleartextHost = @"localhost:5050";
return kLocalCleartextHost;
}
- (int32_t)encodingOverhead {
return 10; // bytes
}
- (void)setUp {
[super setUp];
// Register test server as non-SSL.
[GRPCCall useInsecureConnectionsForHost:kLocalCleartextHost];
[super setUp];
}
@end

@ -47,14 +47,18 @@ static NSString * const kLocalSSLHost = @"localhost:5051";
return kLocalSSLHost;
}
- (int32_t)encodingOverhead {
return 10; // bytes
}
- (void)setUp {
[super setUp];
// Register test server certificates and name.
NSBundle *bundle = [NSBundle bundleForClass:self.class];
NSString *certsPath = [bundle pathForResource:@"TestCertificates.bundle/test-certificates"
ofType:@"pem"];
[GRPCCall useTestCertsPath:certsPath testName:@"foo.test.google.fr" forHost:kLocalSSLHost];
[super setUp];
}
- (void)testExceptions {

@ -47,4 +47,8 @@ static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.googleapis.com";
return kRemoteSSLHost;
}
- (int32_t)encodingOverhead {
return 12; // bytes
}
@end

@ -38,12 +38,6 @@
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
<SkippedTests>
<Test
Identifier = "GRPCClientTests/testConnectionToRemoteServer">
</Test>
<Test
Identifier = "GRPCClientTests/testMetadata">
</Test>
<Test
Identifier = "InteropTests">
</Test>

Loading…
Cancel
Save