aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/objective-c/GRPCClient/GRPCCall.m
diff options
context:
space:
mode:
Diffstat (limited to 'src/objective-c/GRPCClient/GRPCCall.m')
-rw-r--r--src/objective-c/GRPCClient/GRPCCall.m59
1 files changed, 33 insertions, 26 deletions
diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m
index 0f4c811ce4..ff5d1c5aaf 100644
--- a/src/objective-c/GRPCClient/GRPCCall.m
+++ b/src/objective-c/GRPCClient/GRPCCall.m
@@ -42,9 +42,13 @@
#import "private/NSDictionary+GRPC.h"
#import "private/NSError+GRPC.h"
-NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
+NSString * const kGRPCHeadersKey = @"io.grpc.HeadersKey";
+NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
@interface GRPCCall () <GRXWriteable>
+// Make them read-write.
+@property(atomic, strong) NSDictionary *responseHeaders;
+@property(atomic, strong) NSDictionary *responseTrailers;
@end
// The following methods of a C gRPC call object aren't reentrant, and thus
@@ -89,8 +93,7 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
// the response arrives.
GRPCCall *_retainSelf;
- NSMutableDictionary *_requestMetadata;
- NSMutableDictionary *_responseMetadata;
+ NSMutableDictionary *_requestHeaders;
}
@synthesize state = _state;
@@ -121,24 +124,19 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
_requestWriter = requestWriter;
- _requestMetadata = [NSMutableDictionary dictionary];
- _responseMetadata = [NSMutableDictionary dictionary];
+ _requestHeaders = [NSMutableDictionary dictionary];
}
return self;
}
#pragma mark Metadata
-- (NSMutableDictionary *)requestMetadata {
- return _requestMetadata;
+- (NSMutableDictionary *)requestHeaders {
+ return _requestHeaders;
}
-- (void)setRequestMetadata:(NSDictionary *)requestMetadata {
- _requestMetadata = [NSMutableDictionary dictionaryWithDictionary:requestMetadata];
-}
-
-- (NSDictionary *)responseMetadata {
- return _responseMetadata;
+- (void)setRequestHeaders:(NSDictionary *)requestHeaders {
+ _requestHeaders = [NSMutableDictionary dictionaryWithDictionary:requestHeaders];
}
#pragma mark Finish
@@ -232,11 +230,10 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
#pragma mark Send headers
-// TODO(jcanizales): Rename to commitHeaders.
-- (void)sendHeaders:(NSDictionary *)metadata {
+- (void)sendHeaders:(NSDictionary *)headers {
// TODO(jcanizales): Add error handlers for async failures
[_wrappedCall startBatchWithOperations:@[[[GRPCOpSendMetadata alloc]
- initWithMetadata:metadata ?: @{} handler:nil]]];
+ initWithMetadata:headers ?: @{} handler:nil]]];
}
#pragma mark GRXWriteable implementation
@@ -305,35 +302,45 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
// Both handlers will eventually be called, from the network queue. Writes can start immediately
// after this.
-// The first one (metadataHandler), when the response headers are received.
+// The first one (headersHandler), when the response headers are received.
// The second one (completionHandler), whenever the RPC finishes for any reason.
-- (void)invokeCallWithMetadataHandler:(void(^)(NSDictionary *))metadataHandler
+- (void)invokeCallWithHeadersHandler:(void(^)(NSDictionary *))headersHandler
completionHandler:(void(^)(NSError *, NSDictionary *))completionHandler {
// TODO(jcanizales): Add error handlers for async failures
[_wrappedCall startBatchWithOperations:@[[[GRPCOpRecvMetadata alloc]
- initWithHandler:metadataHandler]]];
+ initWithHandler:headersHandler]]];
[_wrappedCall startBatchWithOperations:@[[[GRPCOpRecvStatus alloc]
initWithHandler:completionHandler]]];
}
- (void)invokeCall {
__weak GRPCCall *weakSelf = self;
- [self invokeCallWithMetadataHandler:^(NSDictionary *headers) {
+ [self invokeCallWithHeadersHandler:^(NSDictionary *headers) {
// Response headers received.
GRPCCall *strongSelf = weakSelf;
if (strongSelf) {
- [strongSelf->_responseMetadata addEntriesFromDictionary:headers];
+ strongSelf.responseHeaders = headers;
[strongSelf startNextRead];
}
} completionHandler:^(NSError *error, NSDictionary *trailers) {
GRPCCall *strongSelf = weakSelf;
if (strongSelf) {
- [strongSelf->_responseMetadata addEntriesFromDictionary:trailers];
+ strongSelf.responseTrailers = trailers;
if (error) {
- NSMutableDictionary *userInfo =
- [NSMutableDictionary dictionaryWithDictionary:error.userInfo];
- userInfo[kGRPCStatusMetadataKey] = strongSelf->_responseMetadata;
+ NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
+ if (error.userInfo) {
+ [userInfo addEntriesFromDictionary:error.userInfo];
+ }
+ userInfo[kGRPCTrailersKey] = strongSelf.responseTrailers;
+ // TODO(jcanizales): The C gRPC library doesn't guarantee that the headers block will be
+ // called before this one, so an error might end up with trailers but no headers. We
+ // shouldn't call finishWithError until ater both blocks are called. It is also when this is
+ // done that we can provide a merged view of response headers and trailers in a thread-safe
+ // way.
+ if (strongSelf.responseHeaders) {
+ userInfo[kGRPCHeadersKey] = strongSelf.responseHeaders;
+ }
error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
}
[strongSelf finishWithError:error];
@@ -356,7 +363,7 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
_retainSelf = self;
_responseWriteable = [[GRXConcurrentWriteable alloc] initWithWriteable:writeable];
- [self sendHeaders:_requestMetadata];
+ [self sendHeaders:_requestHeaders];
[self invokeCall];
}