aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/objective-c
diff options
context:
space:
mode:
authorGravatar Jorge Canizales <jcanizales@google.com>2015-08-12 20:19:20 -0700
committerGravatar Jorge Canizales <jcanizales@google.com>2015-08-12 20:34:39 -0700
commit0b34c89bc6f72b3cfd46c1b63840849e1df2511d (patch)
tree8c3fca2e6b44dcae83bec6d3623ebe8eee87931b /src/objective-c
parent25884b305c4b3400cd8deb6e0708c12f0f898477 (diff)
Turn allResponseMetadata into *Headers and *Trailers
Diffstat (limited to 'src/objective-c')
-rw-r--r--src/objective-c/GRPCClient/GRPCCall+OAuth2.m2
-rw-r--r--src/objective-c/GRPCClient/GRPCCall.h21
-rw-r--r--src/objective-c/GRPCClient/GRPCCall.m33
3 files changed, 33 insertions, 23 deletions
diff --git a/src/objective-c/GRPCClient/GRPCCall+OAuth2.m b/src/objective-c/GRPCClient/GRPCCall+OAuth2.m
index 7f4fbacbe3..83b0de18e3 100644
--- a/src/objective-c/GRPCClient/GRPCCall+OAuth2.m
+++ b/src/objective-c/GRPCClient/GRPCCall+OAuth2.m
@@ -57,7 +57,7 @@ static NSString * const kChallengeHeader = @"www-authenticate";
}
- (NSString *)oauth2ChallengeHeader {
- return self.allResponseMetadata[kChallengeHeader];
+ return self.responseHeaders[kChallengeHeader];
}
@end
diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h
index 83a3ce5127..ffa133cee4 100644
--- a/src/objective-c/GRPCClient/GRPCCall.h
+++ b/src/objective-c/GRPCClient/GRPCCall.h
@@ -71,14 +71,21 @@ extern id const kGRPCStatusMetadataKey;
- (NSMutableDictionary *)requestHeaders; // nonatomic
- (void)setRequestHeaders:(NSDictionary *)requestHeaders; // nonatomic, copy
-// This dictionary is populated with the HTTP headers received from the server. When the RPC ends,
-// the HTTP trailers received are added to the dictionary too. It has the same structure as the
-// request metadata dictionary.
+// This dictionary is populated with the HTTP headers received from the server. This happens before
+// any response message is received from the server. It has the same structure as the request
+// headers dictionary: Keys are NSString header names; names ending with the suffix "-bin" have a
+// NSData value; the others have a NSString value.
//
-// The first time this object calls |writeValue| on the writeable passed to |startWithWriteable|,
-// the |responseMetadata| dictionary already contains the response headers. When it calls
-// |writesFinishedWithError|, the dictionary contains both the response headers and trailers.
-@property(atomic, readonly) NSDictionary *allResponseMetadata;
+// The value of this property is nil until all response headers are received, and will change before
+// any of -writeValue: or -writesFinishedWithError: are sent to the writeable.
+@property(atomic, readonly) NSDictionary *responseHeaders;
+
+// Same as responseHeaders, but populated with the HTTP trailers received from the server before the
+// call finishes.
+//
+// The value of this property is nil until all response trailers are received, and will change
+// before -writesFinishedWithError: is sent to the writeable.
+@property(atomic, readonly) NSDictionary *responseTrailers;
// The request writer has to write NSData objects into the provided Writeable. The server will
// receive each of those separately and in order as distinct messages.
diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m
index 0e5204d009..326def7f39 100644
--- a/src/objective-c/GRPCClient/GRPCCall.m
+++ b/src/objective-c/GRPCClient/GRPCCall.m
@@ -45,6 +45,9 @@
NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
@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
@@ -90,7 +93,6 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
GRPCCall *_retainSelf;
NSMutableDictionary *_requestHeaders;
- NSMutableDictionary *_allResponseMetadata;
}
@synthesize state = _state;
@@ -122,7 +124,6 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
_requestWriter = requestWriter;
_requestHeaders = [NSMutableDictionary dictionary];
- _allResponseMetadata = [NSMutableDictionary dictionary];
}
return self;
}
@@ -137,10 +138,6 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
_requestHeaders = [NSMutableDictionary dictionaryWithDictionary:requestHeaders];
}
-- (NSDictionary *)allResponseMetadata {
- return _allResponseMetadata;
-}
-
#pragma mark Finish
- (void)finishWithError:(NSError *)errorOrNil {
@@ -304,35 +301,41 @@ 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->_allResponseMetadata addEntriesFromDictionary:headers];
+ strongSelf.responseHeaders = headers;
[strongSelf startNextRead];
}
} completionHandler:^(NSError *error, NSDictionary *trailers) {
GRPCCall *strongSelf = weakSelf;
if (strongSelf) {
- [strongSelf->_allResponseMetadata addEntriesFromDictionary:trailers];
+ strongSelf.responseTrailers = trailers;
if (error) {
- NSMutableDictionary *userInfo =
- [NSMutableDictionary dictionaryWithDictionary:error.userInfo];
- userInfo[kGRPCStatusMetadataKey] = strongSelf->_allResponseMetadata;
+ NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
+ if (error.userInfo) {
+ [userInfo addEntriesFromDictionary:error.userInfo];
+ }
+ userInfo[kGRPCStatusMetadataKey] = 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 when this is done
+ // that we can provide a merged view of response headers and trailers in a thread-safe way.
error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
}
[strongSelf finishWithError:error];