From c47b3f5c3afa57ccb2bb64426f1aa91ecf6d4bfe Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 21 Dec 2017 16:52:39 -0800 Subject: [PATCH] Add interface to API to enable compression --- .../GRPCClient/GRPCCall+ChannelArg.h | 10 ++++++ .../GRPCClient/GRPCCall+ChannelArg.m | 20 +++++++++++ src/objective-c/GRPCClient/private/GRPCHost.h | 3 ++ src/objective-c/GRPCClient/private/GRPCHost.m | 7 ++++ src/objective-c/tests/InteropTests.m | 34 +++++++++++++++++++ .../tests/RemoteTestClient/messages.proto | 22 ++++++++++++ 6 files changed, 96 insertions(+) diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h index 9f2361bd224..18d45970983 100644 --- a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h +++ b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h @@ -19,6 +19,12 @@ #include +typedef NS_ENUM(NSInteger, GRPCCompressAlgorithm) { + GRPCCompressNone, + GRPCCompressDeflate, + GRPCCompressGzip, +}; + /** * Methods to configure GRPC channel options. */ @@ -36,4 +42,8 @@ + (void)closeOpenConnections DEPRECATED_MSG_ATTRIBUTE("The API for this feature is experimental, " "and might be removed or modified at any " "time."); + ++ (void)setDefaultCompressMethod:(GRPCCompressAlgorithm)algorithm + forhost:(nonnull NSString *)host; + @end diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m index 398d98fbc7a..0248f33638b 100644 --- a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m +++ b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m @@ -20,6 +20,8 @@ #import "private/GRPCHost.h" +#import + @implementation GRPCCall (ChannelArg) + (void)setUserAgentPrefix:(nonnull NSString *)userAgentPrefix forHost:(nonnull NSString *)host { @@ -36,4 +38,22 @@ [GRPCHost flushChannelCache]; } ++ (void)setDefaultCompressMethod:(GRPCCompressAlgorithm)algorithm + forhost:(nonnull NSString *)host { + GRPCHost *hostConfig = [GRPCHost hostWithAddress:host]; + switch (algorithm) { + case GRPCCompressNone: + hostConfig.compressAlgorithm = GRPC_COMPRESS_NONE; + break; + case GRPCCompressDeflate: + hostConfig.compressAlgorithm = GRPC_COMPRESS_DEFLATE; + break; + case GRPCCompressGzip: + hostConfig.compressAlgorithm = GRPC_COMPRESS_GZIP; + break; + default: + NSLog(@"Invalid compression algorithm"); + } +} + @end diff --git a/src/objective-c/GRPCClient/private/GRPCHost.h b/src/objective-c/GRPCClient/private/GRPCHost.h index 58171211b0e..0215db85315 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.h +++ b/src/objective-c/GRPCClient/private/GRPCHost.h @@ -18,6 +18,8 @@ #import +#import + NS_ASSUME_NONNULL_BEGIN @class GRPCCompletionQueue; @@ -32,6 +34,7 @@ struct grpc_channel_credentials; @property(nonatomic, readonly) NSString *address; @property(nonatomic, copy, nullable) NSString *userAgentPrefix; @property(nonatomic, nullable) struct grpc_channel_credentials *channelCreds; +@property(nonatomic) grpc_compression_algorithm compressAlgorithm; /** 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 a0f41187400..665943f1815 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -87,6 +87,7 @@ static GRPCConnectivityMonitor *connectivityMonitor = nil; _address = address; _secure = YES; kHostCache[address] = self; + _compressAlgorithm = GRPC_COMPRESS_NONE; } // Keep a single monitor to flush the cache if the connectivity status changes // Thread safety guarded by @synchronized(kHostCache) @@ -226,6 +227,12 @@ static GRPCConnectivityMonitor *connectivityMonitor = nil; } // Use 10000ms initial backoff time for correct behavior on bad/slow networks args[@GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS] = @10000; + + if (_compressAlgorithm != GRPC_COMPRESS_NONE) { + args[@GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM] = + [NSNumber numberWithInt:_compressAlgorithm]; + } + return args; } diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index 0be8669aa2f..dfa874adab6 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -68,6 +68,10 @@ } @end +BOOL isRemoteInteropTest(NSString *host) { + return [host isEqualToString:@"grpc-test.sandbox.googleapis.com"]; +} + #pragma mark Tests @implementation InteropTests { @@ -452,4 +456,34 @@ [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } +- (void)testCompressedUnaryRPC { + // This test needs to be disabled for remote test because interop server grpc-test + // does not support compression. + if (isRemoteInteropTest(self.class.host)) { + return; + } + XCTAssertNotNil(self.class.host); + __weak XCTestExpectation *expectation = [self expectationWithDescription:@"LargeUnary"]; + + RMTSimpleRequest *request = [RMTSimpleRequest message]; + request.responseType = RMTPayloadType_Compressable; + request.responseSize = 314159; + request.payload.body = [NSMutableData dataWithLength:271828]; + request.expectCompressed.value = YES; + [GRPCCall setDefaultCompressMethod:GRPCCompressGzip forhost:self.class.host]; + + [_service unaryCallWithRequest:request handler:^(RMTSimpleResponse *response, NSError *error) { + XCTAssertNil(error, @"Finished with unexpected error: %@", error); + + RMTSimpleResponse *expectedResponse = [RMTSimpleResponse message]; + expectedResponse.payload.type = RMTPayloadType_Compressable; + expectedResponse.payload.body = [NSMutableData dataWithLength:314159]; + XCTAssertEqualObjects(response, expectedResponse); + + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +} + @end diff --git a/src/objective-c/tests/RemoteTestClient/messages.proto b/src/objective-c/tests/RemoteTestClient/messages.proto index 128efd9337e..ac46ec5d8d8 100644 --- a/src/objective-c/tests/RemoteTestClient/messages.proto +++ b/src/objective-c/tests/RemoteTestClient/messages.proto @@ -20,6 +20,16 @@ package grpc.testing; option objc_class_prefix = "RMT"; +message BoolValue { + // The bool value. + bool value = 1; +} + +message EchoStatus { + int32 code = 1; + string message = 2; +} + // The type of payload that should be returned. enum PayloadType { // Compressable text format. @@ -58,6 +68,18 @@ message SimpleRequest { // Whether SimpleResponse should include OAuth scope. bool fill_oauth_scope = 5; + + // Whether to request the server to compress the response. This field is + // "nullable" in order to interoperate seamlessly with clients not able to + // implement the full compression tests by introspecting the call to verify + // the response's compression status. + BoolValue response_compressed = 6; + + // Whether server should return a given status + EchoStatus response_status = 7; + + // Whether the server should expect this request to be compressed. + BoolValue expect_compressed = 8; } // Unary response, as configured by the request.