1 /* 2 * 3 * Copyright 2015 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 /** 20 * The gRPC protocol is an RPC protocol on top of HTTP2. 21 * 22 * While the most common type of RPC receives only one request message and returns only one response 23 * message, the protocol also supports RPCs that return multiple individual messages in a streaming 24 * fashion, RPCs that accept a stream of request messages, or RPCs with both streaming requests and 25 * responses. 26 * 27 * Conceptually, each gRPC call consists of a bidirectional stream of binary messages, with RPCs of 28 * the "non-streaming type" sending only one message in the corresponding direction (the protocol 29 * doesn't make any distinction). 30 * 31 * Each RPC uses a different HTTP2 stream, and thus multiple simultaneous RPCs can be multiplexed 32 * transparently on the same TCP connection. 33 */ 34 35 #import <Foundation/Foundation.h> 36 #import <RxLibrary/GRXWriter.h> 37 38 #include <AvailabilityMacros.h> 39 40 #pragma mark gRPC errors 41 42 /** Domain of NSError objects produced by gRPC. */ 43 extern NSString *const kGRPCErrorDomain; 44 45 /** 46 * gRPC error codes. 47 * Note that a few of these are never produced by the gRPC libraries, but are of general utility for 48 * server applications to produce. 49 */ 50 typedef NS_ENUM(NSUInteger, GRPCErrorCode) { 51 /** The operation was cancelled (typically by the caller). */ 52 GRPCErrorCodeCancelled = 1, 53 54 /** 55 * Unknown error. Errors raised by APIs that do not return enough error information may be 56 * converted to this error. 57 */ 58 GRPCErrorCodeUnknown = 2, 59 60 /** 61 * The client specified an invalid argument. Note that this differs from FAILED_PRECONDITION. 62 * INVALID_ARGUMENT indicates arguments that are problematic regardless of the state of the 63 * server (e.g., a malformed file name). 64 */ 65 GRPCErrorCodeInvalidArgument = 3, 66 67 /** 68 * Deadline expired before operation could complete. For operations that change the state of the 69 * server, this error may be returned even if the operation has completed successfully. For 70 * example, a successful response from the server could have been delayed long enough for the 71 * deadline to expire. 72 */ 73 GRPCErrorCodeDeadlineExceeded = 4, 74 75 /** Some requested entity (e.g., file or directory) was not found. */ 76 GRPCErrorCodeNotFound = 5, 77 78 /** Some entity that we attempted to create (e.g., file or directory) already exists. */ 79 GRPCErrorCodeAlreadyExists = 6, 80 81 /** 82 * The caller does not have permission to execute the specified operation. PERMISSION_DENIED isn't 83 * used for rejections caused by exhausting some resource (RESOURCE_EXHAUSTED is used instead for 84 * those errors). PERMISSION_DENIED doesn't indicate a failure to identify the caller 85 * (UNAUTHENTICATED is used instead for those errors). 86 */ 87 GRPCErrorCodePermissionDenied = 7, 88 89 /** 90 * The request does not have valid authentication credentials for the operation (e.g. the caller's 91 * identity can't be verified). 92 */ 93 GRPCErrorCodeUnauthenticated = 16, 94 95 /** Some resource has been exhausted, perhaps a per-user quota. */ 96 GRPCErrorCodeResourceExhausted = 8, 97 98 /** 99 * The RPC was rejected because the server is not in a state required for the procedure's 100 * execution. For example, a directory to be deleted may be non-empty, etc. 101 * The client should not retry until the server state has been explicitly fixed (e.g. by 102 * performing another RPC). The details depend on the service being called, and should be found in 103 * the NSError's userInfo. 104 */ 105 GRPCErrorCodeFailedPrecondition = 9, 106 107 /** 108 * The RPC was aborted, typically due to a concurrency issue like sequencer check failures, 109 * transaction aborts, etc. The client should retry at a higher-level (e.g., restarting a read- 110 * modify-write sequence). 111 */ 112 GRPCErrorCodeAborted = 10, 113 114 /** 115 * The RPC was attempted past the valid range. E.g., enumerating past the end of a list. 116 * Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed if the system state 117 * changes. For example, an RPC to get elements of a list will generate INVALID_ARGUMENT if asked 118 * to return the element at a negative index, but it will generate OUT_OF_RANGE if asked to return 119 * the element at an index past the current size of the list. 120 */ 121 GRPCErrorCodeOutOfRange = 11, 122 123 /** The procedure is not implemented or not supported/enabled in this server. */ 124 GRPCErrorCodeUnimplemented = 12, 125 126 /** 127 * Internal error. Means some invariant expected by the server application or the gRPC library has 128 * been broken. 129 */ 130 GRPCErrorCodeInternal = 13, 131 132 /** 133 * The server is currently unavailable. This is most likely a transient condition and may be 134 * corrected by retrying with a backoff. 135 */ 136 GRPCErrorCodeUnavailable = 14, 137 138 /** Unrecoverable data loss or corruption. */ 139 GRPCErrorCodeDataLoss = 15, 140 }; 141 142 /** 143 * Safety remark of a gRPC method as defined in RFC 2616 Section 9.1 144 */ 145 typedef NS_ENUM(NSUInteger, GRPCCallSafety) { 146 /** Signal that there is no guarantees on how the call affects the server state. */ 147 GRPCCallSafetyDefault = 0, 148 /** Signal that the call is idempotent. gRPC is free to use PUT verb. */ 149 GRPCCallSafetyIdempotentRequest = 1, 150 /** Signal that the call is cacheable and will not affect server state. gRPC is free to use GET 151 verb. */ 152 GRPCCallSafetyCacheableRequest = 2, 153 }; 154 155 /** 156 * Keys used in |NSError|'s |userInfo| dictionary to store the response headers and trailers sent by 157 * the server. 158 */ 159 extern id const kGRPCHeadersKey; 160 extern id const kGRPCTrailersKey; 161 162 #pragma mark GRPCCall 163 164 /** Represents a single gRPC remote call. */ 165 @interface GRPCCall : GRXWriter 166 167 /** 168 * The authority for the RPC. If nil, the default authority will be used. This property must be nil 169 * when Cronet transport is enabled. 170 */ 171 @property(atomic, copy, readwrite) NSString *serverName; 172 173 /** 174 * The timeout for the RPC call in seconds. If set to 0, the call will not timeout. If set to 175 * positive, the gRPC call returns with status GRPCErrorCodeDeadlineExceeded if it is not completed 176 * within \a timeout seconds. A negative value is not allowed. 177 */ 178 @property NSTimeInterval timeout; 179 180 /** 181 * The container of the request headers of an RPC conforms to this protocol, which is a subset of 182 * NSMutableDictionary's interface. It will become a NSMutableDictionary later on. 183 * The keys of this container are the header names, which per the HTTP standard are case- 184 * insensitive. They are stored in lowercase (which is how HTTP/2 mandates them on the wire), and 185 * can only consist of ASCII characters. 186 * A header value is a NSString object (with only ASCII characters), unless the header name has the 187 * suffix "-bin", in which case the value has to be a NSData object. 188 */ 189 /** 190 * These HTTP headers will be passed to the server as part of this call. Each HTTP header is a 191 * name-value pair with string names and either string or binary values. 192 * 193 * The passed dictionary has to use NSString keys, corresponding to the header names. The value 194 * associated to each can be a NSString object or a NSData object. E.g.: 195 * 196 * call.requestHeaders = @{@"authorization": @"Bearer ..."}; 197 * 198 * call.requestHeaders[@"my-header-bin"] = someData; 199 * 200 * After the call is started, trying to modify this property is an error. 201 * 202 * The property is initialized to an empty NSMutableDictionary. 203 */ 204 @property(atomic, readonly) NSMutableDictionary *requestHeaders; 205 206 /** 207 * This dictionary is populated with the HTTP headers received from the server. This happens before 208 * any response message is received from the server. It has the same structure as the request 209 * headers dictionary: Keys are NSString header names; names ending with the suffix "-bin" have a 210 * NSData value; the others have a NSString value. 211 * 212 * The value of this property is nil until all response headers are received, and will change before 213 * any of -writeValue: or -writesFinishedWithError: are sent to the writeable. 214 */ 215 @property(atomic, readonly) NSDictionary *responseHeaders; 216 217 /** 218 * Same as responseHeaders, but populated with the HTTP trailers received from the server before the 219 * call finishes. 220 * 221 * The value of this property is nil until all response trailers are received, and will change 222 * before -writesFinishedWithError: is sent to the writeable. 223 */ 224 @property(atomic, readonly) NSDictionary *responseTrailers; 225 226 /** 227 * The request writer has to write NSData objects into the provided Writeable. The server will 228 * receive each of those separately and in order as distinct messages. 229 * A gRPC call might not complete until the request writer finishes. On the other hand, the request 230 * finishing doesn't necessarily make the call to finish, as the server might continue sending 231 * messages to the response side of the call indefinitely (depending on the semantics of the 232 * specific remote method called). 233 * To finish a call right away, invoke cancel. 234 * host parameter should not contain the scheme (http:// or https://), only the name or IP addr 235 * and the port number, for example @"localhost:5050". 236 */ 237 - (instancetype)initWithHost:(NSString *)host 238 path:(NSString *)path 239 requestsWriter:(GRXWriter *)requestsWriter NS_DESIGNATED_INITIALIZER; 240 241 /** 242 * Finishes the request side of this call, notifies the server that the RPC should be cancelled, and 243 * finishes the response side of the call with an error of code CANCELED. 244 */ 245 - (void)cancel; 246 247 /** 248 * Set the call flag for a specific host path. 249 * 250 * Host parameter should not contain the scheme (http:// or https://), only the name or IP addr 251 * and the port number, for example @"localhost:5050". 252 */ 253 + (void)setCallSafety:(GRPCCallSafety)callSafety host:(NSString *)host path:(NSString *)path; 254 255 /** 256 * Set the dispatch queue to be used for callbacks. 257 * 258 * This configuration is only effective before the call starts. 259 */ 260 - (void)setResponseDispatchQueue:(dispatch_queue_t)queue; 261 262 // TODO(jcanizales): Let specify a deadline. As a category of GRXWriter? 263 @end 264 265 #pragma mark Backwards compatibiity 266 267 /** This protocol is kept for backwards compatibility with existing code. */ 268 DEPRECATED_MSG_ATTRIBUTE("Use NSDictionary or NSMutableDictionary instead.") 269 @protocol GRPCRequestHeaders<NSObject> 270 @property(nonatomic, readonly) NSUInteger count; 271 272 - (id)objectForKeyedSubscript:(id)key; 273 - (void)setObject:(id)obj forKeyedSubscript:(id)key; 274 275 - (void)removeAllObjects; 276 - (void)removeObjectForKey:(id)key; 277 @end 278 279 #pragma clang diagnostic push 280 #pragma clang diagnostic ignored "-Wdeprecated" 281 /** This is only needed for backwards-compatibility. */ 282 @interface NSMutableDictionary (GRPCRequestHeaders)<GRPCRequestHeaders> 283 @end 284 #pragma clang diagnostic pop 285