|  | @@ -36,6 +36,7 @@
 | 
	
		
			
				|  |  |  #include <grpc/support/string_util.h>
 | 
	
		
			
				|  |  |  #include <string.h>
 | 
	
		
			
				|  |  |  #include "src/core/lib/profiling/timers.h"
 | 
	
		
			
				|  |  | +#include "src/core/lib/slice/percent_encoding.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/support/string.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/transport/static_metadata.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/transport/transport_impl.h"
 | 
	
	
		
			
				|  | @@ -56,6 +57,7 @@ typedef struct call_data {
 | 
	
		
			
				|  |  |    grpc_linked_mdelem payload_bin;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    grpc_metadata_batch *recv_initial_metadata;
 | 
	
		
			
				|  |  | +  grpc_metadata_batch *recv_trailing_metadata;
 | 
	
		
			
				|  |  |    uint8_t *payload_bytes;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* Vars to read data off of send_message */
 | 
	
	
		
			
				|  | @@ -69,14 +71,16 @@ typedef struct call_data {
 | 
	
		
			
				|  |  |    bool send_message_blocked;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /** Closure to call when finished with the hc_on_recv hook */
 | 
	
		
			
				|  |  | -  grpc_closure *on_done_recv;
 | 
	
		
			
				|  |  | +  grpc_closure *on_done_recv_initial_metadata;
 | 
	
		
			
				|  |  | +  grpc_closure *on_done_recv_trailing_metadata;
 | 
	
		
			
				|  |  |    grpc_closure *on_complete;
 | 
	
		
			
				|  |  |    grpc_closure *post_send;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /** Receive closures are chained: we inject this closure as the on_done_recv
 | 
	
		
			
				|  |  |        up-call on transport_op, and remember to call our on_done_recv member
 | 
	
		
			
				|  |  |        after handling it. */
 | 
	
		
			
				|  |  | -  grpc_closure hc_on_recv;
 | 
	
		
			
				|  |  | +  grpc_closure hc_on_recv_initial_metadata;
 | 
	
		
			
				|  |  | +  grpc_closure hc_on_recv_trailing_metadata;
 | 
	
		
			
				|  |  |    grpc_closure hc_on_complete;
 | 
	
		
			
				|  |  |    grpc_closure got_slice;
 | 
	
		
			
				|  |  |    grpc_closure send_done;
 | 
	
	
		
			
				|  | @@ -106,6 +110,16 @@ static grpc_mdelem *client_recv_filter(void *user_data, grpc_mdelem *md) {
 | 
	
		
			
				|  |  |      grpc_call_element_send_close_with_message(a->exec_ctx, a->elem,
 | 
	
		
			
				|  |  |                                                GRPC_STATUS_CANCELLED, &message);
 | 
	
		
			
				|  |  |      return NULL;
 | 
	
		
			
				|  |  | +  } else if (md->key == GRPC_MDSTR_GRPC_MESSAGE) {
 | 
	
		
			
				|  |  | +    grpc_slice pct_decoded_msg =
 | 
	
		
			
				|  |  | +        grpc_permissive_percent_decode_slice(md->value->slice);
 | 
	
		
			
				|  |  | +    if (grpc_slice_is_equivalent(pct_decoded_msg, md->value->slice)) {
 | 
	
		
			
				|  |  | +      grpc_slice_unref(pct_decoded_msg);
 | 
	
		
			
				|  |  | +      return md;
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      return grpc_mdelem_from_metadata_strings(
 | 
	
		
			
				|  |  | +          GRPC_MDSTR_GRPC_MESSAGE, grpc_mdstr_from_slice(pct_decoded_msg));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |    } else if (md == GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC) {
 | 
	
		
			
				|  |  |      return NULL;
 | 
	
		
			
				|  |  |    } else if (md->key == GRPC_MDSTR_CONTENT_TYPE) {
 | 
	
	
		
			
				|  | @@ -129,8 +143,8 @@ static grpc_mdelem *client_recv_filter(void *user_data, grpc_mdelem *md) {
 | 
	
		
			
				|  |  |    return md;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void hc_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
 | 
	
		
			
				|  |  | -                       grpc_error *error) {
 | 
	
		
			
				|  |  | +static void hc_on_recv_initial_metadata(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | +                                        void *user_data, grpc_error *error) {
 | 
	
		
			
				|  |  |    grpc_call_element *elem = user_data;
 | 
	
		
			
				|  |  |    call_data *calld = elem->call_data;
 | 
	
		
			
				|  |  |    client_recv_filter_args a;
 | 
	
	
		
			
				|  | @@ -138,7 +152,21 @@ static void hc_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
 | 
	
		
			
				|  |  |    a.exec_ctx = exec_ctx;
 | 
	
		
			
				|  |  |    grpc_metadata_batch_filter(calld->recv_initial_metadata, client_recv_filter,
 | 
	
		
			
				|  |  |                               &a);
 | 
	
		
			
				|  |  | -  calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, error);
 | 
	
		
			
				|  |  | +  grpc_closure_run(exec_ctx, calld->on_done_recv_initial_metadata,
 | 
	
		
			
				|  |  | +                   GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void hc_on_recv_trailing_metadata(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | +                                         void *user_data, grpc_error *error) {
 | 
	
		
			
				|  |  | +  grpc_call_element *elem = user_data;
 | 
	
		
			
				|  |  | +  call_data *calld = elem->call_data;
 | 
	
		
			
				|  |  | +  client_recv_filter_args a;
 | 
	
		
			
				|  |  | +  a.elem = elem;
 | 
	
		
			
				|  |  | +  a.exec_ctx = exec_ctx;
 | 
	
		
			
				|  |  | +  grpc_metadata_batch_filter(calld->recv_trailing_metadata, client_recv_filter,
 | 
	
		
			
				|  |  | +                             &a);
 | 
	
		
			
				|  |  | +  grpc_closure_run(exec_ctx, calld->on_done_recv_trailing_metadata,
 | 
	
		
			
				|  |  | +                   GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void hc_on_complete(grpc_exec_ctx *exec_ctx, void *user_data,
 | 
	
	
		
			
				|  | @@ -281,8 +309,15 @@ static void hc_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
 | 
	
		
			
				|  |  |    if (op->recv_initial_metadata != NULL) {
 | 
	
		
			
				|  |  |      /* substitute our callback for the higher callback */
 | 
	
		
			
				|  |  |      calld->recv_initial_metadata = op->recv_initial_metadata;
 | 
	
		
			
				|  |  | -    calld->on_done_recv = op->recv_initial_metadata_ready;
 | 
	
		
			
				|  |  | -    op->recv_initial_metadata_ready = &calld->hc_on_recv;
 | 
	
		
			
				|  |  | +    calld->on_done_recv_initial_metadata = op->recv_initial_metadata_ready;
 | 
	
		
			
				|  |  | +    op->recv_initial_metadata_ready = &calld->hc_on_recv_initial_metadata;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (op->recv_trailing_metadata != NULL) {
 | 
	
		
			
				|  |  | +    /* substitute our callback for the higher callback */
 | 
	
		
			
				|  |  | +    calld->recv_trailing_metadata = op->recv_trailing_metadata;
 | 
	
		
			
				|  |  | +    calld->on_done_recv_trailing_metadata = op->on_complete;
 | 
	
		
			
				|  |  | +    op->on_complete = &calld->hc_on_recv_trailing_metadata;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -308,11 +343,15 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                    grpc_call_element *elem,
 | 
	
		
			
				|  |  |                                    grpc_call_element_args *args) {
 | 
	
		
			
				|  |  |    call_data *calld = elem->call_data;
 | 
	
		
			
				|  |  | -  calld->on_done_recv = NULL;
 | 
	
		
			
				|  |  | +  calld->on_done_recv_initial_metadata = NULL;
 | 
	
		
			
				|  |  | +  calld->on_done_recv_trailing_metadata = NULL;
 | 
	
		
			
				|  |  |    calld->on_complete = NULL;
 | 
	
		
			
				|  |  |    calld->payload_bytes = NULL;
 | 
	
		
			
				|  |  |    grpc_slice_buffer_init(&calld->slices);
 | 
	
		
			
				|  |  | -  grpc_closure_init(&calld->hc_on_recv, hc_on_recv, elem);
 | 
	
		
			
				|  |  | +  grpc_closure_init(&calld->hc_on_recv_initial_metadata,
 | 
	
		
			
				|  |  | +                    hc_on_recv_initial_metadata, elem);
 | 
	
		
			
				|  |  | +  grpc_closure_init(&calld->hc_on_recv_trailing_metadata,
 | 
	
		
			
				|  |  | +                    hc_on_recv_trailing_metadata, elem);
 | 
	
		
			
				|  |  |    grpc_closure_init(&calld->hc_on_complete, hc_on_complete, elem);
 | 
	
		
			
				|  |  |    grpc_closure_init(&calld->got_slice, got_slice, elem);
 | 
	
		
			
				|  |  |    grpc_closure_init(&calld->send_done, send_done, elem);
 |