static void test_compression_algorithm_parse(void) { size_t i; const char *valid_names[] = {"identity", "gzip", "deflate"}; const grpc_compression_algorithm valid_algorithms[] = { GRPC_COMPRESS_NONE, GRPC_COMPRESS_GZIP, GRPC_COMPRESS_DEFLATE}; const char *invalid_names[] = {"gzip2", "foo", "", "2gzip"}; gpr_log(GPR_DEBUG, "test_compression_algorithm_parse"); for (i = 0; i < GPR_ARRAY_SIZE(valid_names); i++) { const char *valid_name = valid_names[i]; grpc_compression_algorithm algorithm; const int success = grpc_compression_algorithm_parse( valid_name, strlen(valid_name), &algorithm); GPR_ASSERT(success != 0); GPR_ASSERT(algorithm == valid_algorithms[i]); } for (i = 0; i < GPR_ARRAY_SIZE(invalid_names); i++) { const char *invalid_name = invalid_names[i]; grpc_compression_algorithm algorithm; int success; success = grpc_compression_algorithm_parse( invalid_name, strlen(invalid_name), &algorithm); GPR_ASSERT(success == 0); /* the value of "algorithm" is undefined upon failure */ } }
/** For each \a md element from the incoming metadata, filter out the entry for * "grpc-encoding", using its value to populate the call data's * compression_algorithm field. */ static grpc_mdelem *compression_md_filter(void *user_data, grpc_mdelem *md) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; if (md->key == GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST) { const char *md_c_str = grpc_mdstr_as_c_string(md->value); if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str), &calld->compression_algorithm)) { gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s' (unknown). Ignoring.", md_c_str); calld->compression_algorithm = GRPC_COMPRESS_NONE; } if (grpc_compression_options_is_algorithm_enabled( &channeld->compression_options, calld->compression_algorithm) == 0) { gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s' (previously disabled). " "Ignoring.", md_c_str); calld->compression_algorithm = GRPC_COMPRESS_NONE; } calld->has_compression_algorithm = 1; return NULL; } return md; }
static void test_algorithm_mesh(void) { int i; gpr_log(GPR_DEBUG, "test_algorithm_mesh"); for (i = 0; i < GRPC_COMPRESS_ALGORITHMS_COUNT; i++) { const char *name; grpc_compression_algorithm parsed; grpc_slice mdstr; grpc_mdelem mdelem; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; GPR_ASSERT( grpc_compression_algorithm_name((grpc_compression_algorithm)i, &name)); GPR_ASSERT(grpc_compression_algorithm_parse( grpc_slice_from_static_string(name), &parsed)); GPR_ASSERT((int)parsed == i); mdstr = grpc_slice_from_copied_string(name); GPR_ASSERT(grpc_slice_eq(mdstr, grpc_compression_algorithm_slice(parsed))); GPR_ASSERT(parsed == grpc_compression_algorithm_from_slice(mdstr)); mdelem = grpc_compression_encoding_mdelem(parsed); GPR_ASSERT(grpc_slice_eq(GRPC_MDVALUE(mdelem), mdstr)); GPR_ASSERT(grpc_slice_eq(GRPC_MDKEY(mdelem), GRPC_MDSTR_GRPC_ENCODING)); grpc_slice_unref_internal(&exec_ctx, mdstr); GRPC_MDELEM_UNREF(&exec_ctx, mdelem); grpc_exec_ctx_finish(&exec_ctx); } /* test failure */ GPR_ASSERT(GRPC_MDISNULL( grpc_compression_encoding_mdelem(GRPC_COMPRESS_ALGORITHMS_COUNT))); }
/* Gets the internal value of a compression algorithm suitable as the value * in a GRPC core channel arguments hash. * algorithm_value is an out parameter. * Raises an error if the name of the algorithm passed in is invalid. */ void grpc_rb_compression_options_algorithm_name_to_value_internal( grpc_compression_algorithm* algorithm_value, VALUE algorithm_name) { grpc_slice name_slice; VALUE algorithm_name_as_string = Qnil; Check_Type(algorithm_name, T_SYMBOL); /* Convert the algorithm symbol to a ruby string, so that we can get the * correct C string out of it. */ algorithm_name_as_string = rb_funcall(algorithm_name, rb_intern("to_s"), 0); name_slice = grpc_slice_from_copied_buffer(RSTRING_PTR(algorithm_name_as_string), RSTRING_LEN(algorithm_name_as_string)); /* Raise an error if the name isn't recognized as a compression algorithm by * the algorithm parse function * in GRPC core. */ if (!grpc_compression_algorithm_parse(name_slice, algorithm_value)) { char* name_slice_str = grpc_slice_to_c_string(name_slice); char* error_message_str = NULL; VALUE error_message_ruby_str = Qnil; GPR_ASSERT(gpr_asprintf(&error_message_str, "Invalid compression algorithm name: %s", name_slice_str) != -1); gpr_free(name_slice_str); error_message_ruby_str = rb_str_new(error_message_str, strlen(error_message_str)); gpr_free(error_message_str); rb_raise(rb_eNameError, "%s", StringValueCStr(error_message_ruby_str)); } grpc_slice_unref(name_slice); }
static grpc_error *process_send_initial_metadata( grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_metadata_batch *initial_metadata, bool *has_compression_algorithm) { call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; *has_compression_algorithm = false; /* Parse incoming request for compression. If any, it'll be available * at calld->compression_algorithm */ if (initial_metadata->idx.named.grpc_internal_encoding_request != NULL) { grpc_mdelem md = initial_metadata->idx.named.grpc_internal_encoding_request->md; if (!grpc_compression_algorithm_parse(GRPC_MDVALUE(md), &calld->compression_algorithm)) { char *val = grpc_slice_to_c_string(GRPC_MDVALUE(md)); gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s' (unknown). Ignoring.", val); gpr_free(val); calld->compression_algorithm = GRPC_COMPRESS_NONE; } if (!GPR_BITGET(channeld->enabled_algorithms_bitset, calld->compression_algorithm)) { char *val = grpc_slice_to_c_string(GRPC_MDVALUE(md)); gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s' (previously disabled). " "Ignoring.", val); gpr_free(val); calld->compression_algorithm = GRPC_COMPRESS_NONE; } *has_compression_algorithm = true; grpc_metadata_batch_remove( exec_ctx, initial_metadata, initial_metadata->idx.named.grpc_internal_encoding_request); } else { /* If no algorithm was found in the metadata and we aren't * exceptionally skipping compression, fall back to the channel * default */ calld->compression_algorithm = channeld->default_compression_algorithm; *has_compression_algorithm = true; } grpc_error *error = GRPC_ERROR_NONE; /* hint compression algorithm */ if (calld->compression_algorithm != GRPC_COMPRESS_NONE) { error = grpc_metadata_batch_add_tail( exec_ctx, initial_metadata, &calld->compression_algorithm_storage, grpc_compression_encoding_mdelem(calld->compression_algorithm)); } if (error != GRPC_ERROR_NONE) return error; /* convey supported compression algorithms */ error = grpc_metadata_batch_add_tail( exec_ctx, initial_metadata, &calld->accept_encoding_storage, GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS( channeld->supported_compression_algorithms)); return error; }
static void set_encodings_accepted_by_peer(grpc_call *call, grpc_mdelem *mdel) { size_t i; grpc_compression_algorithm algorithm; gpr_slice_buffer accept_encoding_parts; gpr_slice accept_encoding_slice; void *accepted_user_data; accepted_user_data = grpc_mdelem_get_user_data(mdel, destroy_encodings_accepted_by_peer); if (accepted_user_data != NULL) { call->encodings_accepted_by_peer = (gpr_uint32)(((gpr_uintptr)accepted_user_data) - 1); return; } accept_encoding_slice = mdel->value->slice; gpr_slice_buffer_init(&accept_encoding_parts); gpr_slice_split(accept_encoding_slice, ",", &accept_encoding_parts); /* No need to zero call->encodings_accepted_by_peer: grpc_call_create already * zeroes the whole grpc_call */ /* Always support no compression */ GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE); for (i = 0; i < accept_encoding_parts.count; i++) { const gpr_slice *accept_encoding_entry_slice = &accept_encoding_parts.slices[i]; if (grpc_compression_algorithm_parse( (const char *)GPR_SLICE_START_PTR(*accept_encoding_entry_slice), GPR_SLICE_LENGTH(*accept_encoding_entry_slice), &algorithm)) { GPR_BITSET(&call->encodings_accepted_by_peer, algorithm); } else { char *accept_encoding_entry_str = gpr_dump_slice(*accept_encoding_entry_slice, GPR_DUMP_ASCII); gpr_log(GPR_ERROR, "Invalid entry in accept encoding metadata: '%s'. Ignoring.", accept_encoding_entry_str); gpr_free(accept_encoding_entry_str); } } gpr_slice_buffer_destroy(&accept_encoding_parts); grpc_mdelem_set_user_data( mdel, destroy_encodings_accepted_by_peer, (void *)(((gpr_uintptr)call->encodings_accepted_by_peer) + 1)); }
static gpr_uint32 decode_compression(grpc_mdelem *md) { grpc_compression_algorithm algorithm; void *user_data = grpc_mdelem_get_user_data(md, destroy_compression); if (user_data) { algorithm = ((grpc_compression_algorithm)(gpr_intptr)user_data) - COMPRESS_OFFSET; } else { const char *md_c_str = grpc_mdstr_as_c_string(md->value); if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str), &algorithm)) { gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'", md_c_str); assert(0); } grpc_mdelem_set_user_data( md, destroy_compression, (void *)(gpr_intptr)(algorithm + COMPRESS_OFFSET)); } return algorithm; }
/** For each \a md element from the incoming metadata, filter out the entry for * "grpc-encoding", using its value to populate the call data's * compression_algorithm field. */ static grpc_mdelem *compression_md_filter(void *user_data, grpc_mdelem *md) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; if (md->key == channeld->mdstr_request_compression_algorithm_key) { const char *md_c_str = grpc_mdstr_as_c_string(md->value); if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str), &calld->compression_algorithm)) { gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'. Ignoring.", md_c_str); calld->compression_algorithm = GRPC_COMPRESS_NONE; } calld->has_compression_algorithm = 1; return NULL; } return md; }