|  | @@ -40,6 +40,7 @@
 | 
	
		
			
				|  |  |  #include <grpc/grpc.h>
 | 
	
		
			
				|  |  |  #include <grpc/support/alloc.h>
 | 
	
		
			
				|  |  |  #include <grpc/support/log.h>
 | 
	
		
			
				|  |  | +#include <grpc/support/slice.h>
 | 
	
		
			
				|  |  |  #include <grpc/support/string_util.h>
 | 
	
		
			
				|  |  |  #include <grpc/support/useful.h>
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -52,7 +53,9 @@
 | 
	
		
			
				|  |  |  #include "src/core/lib/surface/call.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/surface/channel.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/surface/completion_queue.h"
 | 
	
		
			
				|  |  | +#include "src/core/lib/transport/metadata.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/transport/static_metadata.h"
 | 
	
		
			
				|  |  | +#include "src/core/lib/transport/transport.h"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /** The maximum number of concurrent batches possible.
 | 
	
		
			
				|  |  |      Based upon the maximum number of individually queueable ops in the batch
 | 
	
	
		
			
				|  | @@ -238,6 +241,9 @@ static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
 | 
	
		
			
				|  |  |  static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
 | 
	
		
			
				|  |  |                                            grpc_status_code status,
 | 
	
		
			
				|  |  |                                            const char *description);
 | 
	
		
			
				|  |  | +static grpc_call_error close_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
 | 
	
		
			
				|  |  | +                                         grpc_status_code status,
 | 
	
		
			
				|  |  | +                                         const char *description);
 | 
	
		
			
				|  |  |  static void destroy_call(grpc_exec_ctx *exec_ctx, void *call_stack,
 | 
	
		
			
				|  |  |                           bool success);
 | 
	
		
			
				|  |  |  static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
 | 
	
	
		
			
				|  | @@ -408,8 +414,8 @@ static void set_status_code(grpc_call *call, status_source source,
 | 
	
		
			
				|  |  |    /* TODO(ctiller): what to do about the flush that was previously here */
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void set_compression_algorithm(grpc_call *call,
 | 
	
		
			
				|  |  | -                                      grpc_compression_algorithm algo) {
 | 
	
		
			
				|  |  | +static void set_incoming_compression_algorithm(
 | 
	
		
			
				|  |  | +    grpc_call *call, grpc_compression_algorithm algo) {
 | 
	
		
			
				|  |  |    GPR_ASSERT(algo < GRPC_COMPRESS_ALGORITHMS_COUNT);
 | 
	
		
			
				|  |  |    call->incoming_compression_algorithm = algo;
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -425,61 +431,8 @@ grpc_compression_algorithm grpc_call_test_only_get_compression_algorithm(
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static grpc_compression_algorithm compression_algorithm_for_level_locked(
 | 
	
		
			
				|  |  |      grpc_call *call, grpc_compression_level level) {
 | 
	
		
			
				|  |  | -  /* Establish a "ranking" or compression algorithms in increasing order of
 | 
	
		
			
				|  |  | -   * compression.
 | 
	
		
			
				|  |  | -   * This is simplistic and we will probably want to introduce other
 | 
	
		
			
				|  |  | -   * dimensions
 | 
	
		
			
				|  |  | -   * in the future (cpu/memory cost, etc). */
 | 
	
		
			
				|  |  | -  const grpc_compression_algorithm algos_ranking[] = {GRPC_COMPRESS_GZIP,
 | 
	
		
			
				|  |  | -                                                      GRPC_COMPRESS_DEFLATE};
 | 
	
		
			
				|  |  | -  const uint32_t accepted_encodings = call->encodings_accepted_by_peer;
 | 
	
		
			
				|  |  | -  if (level > GRPC_COMPRESS_LEVEL_HIGH) {
 | 
	
		
			
				|  |  | -    extern int grpc_compression_trace;
 | 
	
		
			
				|  |  | -    if (grpc_compression_trace) {
 | 
	
		
			
				|  |  | -      gpr_log(GPR_ERROR,
 | 
	
		
			
				|  |  | -              "Unknown compression level %d. Compression will be disabled.",
 | 
	
		
			
				|  |  | -              (int)level);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    return GRPC_COMPRESS_NONE;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  const size_t num_supported =
 | 
	
		
			
				|  |  | -      GPR_BITCOUNT(accepted_encodings) - 1; /* discard NONE */
 | 
	
		
			
				|  |  | -  if (level == GRPC_COMPRESS_LEVEL_NONE || num_supported == 0) {
 | 
	
		
			
				|  |  | -    return GRPC_COMPRESS_NONE;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  GPR_ASSERT(level > 0);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* intersect algos_ranking with the supported ones keeping the ranked order
 | 
	
		
			
				|  |  | -   */
 | 
	
		
			
				|  |  | -  grpc_compression_algorithm
 | 
	
		
			
				|  |  | -      sorted_supported_algos[GRPC_COMPRESS_ALGORITHMS_COUNT];
 | 
	
		
			
				|  |  | -  size_t algos_supported_idx = 0;
 | 
	
		
			
				|  |  | -  for (size_t i = 0; i < GPR_ARRAY_SIZE(algos_ranking); i++) {
 | 
	
		
			
				|  |  | -    const grpc_compression_algorithm alg = algos_ranking[i];
 | 
	
		
			
				|  |  | -    for (size_t j = 0; j < num_supported; j++) {
 | 
	
		
			
				|  |  | -      if (GPR_BITGET(accepted_encodings, alg) == 1) {
 | 
	
		
			
				|  |  | -        /* if \a alg in supported */
 | 
	
		
			
				|  |  | -        sorted_supported_algos[algos_supported_idx++] = alg;
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    if (algos_supported_idx == num_supported) break;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  switch (level) {
 | 
	
		
			
				|  |  | -    case GRPC_COMPRESS_LEVEL_NONE:
 | 
	
		
			
				|  |  | -      abort(); /* should have been handled already */
 | 
	
		
			
				|  |  | -    case GRPC_COMPRESS_LEVEL_LOW:
 | 
	
		
			
				|  |  | -      return sorted_supported_algos[0];
 | 
	
		
			
				|  |  | -    case GRPC_COMPRESS_LEVEL_MED:
 | 
	
		
			
				|  |  | -      return sorted_supported_algos[num_supported / 2];
 | 
	
		
			
				|  |  | -    case GRPC_COMPRESS_LEVEL_HIGH:
 | 
	
		
			
				|  |  | -      return sorted_supported_algos[num_supported - 1];
 | 
	
		
			
				|  |  | -    default:
 | 
	
		
			
				|  |  | -      abort();
 | 
	
		
			
				|  |  | -  };
 | 
	
		
			
				|  |  | +  return grpc_compression_algorithm_for_level(level,
 | 
	
		
			
				|  |  | +                                              call->encodings_accepted_by_peer);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  uint32_t grpc_call_test_only_get_message_flags(grpc_call *call) {
 | 
	
	
		
			
				|  | @@ -793,48 +746,102 @@ grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
 | 
	
		
			
				|  |  |    return r;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -typedef struct cancel_closure {
 | 
	
		
			
				|  |  | +typedef struct termination_closure {
 | 
	
		
			
				|  |  |    grpc_closure closure;
 | 
	
		
			
				|  |  |    grpc_call *call;
 | 
	
		
			
				|  |  |    grpc_status_code status;
 | 
	
		
			
				|  |  | -} cancel_closure;
 | 
	
		
			
				|  |  | +  gpr_slice optional_message;
 | 
	
		
			
				|  |  | +  grpc_closure *op_closure;
 | 
	
		
			
				|  |  | +  enum { TC_CANCEL, TC_CLOSE } type;
 | 
	
		
			
				|  |  | +} termination_closure;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void done_termination(grpc_exec_ctx *exec_ctx, void *tcp, bool success) {
 | 
	
		
			
				|  |  | +  termination_closure *tc = tcp;
 | 
	
		
			
				|  |  | +  if (tc->type == TC_CANCEL) {
 | 
	
		
			
				|  |  | +    GRPC_CALL_INTERNAL_UNREF(exec_ctx, tc->call, "cancel");
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (tc->type == TC_CLOSE) {
 | 
	
		
			
				|  |  | +    GRPC_CALL_INTERNAL_UNREF(exec_ctx, tc->call, "close");
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  gpr_slice_unref(tc->optional_message);
 | 
	
		
			
				|  |  | +  if (tc->op_closure != NULL) {
 | 
	
		
			
				|  |  | +    grpc_exec_ctx_enqueue(exec_ctx, tc->op_closure, true, NULL);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  gpr_free(tc);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void done_cancel(grpc_exec_ctx *exec_ctx, void *ccp, bool success) {
 | 
	
		
			
				|  |  | -  cancel_closure *cc = ccp;
 | 
	
		
			
				|  |  | -  GRPC_CALL_INTERNAL_UNREF(exec_ctx, cc->call, "cancel");
 | 
	
		
			
				|  |  | -  gpr_free(cc);
 | 
	
		
			
				|  |  | +static void send_cancel(grpc_exec_ctx *exec_ctx, void *tcp, bool success) {
 | 
	
		
			
				|  |  | +  grpc_transport_stream_op op;
 | 
	
		
			
				|  |  | +  termination_closure *tc = tcp;
 | 
	
		
			
				|  |  | +  memset(&op, 0, sizeof(op));
 | 
	
		
			
				|  |  | +  op.cancel_with_status = tc->status;
 | 
	
		
			
				|  |  | +  /* reuse closure to catch completion */
 | 
	
		
			
				|  |  | +  grpc_closure_init(&tc->closure, done_termination, tc);
 | 
	
		
			
				|  |  | +  op.on_complete = &tc->closure;
 | 
	
		
			
				|  |  | +  execute_op(exec_ctx, tc->call, &op);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void send_cancel(grpc_exec_ctx *exec_ctx, void *ccp, bool success) {
 | 
	
		
			
				|  |  | +static void send_close(grpc_exec_ctx *exec_ctx, void *tcp, bool success) {
 | 
	
		
			
				|  |  |    grpc_transport_stream_op op;
 | 
	
		
			
				|  |  | -  cancel_closure *cc = ccp;
 | 
	
		
			
				|  |  | +  termination_closure *tc = tcp;
 | 
	
		
			
				|  |  |    memset(&op, 0, sizeof(op));
 | 
	
		
			
				|  |  | -  op.cancel_with_status = cc->status;
 | 
	
		
			
				|  |  | +  tc->optional_message = gpr_slice_ref(tc->optional_message);
 | 
	
		
			
				|  |  | +  grpc_transport_stream_op_add_close(&op, tc->status, &tc->optional_message);
 | 
	
		
			
				|  |  |    /* reuse closure to catch completion */
 | 
	
		
			
				|  |  | -  grpc_closure_init(&cc->closure, done_cancel, cc);
 | 
	
		
			
				|  |  | -  op.on_complete = &cc->closure;
 | 
	
		
			
				|  |  | -  execute_op(exec_ctx, cc->call, &op);
 | 
	
		
			
				|  |  | +  grpc_closure_init(&tc->closure, done_termination, tc);
 | 
	
		
			
				|  |  | +  tc->op_closure = op.on_complete;
 | 
	
		
			
				|  |  | +  op.on_complete = &tc->closure;
 | 
	
		
			
				|  |  | +  execute_op(exec_ctx, tc->call, &op);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static grpc_call_error terminate_with_status(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | +                                             termination_closure *tc) {
 | 
	
		
			
				|  |  | +  grpc_mdstr *details = NULL;
 | 
	
		
			
				|  |  | +  if (GPR_SLICE_LENGTH(tc->optional_message) > 0) {
 | 
	
		
			
				|  |  | +    tc->optional_message = gpr_slice_ref(tc->optional_message);
 | 
	
		
			
				|  |  | +    details = grpc_mdstr_from_slice(tc->optional_message);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  set_status_code(tc->call, STATUS_FROM_API_OVERRIDE, (uint32_t)tc->status);
 | 
	
		
			
				|  |  | +  set_status_details(tc->call, STATUS_FROM_API_OVERRIDE, details);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (tc->type == TC_CANCEL) {
 | 
	
		
			
				|  |  | +    grpc_closure_init(&tc->closure, send_cancel, tc);
 | 
	
		
			
				|  |  | +    GRPC_CALL_INTERNAL_REF(tc->call, "cancel");
 | 
	
		
			
				|  |  | +  } else if (tc->type == TC_CLOSE) {
 | 
	
		
			
				|  |  | +    grpc_closure_init(&tc->closure, send_close, tc);
 | 
	
		
			
				|  |  | +    GRPC_CALL_INTERNAL_REF(tc->call, "close");
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  grpc_exec_ctx_enqueue(exec_ctx, &tc->closure, true, NULL);
 | 
	
		
			
				|  |  | +  return GRPC_CALL_OK;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
 | 
	
		
			
				|  |  |                                            grpc_status_code status,
 | 
	
		
			
				|  |  |                                            const char *description) {
 | 
	
		
			
				|  |  | -  grpc_mdstr *details =
 | 
	
		
			
				|  |  | -      description ? grpc_mdstr_from_string(description) : NULL;
 | 
	
		
			
				|  |  | -  cancel_closure *cc = gpr_malloc(sizeof(*cc));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +  termination_closure *tc = gpr_malloc(sizeof(*tc));
 | 
	
		
			
				|  |  | +  memset(tc, 0, sizeof(termination_closure));
 | 
	
		
			
				|  |  | +  tc->type = TC_CANCEL;
 | 
	
		
			
				|  |  | +  tc->call = c;
 | 
	
		
			
				|  |  | +  tc->optional_message = gpr_slice_from_copied_string(description);
 | 
	
		
			
				|  |  |    GPR_ASSERT(status != GRPC_STATUS_OK);
 | 
	
		
			
				|  |  | +  tc->status = status;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  set_status_code(c, STATUS_FROM_API_OVERRIDE, (uint32_t)status);
 | 
	
		
			
				|  |  | -  set_status_details(c, STATUS_FROM_API_OVERRIDE, details);
 | 
	
		
			
				|  |  | +  return terminate_with_status(exec_ctx, tc);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  grpc_closure_init(&cc->closure, send_cancel, cc);
 | 
	
		
			
				|  |  | -  cc->call = c;
 | 
	
		
			
				|  |  | -  cc->status = status;
 | 
	
		
			
				|  |  | -  GRPC_CALL_INTERNAL_REF(c, "cancel");
 | 
	
		
			
				|  |  | -  grpc_exec_ctx_enqueue(exec_ctx, &cc->closure, true, NULL);
 | 
	
		
			
				|  |  | +static grpc_call_error close_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
 | 
	
		
			
				|  |  | +                                         grpc_status_code status,
 | 
	
		
			
				|  |  | +                                         const char *description) {
 | 
	
		
			
				|  |  | +  termination_closure *tc = gpr_malloc(sizeof(*tc));
 | 
	
		
			
				|  |  | +  memset(tc, 0, sizeof(termination_closure));
 | 
	
		
			
				|  |  | +  tc->type = TC_CLOSE;
 | 
	
		
			
				|  |  | +  tc->call = c;
 | 
	
		
			
				|  |  | +  tc->optional_message = gpr_slice_from_copied_string(description);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(status != GRPC_STATUS_OK);
 | 
	
		
			
				|  |  | +  tc->status = status;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  return GRPC_CALL_OK;
 | 
	
		
			
				|  |  | +  return terminate_with_status(exec_ctx, tc);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
 | 
	
	
		
			
				|  | @@ -976,7 +983,7 @@ static grpc_mdelem *recv_initial_filter(void *callp, grpc_mdelem *elem) {
 | 
	
		
			
				|  |  |      return NULL;
 | 
	
		
			
				|  |  |    } else if (elem->key == GRPC_MDSTR_GRPC_ENCODING) {
 | 
	
		
			
				|  |  |      GPR_TIMER_BEGIN("incoming_compression_algorithm", 0);
 | 
	
		
			
				|  |  | -    set_compression_algorithm(call, decode_compression(elem));
 | 
	
		
			
				|  |  | +    set_incoming_compression_algorithm(call, decode_compression(elem));
 | 
	
		
			
				|  |  |      GPR_TIMER_END("incoming_compression_algorithm", 0);
 | 
	
		
			
				|  |  |      return NULL;
 | 
	
		
			
				|  |  |    } else if (elem->key == GRPC_MDSTR_GRPC_ACCEPT_ENCODING) {
 | 
	
	
		
			
				|  | @@ -1170,6 +1177,56 @@ static void receiving_stream_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | +                                       batch_control *bctl) {
 | 
	
		
			
				|  |  | +  grpc_call *call = bctl->call;
 | 
	
		
			
				|  |  | +  /* validate call->incoming_compression_algorithm */
 | 
	
		
			
				|  |  | +  if (call->incoming_compression_algorithm != GRPC_COMPRESS_NONE) {
 | 
	
		
			
				|  |  | +    const grpc_compression_algorithm algo =
 | 
	
		
			
				|  |  | +        call->incoming_compression_algorithm;
 | 
	
		
			
				|  |  | +    char *error_msg = NULL;
 | 
	
		
			
				|  |  | +    const grpc_compression_options compression_options =
 | 
	
		
			
				|  |  | +        grpc_channel_compression_options(call->channel);
 | 
	
		
			
				|  |  | +    /* check if algorithm is known */
 | 
	
		
			
				|  |  | +    if (algo >= GRPC_COMPRESS_ALGORITHMS_COUNT) {
 | 
	
		
			
				|  |  | +      gpr_asprintf(&error_msg, "Invalid compression algorithm value '%d'.",
 | 
	
		
			
				|  |  | +                   algo);
 | 
	
		
			
				|  |  | +      gpr_log(GPR_ERROR, error_msg);
 | 
	
		
			
				|  |  | +      close_with_status(exec_ctx, call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
 | 
	
		
			
				|  |  | +    } else if (grpc_compression_options_is_algorithm_enabled(
 | 
	
		
			
				|  |  | +                   &compression_options, algo) == 0) {
 | 
	
		
			
				|  |  | +      /* check if algorithm is supported by current channel config */
 | 
	
		
			
				|  |  | +      char *algo_name;
 | 
	
		
			
				|  |  | +      grpc_compression_algorithm_name(algo, &algo_name);
 | 
	
		
			
				|  |  | +      gpr_asprintf(&error_msg, "Compression algorithm '%s' is disabled.",
 | 
	
		
			
				|  |  | +                   algo_name);
 | 
	
		
			
				|  |  | +      gpr_log(GPR_ERROR, error_msg);
 | 
	
		
			
				|  |  | +      close_with_status(exec_ctx, call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      call->incoming_compression_algorithm = algo;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    gpr_free(error_msg);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /* make sure the received grpc-encoding is amongst the ones listed in
 | 
	
		
			
				|  |  | +   * grpc-accept-encoding */
 | 
	
		
			
				|  |  | +  GPR_ASSERT(call->encodings_accepted_by_peer != 0);
 | 
	
		
			
				|  |  | +  if (!GPR_BITGET(call->encodings_accepted_by_peer,
 | 
	
		
			
				|  |  | +                  call->incoming_compression_algorithm)) {
 | 
	
		
			
				|  |  | +    extern int grpc_compression_trace;
 | 
	
		
			
				|  |  | +    if (grpc_compression_trace) {
 | 
	
		
			
				|  |  | +      char *algo_name;
 | 
	
		
			
				|  |  | +      grpc_compression_algorithm_name(call->incoming_compression_algorithm,
 | 
	
		
			
				|  |  | +                                      &algo_name);
 | 
	
		
			
				|  |  | +      gpr_log(GPR_ERROR,
 | 
	
		
			
				|  |  | +              "Compression algorithm (grpc-encoding = '%s') not present in "
 | 
	
		
			
				|  |  | +              "the bitset of accepted encodings (grpc-accept-encodings: "
 | 
	
		
			
				|  |  | +              "'0x%x')",
 | 
	
		
			
				|  |  | +              algo_name, call->encodings_accepted_by_peer);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                               void *bctlp, bool success) {
 | 
	
		
			
				|  |  |    batch_control *bctl = bctlp;
 | 
	
	
		
			
				|  | @@ -1184,24 +1241,10 @@ static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |          &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
 | 
	
		
			
				|  |  |      grpc_metadata_batch_filter(md, recv_initial_filter, call);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    /* make sure the received grpc-encoding is amongst the ones listed in
 | 
	
		
			
				|  |  | -     * grpc-accept-encoding */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    GPR_ASSERT(call->encodings_accepted_by_peer != 0);
 | 
	
		
			
				|  |  | -    if (!GPR_BITGET(call->encodings_accepted_by_peer,
 | 
	
		
			
				|  |  | -                    call->incoming_compression_algorithm)) {
 | 
	
		
			
				|  |  | -      extern int grpc_compression_trace;
 | 
	
		
			
				|  |  | -      if (grpc_compression_trace) {
 | 
	
		
			
				|  |  | -        char *algo_name;
 | 
	
		
			
				|  |  | -        grpc_compression_algorithm_name(call->incoming_compression_algorithm,
 | 
	
		
			
				|  |  | -                                        &algo_name);
 | 
	
		
			
				|  |  | -        gpr_log(GPR_ERROR,
 | 
	
		
			
				|  |  | -                "Compression algorithm (grpc-encoding = '%s') not present in "
 | 
	
		
			
				|  |  | -                "the bitset of accepted encodings (grpc-accept-encodings: "
 | 
	
		
			
				|  |  | -                "'0x%x')",
 | 
	
		
			
				|  |  | -                algo_name, call->encodings_accepted_by_peer);
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | +    GPR_TIMER_BEGIN("validate_filtered_metadata", 0);
 | 
	
		
			
				|  |  | +    validate_filtered_metadata(exec_ctx, bctl);
 | 
	
		
			
				|  |  | +    GPR_TIMER_END("validate_filtered_metadata", 0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      if (gpr_time_cmp(md->deadline, gpr_inf_future(md->deadline.clock_type)) !=
 | 
	
		
			
				|  |  |              0 &&
 | 
	
		
			
				|  |  |          !call->is_client) {
 | 
	
	
		
			
				|  | @@ -1356,8 +1399,12 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                    .compression_level;
 | 
	
		
			
				|  |  |            level_set = true;
 | 
	
		
			
				|  |  |          } else {
 | 
	
		
			
				|  |  | -          level_set = grpc_channel_default_compression_level(
 | 
	
		
			
				|  |  | -              call->channel, &effective_compression_level);
 | 
	
		
			
				|  |  | +          const grpc_compression_options copts =
 | 
	
		
			
				|  |  | +              grpc_channel_compression_options(call->channel);
 | 
	
		
			
				|  |  | +          level_set = copts.default_level.is_set;
 | 
	
		
			
				|  |  | +          if (level_set) {
 | 
	
		
			
				|  |  | +            effective_compression_level = copts.default_level.level;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          if (level_set) {
 | 
	
		
			
				|  |  |            const grpc_compression_algorithm calgo =
 |