Merge pull request #8223 from muxi/add-quic-support

Add QUIC support to Objective C
pull/8299/head
makdharma 8 years ago committed by GitHub
commit ba46906c92
  1. 19
      src/core/ext/transport/cronet/transport/cronet_transport.c
  2. 20
      src/objective-c/GRPCClient/GRPCCall.h
  3. 25
      src/objective-c/GRPCClient/GRPCCall.m
  4. 4
      src/objective-c/GRPCClient/private/GRPCWrappedCall.h
  5. 12
      src/objective-c/GRPCClient/private/GRPCWrappedCall.m
  6. 33
      src/objective-c/tests/GRPCClientTests.m

@ -542,7 +542,8 @@ static void create_grpc_frame(gpr_slice_buffer *write_slice_buffer,
*/
static void convert_metadata_to_cronet_headers(
grpc_linked_mdelem *head, const char *host, char **pp_url,
cronet_bidirectional_stream_header **pp_headers, size_t *p_num_headers) {
cronet_bidirectional_stream_header **pp_headers, size_t *p_num_headers,
const char ** method) {
grpc_linked_mdelem *curr = head;
/* Walk the linked list and get number of header fields */
size_t num_headers_available = 0;
@ -569,11 +570,20 @@ static void convert_metadata_to_cronet_headers(
curr = curr->next;
const char *key = grpc_mdstr_as_c_string(mdelem->key);
const char *value = grpc_mdstr_as_c_string(mdelem->value);
if (mdelem->key == GRPC_MDSTR_METHOD || mdelem->key == GRPC_MDSTR_SCHEME ||
if (mdelem->key == GRPC_MDSTR_SCHEME ||
mdelem->key == GRPC_MDSTR_AUTHORITY) {
/* Cronet populates these fields on its own */
continue;
}
if (mdelem->key == GRPC_MDSTR_METHOD) {
if (mdelem->value == GRPC_MDSTR_PUT) {
*method = "PUT";
} else {
/* POST method in default*/
*method = "POST";
}
continue;
}
if (mdelem->key == GRPC_MDSTR_PATH) {
/* Create URL by appending :path value to the hostname */
gpr_asprintf(pp_url, "https://%s%s", host, value);
@ -771,14 +781,15 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
&cronet_callbacks);
CRONET_LOG(GPR_DEBUG, "%p = cronet_bidirectional_stream_create()", s->cbs);
char *url;
const char *method;
s->header_array.headers = NULL;
convert_metadata_to_cronet_headers(
stream_op->send_initial_metadata->list.head, s->curr_ct.host, &url,
&s->header_array.headers, &s->header_array.count);
&s->header_array.headers, &s->header_array.count, &method);
s->header_array.capacity = s->header_array.count;
CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_start(%p, %s)", s->cbs,
url);
cronet_bidirectional_stream_start(s->cbs, url, 0, "POST", &s->header_array,
cronet_bidirectional_stream_start(s->cbs, url, 0, method, &s->header_array,
false);
stream_state->state_op_done[OP_SEND_INITIAL_METADATA] = true;
result = ACTION_TAKEN_WITH_CALLBACK;

@ -154,6 +154,18 @@ typedef NS_ENUM(NSUInteger, GRPCErrorCode) {
GRPCErrorCodeDataLoss = 15,
};
/**
* Safety remark of a gRPC method as defined in RFC 2616 Section 9.1
*/
typedef NS_ENUM(NSUInteger, GRPCCallSafety) {
/** Signal that there is no guarantees on how the call affects the server state. */
GRPCCallSafetyDefault = 0,
/** Signal that the call is idempotent. gRPC is free to use PUT verb. */
GRPCCallSafetyIdempotentRequest = 1,
/** Signal that the call is cacheable and will not affect server state. gRPC is free to use GET verb. */
GRPCCallSafetyCacheableRequest = 2,
};
/**
* Keys used in |NSError|'s |userInfo| dictionary to store the response headers and trailers sent by
* the server.
@ -233,6 +245,14 @@ extern id const kGRPCTrailersKey;
*/
- (void)cancel;
/**
* Set the call flag for a specific host path.
*
* Host parameter should not contain the scheme (http:// or https://), only the name or IP addr
* and the port number, for example @"localhost:5050".
*/
+ (void)setCallSafety:(GRPCCallSafety)callSafety host:(NSString *)host path:(NSString *)path;
// TODO(jcanizales): Let specify a deadline. As a category of GRXWriter?
@end

@ -47,6 +47,7 @@
NSString * const kGRPCHeadersKey = @"io.grpc.HeadersKey";
NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
static NSMutableDictionary *callFlags;
@interface GRPCCall () <GRXWriteable>
// Make them read-write.
@ -106,6 +107,29 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
// TODO(jcanizales): If grpc_init is idempotent, this should be changed from load to initialize.
+ (void)load {
grpc_init();
callFlags = [NSMutableDictionary dictionary];
}
+ (void)setCallSafety:(GRPCCallSafety)callSafety host:(NSString *)host path:(NSString *)path {
NSString *hostAndPath = [NSString stringWithFormat:@"%@/%@", host, path];
switch (callSafety) {
case GRPCCallSafetyDefault:
callFlags[hostAndPath] = @0;
break;
case GRPCCallSafetyIdempotentRequest:
callFlags[hostAndPath] = @GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST;
break;
case GRPCCallSafetyCacheableRequest:
callFlags[hostAndPath] = @GRPC_INITIAL_METADATA_CACHEABLE_REQUEST;
break;
default:
break;
}
}
+ (uint32_t)callFlagsForHost:(NSString *)host path:(NSString *)path {
NSString *hostAndPath = [NSString stringWithFormat:@"%@/%@", host, path];
return [callFlags[hostAndPath] intValue];
}
- (instancetype)init {
@ -231,6 +255,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
flags:[GRPCCall callFlagsForHost:_host path:_path]
handler:nil]]];
}

@ -45,6 +45,10 @@
@interface GRPCOpSendMetadata : GRPCOperation
- (instancetype)initWithMetadata:(NSDictionary *)metadata
handler:(void(^)())handler;
- (instancetype)initWithMetadata:(NSDictionary *)metadata
flags:(uint32_t)flags
handler:(void(^)())handler NS_DESIGNATED_INITIALIZER;
@end

@ -64,16 +64,24 @@
@implementation GRPCOpSendMetadata
- (instancetype)init {
return [self initWithMetadata:nil handler:nil];
return [self initWithMetadata:nil flags:0 handler:nil];
}
- (instancetype)initWithMetadata:(NSDictionary *)metadata handler:(void (^)())handler {
- (instancetype)initWithMetadata:(NSDictionary *)metadata
handler:(void (^)())handler {
return [self initWithMetadata:metadata flags:0 handler:handler];
}
- (instancetype)initWithMetadata:(NSDictionary *)metadata
flags:(uint32_t)flags
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;
_op.flags = flags;
_handler = handler;
}
return self;

@ -317,4 +317,37 @@ static GRPCProtoMethod *kUnaryCallMethod;
}
- (void)testIdempotentProtoRPC {
__weak XCTestExpectation *response = [self expectationWithDescription:@"Expected response."];
__weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
RMTSimpleRequest *request = [RMTSimpleRequest message];
request.responseSize = 100;
request.fillUsername = YES;
request.fillOauthScope = YES;
GRXWriter *requestsWriter = [GRXWriter writerWithValue:[request data]];
GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress
path:kUnaryCallMethod.HTTPPath
requestsWriter:requestsWriter];
[GRPCCall setCallSafety:GRPCCallSafetyIdempotentRequest host:kHostAddress path:kUnaryCallMethod.HTTPPath];
id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
XCTAssertNotNil(value, @"nil value received as response.");
XCTAssertGreaterThan(value.length, 0, @"Empty response received.");
RMTSimpleResponse *responseProto = [RMTSimpleResponse parseFromData:value error:NULL];
// We expect empty strings, not nil:
XCTAssertNotNil(responseProto.username, @"Response's username is nil.");
XCTAssertNotNil(responseProto.oauthScope, @"Response's OAuth scope is nil.");
[response fulfill];
} completionHandler:^(NSError *errorOrNil) {
XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil);
[completion fulfill];
}];
[call startWithWriteable:responsesWriteable];
[self waitForExpectationsWithTimeout:8 handler:nil];
}
@end

Loading…
Cancel
Save