From fdea83d42afbebfecfea1edf9143619640115824 Mon Sep 17 00:00:00 2001
From: Muxi Yan <mxyan@google.com>
Date: Tue, 27 Sep 2016 16:11:18 -0700
Subject: [PATCH] Update grpc objc API for support of PUT method

---
 src/objective-c/GRPCClient/GRPCCall.h              |  7 ++++++-
 src/objective-c/GRPCClient/GRPCCall.m              | 14 ++++++++++++--
 .../GRPCClient/private/GRPCWrappedCall.h           |  4 ++++
 .../GRPCClient/private/GRPCWrappedCall.m           | 14 ++++++++++++--
 src/objective-c/ProtoRPC/ProtoRPC.h                |  3 ++-
 src/objective-c/ProtoRPC/ProtoRPC.m                |  9 ++++++---
 src/objective-c/ProtoRPC/ProtoService.h            |  3 ++-
 src/objective-c/ProtoRPC/ProtoService.m            |  6 ++++--
 8 files changed, 48 insertions(+), 12 deletions(-)

diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h
index b9e741dfa8..fc59e5f5e9 100644
--- a/src/objective-c/GRPCClient/GRPCCall.h
+++ b/src/objective-c/GRPCClient/GRPCCall.h
@@ -225,7 +225,12 @@ extern id const kGRPCTrailersKey;
  */
 - (instancetype)initWithHost:(NSString *)host
                         path:(NSString *)path
-              requestsWriter:(GRXWriter *)requestsWriter NS_DESIGNATED_INITIALIZER;
+              requestsWriter:(GRXWriter *)requestsWriter;
+
+- (instancetype)initWithHost:(NSString *)host
+                        path:(NSString *)path
+              requestsWriter:(GRXWriter *)requestsWriter
+                 http2Method:(NSString *)http2Method NS_DESIGNATED_INITIALIZER;
 
 /**
  * Finishes the request side of this call, notifies the server that the RPC should be cancelled, and
diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m
index eecda4c03a..6bd80c8b3f 100644
--- a/src/objective-c/GRPCClient/GRPCCall.m
+++ b/src/objective-c/GRPCClient/GRPCCall.m
@@ -75,6 +75,7 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
 
   NSString *_host;
   NSString *_path;
+  NSString *_http2Method;
   GRPCWrappedCall *_wrappedCall;
   GRPCConnectivityMonitor *_connectivityMonitor;
 
@@ -109,13 +110,20 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
 }
 
 - (instancetype)init {
-  return [self initWithHost:nil path:nil requestsWriter:nil];
+  return [self initWithHost:nil path:nil requestsWriter:nil http2Method:nil];
+}
+
+- (instancetype)initWithHost:(NSString *)host
+                        path:(NSString *)path
+              requestsWriter:(GRXWriter *)requestWriter{
+  return [self initWithHost:host path:path requestsWriter:requestWriter http2Method:@"POST"];
 }
 
 // Designated initializer
 - (instancetype)initWithHost:(NSString *)host
                         path:(NSString *)path
-              requestsWriter:(GRXWriter *)requestWriter {
+              requestsWriter:(GRXWriter *)requestWriter
+                 http2Method:(NSString *)http2Method {
   if (!host || !path) {
     [NSException raise:NSInvalidArgumentException format:@"Neither host nor path can be nil."];
   }
@@ -126,6 +134,7 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
   if ((self = [super init])) {
     _host = [host copy];
     _path = [path copy];
+    _http2Method = http2Method;
 
     // Serial queue to invoke the non-reentrant methods of the grpc_call object.
     _callQueue = dispatch_queue_create("io.grpc.call", NULL);
@@ -231,6 +240,7 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
 - (void)sendHeaders:(NSDictionary *)headers {
   // TODO(jcanizales): Add error handlers for async failures
   [_wrappedCall startBatchWithOperations:@[[[GRPCOpSendMetadata alloc] initWithMetadata:headers
+                                                                            http2Method:_http2Method
                                                                                 handler:nil]]];
 }
 
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
index e37ed1b59f..8b64b27e56 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
@@ -45,6 +45,10 @@
 @interface GRPCOpSendMetadata : GRPCOperation
 
 - (instancetype)initWithMetadata:(NSDictionary *)metadata
+                         handler:(void(^)())handler;
+
+- (instancetype)initWithMetadata:(NSDictionary *)metadata
+                     http2Method:(NSString *)http2Method
                          handler:(void(^)())handler NS_DESIGNATED_INITIALIZER;
 
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
index 1339429660..2836f99bf1 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
@@ -64,16 +64,26 @@
 @implementation GRPCOpSendMetadata
 
 - (instancetype)init {
-  return [self initWithMetadata:nil handler:nil];
+  return [self initWithMetadata:nil http2Method:nil handler:nil];
 }
 
-- (instancetype)initWithMetadata:(NSDictionary *)metadata handler:(void (^)())handler {
+- (instancetype)initWithMetadata:(NSDictionary *)metadata
+                         handler:(void (^)())handler {
+  return [self initWithMetadata:metadata http2Method:@"POST" handler:handler];
+}
+
+- (instancetype)initWithMetadata:(NSDictionary *)metadata
+                     http2Method:(NSString *)http2Method
+                         handler:(void (^)())handler {
   if (self = [super init]) {
     _op.op = GRPC_OP_SEND_INITIAL_METADATA;
     _op.data.send_initial_metadata.count = metadata.count;
     _op.data.send_initial_metadata.metadata = metadata.grpc_metadataArray;
     _op.data.send_initial_metadata.maybe_compression_level.is_set = false;
     _op.data.send_initial_metadata.maybe_compression_level.level = 0;
+    if ([http2Method isEqualToString:@"PUT"]) {
+      _op.flags = GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST;
+    }
     _handler = handler;
   }
   return self;
diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h
index 04fc1e45f1..509a15abae 100644
--- a/src/objective-c/ProtoRPC/ProtoRPC.h
+++ b/src/objective-c/ProtoRPC/ProtoRPC.h
@@ -47,7 +47,8 @@ __attribute__((deprecated("Please use GRPCProtoCall.")))
                       method:(GRPCProtoMethod *)method
               requestsWriter:(GRXWriter *)requestsWriter
                responseClass:(Class)responseClass
-          responsesWriteable:(id<GRXWriteable>)responsesWriteable NS_DESIGNATED_INITIALIZER;
+          responsesWriteable:(id<GRXWriteable>)responsesWriteable
+                 http2Method:(NSString *)http2Method NS_DESIGNATED_INITIALIZER;
 
 - (void)start;
 @end
diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m
index 83d1b655e8..67405d2a19 100644
--- a/src/objective-c/ProtoRPC/ProtoRPC.m
+++ b/src/objective-c/ProtoRPC/ProtoRPC.m
@@ -65,7 +65,8 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing
 #pragma clang diagnostic ignored "-Wobjc-designated-initializers"
 - (instancetype)initWithHost:(NSString *)host
                         path:(NSString *)path
-              requestsWriter:(GRXWriter *)requestsWriter {
+              requestsWriter:(GRXWriter *)requestsWriter
+                 http2Method:(NSString *)http2Method {
   [NSException raise:NSInvalidArgumentException
               format:@"Please use ProtoRPC's designated initializer instead."];
   return nil;
@@ -77,7 +78,8 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing
                       method:(GRPCProtoMethod *)method
               requestsWriter:(GRXWriter *)requestsWriter
                responseClass:(Class)responseClass
-          responsesWriteable:(id<GRXWriteable>)responsesWriteable {
+          responsesWriteable:(id<GRXWriteable>)responsesWriteable
+                 http2Method:(NSString *)http2Method {
   // Because we can't tell the type system to constrain the class, we need to check at runtime:
   if (![responseClass respondsToSelector:@selector(parseFromData:error:)]) {
     [NSException raise:NSInvalidArgumentException
@@ -91,7 +93,8 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing
     }
     return [proto data];
   }];
-  if ((self = [super initWithHost:host path:method.HTTPPath requestsWriter:bytesWriter])) {
+  if ((self = [super initWithHost:host path:method.HTTPPath requestsWriter:bytesWriter
+                      http2Method:http2Method])) {
     __weak ProtoRPC *weakSelf = self;
 
     // A writeable that parses the proto messages received.
diff --git a/src/objective-c/ProtoRPC/ProtoService.h b/src/objective-c/ProtoRPC/ProtoService.h
index 7faae1b49c..80fab37fd5 100644
--- a/src/objective-c/ProtoRPC/ProtoService.h
+++ b/src/objective-c/ProtoRPC/ProtoService.h
@@ -47,7 +47,8 @@ __attribute__((deprecated("Please use GRPCProtoService.")))
 - (GRPCProtoCall *)RPCToMethod:(NSString *)method
            requestsWriter:(GRXWriter *)requestsWriter
   	        responseClass:(Class)responseClass
-  	   responsesWriteable:(id<GRXWriteable>)responsesWriteable;
+  	   responsesWriteable:(id<GRXWriteable>)responsesWriteable
+                   http2Method:(NSString *)http2Method;
 @end
 
 
diff --git a/src/objective-c/ProtoRPC/ProtoService.m b/src/objective-c/ProtoRPC/ProtoService.m
index 3487fac59d..fc3e017072 100644
--- a/src/objective-c/ProtoRPC/ProtoService.m
+++ b/src/objective-c/ProtoRPC/ProtoService.m
@@ -68,7 +68,8 @@
 - (GRPCProtoCall *)RPCToMethod:(NSString *)method
                 requestsWriter:(GRXWriter *)requestsWriter
                  responseClass:(Class)responseClass
-            responsesWriteable:(id<GRXWriteable>)responsesWriteable {
+            responsesWriteable:(id<GRXWriteable>)responsesWriteable
+                   http2Method:(NSString *)http2Method {
   GRPCProtoMethod *methodName = [[GRPCProtoMethod alloc] initWithPackage:_packageName
                                                                  service:_serviceName
                                                                   method:method];
@@ -76,7 +77,8 @@
                                       method:methodName
                               requestsWriter:requestsWriter
                                responseClass:responseClass
-                          responsesWriteable:responsesWriteable];
+                          responsesWriteable:responsesWriteable
+                                 http2Method:http2Method];
 }
 @end
 
-- 
GitLab